849 lines
32 KiB
C++
849 lines
32 KiB
C++
#include <objbase.h>
|
|
#include <assert.h>
|
|
|
|
#include "shlwapi.h"
|
|
#include "shellstg.h"
|
|
#include "mischlpr.h"
|
|
#include "strutil.h"
|
|
#include "resource.h"
|
|
|
|
#include <stdio.h>
|
|
#define DEBUG
|
|
//#define TRACE(a) (fprintf(stderr,"%d %s\n",GetTickCount(),a))
|
|
#define TRACE(a)
|
|
|
|
///////////////////////////////////////
|
|
|
|
CShellStorageImpl::CShellStorageImpl (): _plistPIDL(NULL), _pwszTitleExamining(NULL), _pwszTitleConnecting(NULL),
|
|
_pwszTitleSending(NULL), _pwszTitleTo(NULL), _ppd(NULL)
|
|
{
|
|
TRACE("CShellStorage::CShellStorage");
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
|
|
CShellStorageImpl::~CShellStorageImpl ()
|
|
{
|
|
TRACE("CShellStorage::~CShellStorage");
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::Init(HWND hwnd, LPWSTR pwszServer, BOOL fShowProgressDialog)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
TRACE("CShellStorage::Init");
|
|
|
|
_hwnd = hwnd;
|
|
_hinstShellStg = GetModuleHandle(L"shellstg");
|
|
if (!_hinstShellStg)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
WCHAR wszLoad[MAX_PATH];
|
|
_pwszTitleExamining = NULL;
|
|
_pwszTitleConnecting = NULL;
|
|
_pwszTitleSending = NULL;
|
|
_pwszTitleTo = NULL;
|
|
|
|
if (LoadStringW(_hinstShellStg, IDS_EXAMINING, wszLoad, sizeof(wszLoad)))
|
|
_pwszTitleExamining = DuplicateStringW(wszLoad);
|
|
|
|
if (LoadStringW(_hinstShellStg, IDS_CONNECTING, wszLoad, sizeof(wszLoad)))
|
|
_pwszTitleConnecting = DuplicateStringW(wszLoad);
|
|
|
|
if (LoadStringW(_hinstShellStg, IDS_UPLOADING, wszLoad, sizeof(wszLoad)))
|
|
_pwszTitleSending = DuplicateStringW(wszLoad);
|
|
|
|
if (LoadStringW(_hinstShellStg, IDS_SERVERTO, wszLoad, sizeof(wszLoad)))
|
|
_pwszTitleTo = DuplicateStringW(wszLoad);
|
|
|
|
if (LoadStringW(_hinstShellStg, IDS_SERVERNEWFOLDER, wszLoad, sizeof(wszLoad)))
|
|
_pwszTitleNewFolder = DuplicateStringW(wszLoad);
|
|
|
|
_plistPIDL = new CGenericList();
|
|
_pwszServer = DuplicateStringW(pwszServer);
|
|
|
|
if (!_pwszTitleExamining || !_pwszTitleConnecting ||
|
|
!_pwszTitleSending || !_pwszTitleTo ||
|
|
!_pwszTitleNewFolder ||
|
|
!_plistPIDL || !_pwszServer)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
if (fShowProgressDialog)
|
|
{
|
|
// set up the progress dialog
|
|
hr = CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, IID_IProgressDialog, (LPVOID*)&_ppd);
|
|
// BUGBUG: catch all these return values
|
|
hr = _ppd->SetAnimation(_hinstShellStg, IDA_FTPUPLOAD);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_ppd->SetTitle(_pwszTitleExamining);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ppd->StartProgressDialog(NULL, NULL, PROGDLG_AUTOTIME, NULL);if (SUCCEEDED(hr))
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::AddIDListReference(LPVOID rgpidl[],
|
|
DWORD cpidl,
|
|
BOOL fRecursive)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TRACE("CShellStorage::AddIDListReference");
|
|
|
|
if (!rgpidl || cpidl <= 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
for (DWORD i = 0; i < cpidl; i++)
|
|
{
|
|
if (!rgpidl[i])
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// add the pidl
|
|
DWORD cb = ((LPSHITEMID)rgpidl[i])->cb;
|
|
LPITEMIDLIST pidl = ILClone((LPITEMIDLIST)rgpidl[i]);
|
|
if (!pidl)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
WCHAR wszTag[2];
|
|
wszTag[0] = fRecursive ? 'R' : 'S';
|
|
wszTag[1] = '\0';
|
|
hr = _plistPIDL->Add(wszTag, pidl, cb);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::CreateStream(const WCHAR * UNREF_PARAM(pwcsName), //Points to the name of the new stream
|
|
DWORD UNREF_PARAM(grfMode), //Access mode for the new stream
|
|
DWORD UNREF_PARAM(reserved1), //Reserved; must be zero
|
|
DWORD UNREF_PARAM(reserved2), //Reserved; must be zero
|
|
IStream ** UNREF_PARAM(ppstm)) //Points to new stream object
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::OpenStream(const WCHAR * UNREF_PARAM(pwcsName), //Points to name of stream to open
|
|
void * UNREF_PARAM(reserved1), //Reserved; must be NULL
|
|
DWORD UNREF_PARAM(grfMode), //Access mode for the new stream
|
|
DWORD UNREF_PARAM(reserved2), //Reserved; must be zero
|
|
IStream ** UNREF_PARAM(ppstm)) //Address of output variable
|
|
// that receives the IStream interface pointer
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::CreateStorage(const WCHAR * UNREF_PARAM(pwcsName), //Points to the name of the new storage object
|
|
DWORD UNREF_PARAM(grfMode), //Access mode for the new storage object
|
|
DWORD UNREF_PARAM(reserved1), //Reserved; must be zero
|
|
DWORD UNREF_PARAM(reserved2), //Reserved; must be zero
|
|
IStorage ** UNREF_PARAM(ppstg)) //Points to new storage object
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::OpenStorage(const WCHAR * UNREF_PARAM(pwcsName), //Points to the name of the
|
|
// storage object to open
|
|
IStorage * UNREF_PARAM(pstgPriority), //Must be NULL.
|
|
DWORD UNREF_PARAM(grfMode), //Access mode for the new storage object
|
|
SNB UNREF_PARAM(snbExclude), //Must be NULL.
|
|
DWORD UNREF_PARAM(reserved), //Reserved; must be zero
|
|
IStorage ** UNREF_PARAM(ppstg)) //Points to opened storage object
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
STDMETHODIMP CShellStorageImpl::_IncrementULargeInteger(ULARGE_INTEGER* a,
|
|
ULARGE_INTEGER* b)
|
|
{
|
|
a->HighPart+=b->HighPart;
|
|
|
|
DWORD dwNewLow = a->LowPart + b->LowPart;
|
|
if ((dwNewLow < a->LowPart) ||( dwNewLow < b->LowPart))
|
|
{
|
|
a->HighPart+=1; // rollover in low
|
|
}
|
|
|
|
a->LowPart = dwNewLow;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CShellStorageImpl::_IncrementByteCount(LPITEMIDLIST pidl,
|
|
ULARGE_INTEGER* pcbTotal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
LPCITEMIDLIST pidlRelative;
|
|
IShellFolder* pshfParent = NULL;
|
|
|
|
hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&pshfParent, &pidlRelative);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WIN32_FIND_DATA wfdData;
|
|
hr = SHGetDataFromIDList(pshfParent, pidlRelative, SHGDFIL_FINDDATA, &wfdData, sizeof(wfdData));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ULARGE_INTEGER ulwfdData;
|
|
ulwfdData.HighPart = wfdData.nFileSizeHigh;
|
|
ulwfdData.LowPart = wfdData.nFileSizeLow;
|
|
|
|
hr = this->_IncrementULargeInteger(pcbTotal, &ulwfdData);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
STDMETHODIMP CShellStorageImpl::_ExaminePIDLListRecursive(LPITEMIDLIST pidl,
|
|
IShellFolder* pshfDesk,
|
|
UINT* pcbElts,
|
|
ULARGE_INTEGER* pcbTotal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SHFILEINFO sfi;
|
|
TRACE("CShellStorage::_FlattenPIDLListRecursive");
|
|
|
|
if (!SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi),
|
|
SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME))
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
*pcbElts = *pcbElts + 1;
|
|
hr = this->_IncrementByteCount(pidl, pcbTotal);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (_ppd)
|
|
{
|
|
WCHAR wszTempLine1[MAX_PATH];
|
|
WCHAR wszTempLine2[MAX_PATH];
|
|
swprintf(wszTempLine1, L"Found %d files", *pcbElts);
|
|
if (pcbTotal->HighPart > 0)
|
|
{
|
|
// BUGBUG: need to format lowpart correctly so it'll have the right width
|
|
swprintf(wszTempLine2, L"Total %d%d bytes", pcbTotal->HighPart, pcbTotal->LowPart);
|
|
}
|
|
else
|
|
{
|
|
swprintf(wszTempLine2, L"Total %d bytes", pcbTotal->LowPart);
|
|
}
|
|
hr = this->_UpdateProgressDialog(NULL, NULL, NULL, wszTempLine1, wszTempLine2);
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && hr != S_FALSE)
|
|
{
|
|
if ((sfi.dwAttributes & SFGAO_FILESYSTEM) && (sfi.dwAttributes & SFGAO_FOLDER))
|
|
{
|
|
// if this is a folder, we need to enumerate its contents and add those too
|
|
IShellFolder* pshf = NULL;
|
|
LPENUMIDLIST penumIDList = NULL;
|
|
LPITEMIDLIST pidlRelative = NULL;
|
|
LPITEMIDLIST pidlAbsolute = NULL;
|
|
|
|
hr = pshfDesk->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&pshf);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pshf->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penumIDList);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BOOL fDone = FALSE;
|
|
while (!fDone)
|
|
{
|
|
DWORD cFetched;
|
|
hr = penumIDList->Next(1, &pidlRelative, &cFetched);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (hr == S_FALSE || cFetched != 1)
|
|
{
|
|
hr = S_OK;
|
|
fDone = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pidlAbsolute = ILCombine((LPCITEMIDLIST)pidl, pidlRelative);
|
|
if (!pidlAbsolute)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
hr = this->_ExaminePIDLListRecursive(pidlAbsolute,
|
|
pshfDesk,
|
|
pcbElts,
|
|
pcbTotal);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr) || hr == S_FALSE)
|
|
{
|
|
fDone=TRUE;
|
|
}
|
|
}
|
|
}
|
|
pshf->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
STDMETHODIMP CShellStorageImpl::_ExaminePIDLList(UINT* pcElts,
|
|
ULARGE_INTEGER* pcbTotal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
UINT cEltsTopLevel;
|
|
LPWSTR pwszTag;
|
|
LPITEMIDLIST pidl;
|
|
UINT cbPIDL;
|
|
IShellFolder* pshfDesk = NULL;
|
|
|
|
hr = _plistPIDL->Size(&cEltsTopLevel);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
for (UINT i = 0; i < cEltsTopLevel; i++)
|
|
{
|
|
hr = _plistPIDL->GetTagByDex (i, &pwszTag);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _plistPIDL->FindByDex(i, (LPVOID*)&pidl, &cbPIDL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (*pwszTag == 'R')
|
|
{
|
|
// add to the new list recursively
|
|
if (!pshfDesk)
|
|
{
|
|
hr = SHGetDesktopFolder(&pshfDesk);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ExaminePIDLListRecursive(pidl, pshfDesk, pcElts, pcbTotal);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// increment count of elements to copy
|
|
*pcElts = *pcElts + 1;
|
|
// if a file, get size and add to pcbTotal
|
|
hr = this->_IncrementByteCount(pidl, pcbTotal);
|
|
WCHAR wszTempLine1[MAX_PATH];
|
|
WCHAR wszTempLine2[MAX_PATH];
|
|
swprintf(wszTempLine1, L"Found %d files", *pcElts);
|
|
swprintf(wszTempLine2, L"Total %d%d bytes", pcbTotal->HighPart, pcbTotal->LowPart);
|
|
hr = this->_UpdateProgressDialog(NULL, NULL, NULL, wszTempLine1, wszTempLine2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (FAILED(hr) || hr == S_FALSE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
HRESULT CShellStorageImpl::_UpdateProgressDialog(ULARGE_INTEGER* pcbNewComplete,
|
|
ULARGE_INTEGER* pcbComplete,
|
|
ULARGE_INTEGER* pcbTotal,
|
|
LPWSTR pwszLine1,
|
|
LPWSTR pwszLine2)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
static BOOL fSending = FALSE;
|
|
|
|
assert(_ppd); // should not call if we aren't using the dialog
|
|
|
|
// first, check if user has cancelled
|
|
if (_ppd->HasUserCancelled())
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ppd->SetLine(1, pwszLine1, TRUE, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ppd->SetLine(2, pwszLine2, TRUE, NULL);
|
|
|
|
if (pcbNewComplete && pcbComplete && pcbTotal)
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// -- update title if appropriate, "Connecting" --> "Sending"
|
|
if (!fSending)
|
|
{
|
|
hr = _ppd->SetTitle(_pwszTitleSending);
|
|
fSending = TRUE;
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = this->_IncrementULargeInteger(pcbComplete, pcbNewComplete);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ppd->SetProgress64(pcbComplete->QuadPart, pcbTotal->QuadPart);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::_CopyPidlToStream(LPITEMIDLIST pidl,
|
|
IStream* pstream,
|
|
ULARGE_INTEGER* pcbComplete,
|
|
ULARGE_INTEGER* pcbTotal,
|
|
UINT cchRootPath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR wszPath[MAX_PATH];
|
|
WCHAR wszLine2[MAX_PATH];
|
|
BOOL fLine2Init = FALSE;
|
|
DWORD cbRead, cbWritten;
|
|
|
|
TRACE("CShellStorage::_CopyPidlToStream");
|
|
if (!SHGetPathFromIDList(pidl, wszPath))
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
HANDLE hFile = CreateFile(wszPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
BYTE lpv[4096];
|
|
if (ReadFile(hFile, lpv, 4096, &cbRead, NULL))
|
|
{
|
|
if (cbRead > 0)
|
|
{
|
|
hr = pstream->Write(lpv, cbRead, &cbWritten);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (cbRead != cbWritten)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
if (_ppd)
|
|
{
|
|
// update progress dialog
|
|
if (!fLine2Init)
|
|
{
|
|
lstrcpy(wszLine2, _pwszTitleTo);
|
|
lstrcat(wszLine2, wszPath + cchRootPath);
|
|
fLine2Init = TRUE;
|
|
}
|
|
ULARGE_INTEGER ulcbWritten;
|
|
ulcbWritten.HighPart = 0;
|
|
ulcbWritten.LowPart = cbWritten;
|
|
hr = this->_UpdateProgressDialog(&ulcbWritten, pcbComplete, pcbTotal, wszPath, wszLine2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (cbRead > 0 && SUCCEEDED(hr) && hr != S_FALSE);
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
STDMETHODIMP CShellStorageImpl::_CopyPidlContentsToStorage(LPITEMIDLIST pidl,
|
|
IStorage* pstgDest,
|
|
ULARGE_INTEGER* pcbComplete,
|
|
ULARGE_INTEGER* pcbTotal,
|
|
BOOL fRecursive,
|
|
UINT cchRootPath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TRACE("CShellStorage::_FlattenPIDLListRecursive");
|
|
|
|
IShellFolder* pshfDesk = NULL; // BUGBUG, don't get this every time
|
|
IShellFolder* pshf = NULL;
|
|
LPENUMIDLIST penumIDList = NULL;
|
|
LPITEMIDLIST pidlRelative = NULL;
|
|
LPITEMIDLIST pidlAbsolute = NULL;
|
|
|
|
SHGetDesktopFolder(&pshfDesk);
|
|
hr = pshfDesk->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&pshf);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pshf->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penumIDList);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BOOL fDone = FALSE;
|
|
while (!fDone)
|
|
{
|
|
DWORD cFetched;
|
|
hr = penumIDList->Next(1, &pidlRelative, &cFetched);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (hr == S_FALSE || cFetched != 1)
|
|
{
|
|
hr = S_OK;
|
|
fDone = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pidlAbsolute = ILCombine((LPCITEMIDLIST)pidl, pidlRelative);
|
|
if (!pidlAbsolute)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
hr = this->_CopyPidlToStorage(pidlAbsolute,
|
|
pstgDest,
|
|
pcbComplete,
|
|
pcbTotal,
|
|
fRecursive,
|
|
cchRootPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr) || hr == S_FALSE)
|
|
{
|
|
fDone=TRUE;
|
|
}
|
|
}
|
|
}
|
|
pshf->Release();
|
|
}
|
|
|
|
pshfDesk->Release();
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CShellStorageImpl::_CopyPidlToStorage(LPITEMIDLIST pidl,
|
|
IStorage* pstgDest,
|
|
ULARGE_INTEGER* pcbComplete,
|
|
ULARGE_INTEGER* pcbTotal,
|
|
BOOL fRecursive,
|
|
UINT cchRootPath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SHFILEINFO sfi;
|
|
IStorage* newStorage = NULL;
|
|
IStream* newStream = NULL;
|
|
|
|
TRACE("CShellStorage::_CopyPidlToStorage");
|
|
|
|
if (!SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi),
|
|
SHGFI_PIDL | SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME))
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
if (sfi.dwAttributes & SFGAO_FILESYSTEM) // we only support filesystem items for now
|
|
{
|
|
if (sfi.dwAttributes & SFGAO_FOLDER)
|
|
{
|
|
// folder
|
|
hr = pstgDest->CreateStorage(sfi.szDisplayName, 0, 0, 0, &newStorage);
|
|
if (FAILED(hr))
|
|
{ // if we can't create, try to open an existing storage there
|
|
hr = pstgDest->OpenStorage(sfi.szDisplayName, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &newStorage);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR wszTitle[MAX_PATH];
|
|
WCHAR wszPath[MAX_PATH];
|
|
if (!SHGetPathFromIDList(pidl, wszPath))
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(wszTitle, _pwszTitleNewFolder);
|
|
lstrcat(wszTitle, wszPath + cchRootPath);
|
|
hr = this->_UpdateProgressDialog(NULL, NULL, NULL, wszTitle, L"");
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (fRecursive)
|
|
{
|
|
hr = this->_CopyPidlContentsToStorage(pidl, newStorage, pcbComplete, pcbTotal, TRUE, cchRootPath);
|
|
}
|
|
}
|
|
newStorage->Release();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// file
|
|
hr = pstgDest->CreateStream(sfi.szDisplayName, STGM_TRANSACTED, 0, 0, &newStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _CopyPidlToStream(pidl, newStream, pcbComplete, pcbTotal, cchRootPath);
|
|
if (SUCCEEDED(hr) && hr != S_FALSE)
|
|
{
|
|
hr = newStream->Commit(0);
|
|
}
|
|
|
|
newStream->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::CopyTo(DWORD UNREF_PARAM(ciidExclude), //Number of elements in rgiidExclude
|
|
IID const * UNREF_PARAM(rgiidExclude), //Array of interface identifiers (IIDs)
|
|
SNB UNREF_PARAM(snbExclude), //Points to a block of stream
|
|
// names in the storage object
|
|
IStorage* pstgDest) //Points to destination storage object
|
|
{
|
|
// here's where all the magic happens
|
|
// ISSUE: we don't support exclusion at the moment
|
|
HRESULT hr;
|
|
UINT cElts = 0;
|
|
ULARGE_INTEGER cbTotal = {0}; // total size in bytes of all files to be transmitted
|
|
ULARGE_INTEGER cbComplete = {0};
|
|
|
|
TRACE("CShellStorage::CopyTo");
|
|
|
|
// examine list of pidls (maybe recursive), and find total size and number of elements
|
|
hr = this->_ExaminePIDLList(&cElts, &cbTotal);
|
|
|
|
if (_ppd && hr == S_FALSE)
|
|
{
|
|
// we just cancelled, but that doesn't mean failure
|
|
_ppd->StopProgressDialog();
|
|
hr = S_OK;
|
|
}
|
|
else if (SUCCEEDED(hr))
|
|
{
|
|
if (_ppd)
|
|
{
|
|
_ppd->SetTitle(_pwszTitleConnecting);
|
|
this->_UpdateProgressDialog(NULL, NULL, NULL, L"", L"");
|
|
}
|
|
|
|
UINT cEltsTopLevel;
|
|
_plistPIDL->Size(&cEltsTopLevel); // BUGBUG: check ret val
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
for (UINT i = 0; i < cEltsTopLevel; i++)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
UINT cbPIDL;
|
|
|
|
hr = _plistPIDL->FindByDex(i, (LPVOID*)&pidl, &cbPIDL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPWSTR pwszTag = NULL;
|
|
hr = _plistPIDL->GetTagByDex (i, &pwszTag);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR wszPath[MAX_PATH];
|
|
if (!SHGetPathFromIDList(pidl, wszPath))
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
SHFILEINFO sfi;
|
|
if (!SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi),
|
|
SHGFI_PIDL | SHGFI_DISPLAYNAME))
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
UINT cchRootPath = lstrlen(wszPath) - lstrlen(sfi.szDisplayName);
|
|
if (*pwszTag == 'R')
|
|
hr = this->_CopyPidlToStorage(pidl, pstgDest, &cbComplete, &cbTotal, TRUE, cchRootPath);
|
|
else
|
|
hr = this->_CopyPidlToStorage(pidl, pstgDest, &cbComplete, &cbTotal, FALSE, cchRootPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_ppd)
|
|
{
|
|
hr = _ppd->StopProgressDialog();
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::MoveElementTo(const WCHAR * UNREF_PARAM(pwcsName), //Name of the element to be moved
|
|
IStorage * UNREF_PARAM(pstgDest), //Points to destination storage object
|
|
const WCHAR* UNREF_PARAM(pwcsNewName), //Points to new name of element in destination
|
|
DWORD UNREF_PARAM(grfFlags)) //Specifies a copy or a move
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
// IStorage::EnumElements
|
|
STDMETHODIMP CShellStorageImpl::EnumElements(DWORD UNREF_PARAM(reserved1), //Reserved; must be zero
|
|
void * UNREF_PARAM(reserved2), //Reserved; must be NULL
|
|
DWORD UNREF_PARAM(reserved3), //Reserved; must be zero
|
|
IEnumSTATSTG ** UNREF_PARAM(ppenum)) //Address of output variable that
|
|
// receives the IEnumSTATSTG interface pointer
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::DestroyElement(const WCHAR* UNREF_PARAM(pwcsName)) //Points to the name of the element to be removed
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::RenameElement(const WCHAR * UNREF_PARAM(pwcsOldName), //Points to the name of the
|
|
// element to be changed
|
|
const WCHAR * UNREF_PARAM(pwcsNewName)) //Points to the new name for
|
|
// the specified element
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::SetStateBits(DWORD UNREF_PARAM(grfStateBits), //Specifies new values of bits
|
|
DWORD UNREF_PARAM(grfMask)) //Specifies mask that indicates which
|
|
// bits are significant
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::Commit(DWORD UNREF_PARAM(grfCommitFlags)) //Specifies how changes are to be committed
|
|
{
|
|
return E_NOTIMPL; // first pass, we do everything synchronously to the server
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::Revert(void)
|
|
{
|
|
return E_NOTIMPL; // first pass, we do everything synchronously to the server
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::SetElementTimes(const WCHAR * UNREF_PARAM(pwcsName), //Points to name of element to be changed
|
|
FILETIME const * UNREF_PARAM(pctime), //New creation time for element, or NULL
|
|
FILETIME const * UNREF_PARAM(patime), //New access time for element, or NULL
|
|
FILETIME const * UNREF_PARAM(pmtime)) //New modification time for element, or NULL
|
|
{
|
|
return E_NOTIMPL; // not the first time around
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::SetClass(REFCLSID UNREF_PARAM(clsid)) //Class identifier to be assigned to the storage object
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
|
|
STDMETHODIMP CShellStorageImpl::Stat(STATSTG* UNREF_PARAM(pstatstg), //Location for STATSTG structure
|
|
DWORD UNREF_PARAM(grfStatFlag)) //Values taken from the STATFLAG enumeration
|
|
{
|
|
return E_NOTIMPL; // not the first pass
|
|
}
|
|
|