426 lines
11 KiB
C++
426 lines
11 KiB
C++
|
|
||
|
#include "shellprv.h"
|
||
|
//#include "mkhelp.h"
|
||
|
#include "urlmon.h"
|
||
|
#include "ids.h"
|
||
|
|
||
|
class CBSCLocalCopyHelper : public IBindStatusCallback,
|
||
|
public IAuthenticate
|
||
|
{
|
||
|
public:
|
||
|
CBSCLocalCopyHelper(IBindCtx *pbc, BOOL fWebfolders);
|
||
|
|
||
|
// IUnknown methods
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||
|
STDMETHODIMP_(ULONG) AddRef () ;
|
||
|
STDMETHODIMP_(ULONG) Release ();
|
||
|
|
||
|
// *** IAuthenticate ***
|
||
|
virtual STDMETHODIMP Authenticate(
|
||
|
HWND *phwnd,
|
||
|
LPWSTR *pszUsername,
|
||
|
LPWSTR *pszPassword);
|
||
|
|
||
|
// *** IBindStatusCallback ***
|
||
|
virtual STDMETHODIMP OnStartBinding(
|
||
|
/* [in] */ DWORD grfBSCOption,
|
||
|
/* [in] */ IBinding *pib);
|
||
|
|
||
|
virtual STDMETHODIMP GetPriority(
|
||
|
/* [out] */ LONG *pnPriority);
|
||
|
|
||
|
virtual STDMETHODIMP OnLowResource(
|
||
|
/* [in] */ DWORD reserved);
|
||
|
|
||
|
virtual STDMETHODIMP OnProgress(
|
||
|
/* [in] */ ULONG ulProgress,
|
||
|
/* [in] */ ULONG ulProgressMax,
|
||
|
/* [in] */ ULONG ulStatusCode,
|
||
|
/* [in] */ LPCWSTR szStatusText);
|
||
|
|
||
|
virtual STDMETHODIMP OnStopBinding(
|
||
|
/* [in] */ HRESULT hresult,
|
||
|
/* [in] */ LPCWSTR szError);
|
||
|
|
||
|
virtual STDMETHODIMP GetBindInfo(
|
||
|
/* [out] */ DWORD *grfBINDINFOF,
|
||
|
/* [unique][out][in] */ BINDINFO *pbindinfo);
|
||
|
|
||
|
virtual STDMETHODIMP OnDataAvailable(
|
||
|
/* [in] */ DWORD grfBSCF,
|
||
|
/* [in] */ DWORD dwSize,
|
||
|
/* [in] */ FORMATETC *pformatetc,
|
||
|
/* [in] */ STGMEDIUM *pstgmed);
|
||
|
|
||
|
virtual STDMETHODIMP OnObjectAvailable(
|
||
|
/* [in] */ REFIID riid,
|
||
|
/* [iid_is][in] */ IUnknown *punk);
|
||
|
|
||
|
|
||
|
protected:
|
||
|
~CBSCLocalCopyHelper();
|
||
|
|
||
|
long _cRef;
|
||
|
IBinding *_pib;
|
||
|
|
||
|
IProgressDialog *_pdlg;
|
||
|
HWND _hwnd;
|
||
|
|
||
|
BOOL _fRosebudMagic;
|
||
|
};
|
||
|
|
||
|
CBSCLocalCopyHelper::CBSCLocalCopyHelper(IBindCtx *pbc, BOOL fWebfolders)
|
||
|
: _cRef(1) , _fRosebudMagic(fWebfolders)
|
||
|
{
|
||
|
// we should use the pbc to
|
||
|
// get our simpler uiprogress
|
||
|
// interface. but for now
|
||
|
// we will do nothing
|
||
|
}
|
||
|
|
||
|
CBSCLocalCopyHelper::~CBSCLocalCopyHelper()
|
||
|
{
|
||
|
ATOMICRELEASE(_pib);
|
||
|
ATOMICRELEASE(_pdlg);
|
||
|
|
||
|
// NOTE dont need to release _ppstm because we dont own it
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::QueryInterface(REFIID riid, void **ppv)
|
||
|
{
|
||
|
static const QITAB qit[] =
|
||
|
{
|
||
|
QITABENT(CBSCLocalCopyHelper, IBindStatusCallback),
|
||
|
QITABENT(CBSCLocalCopyHelper, IAuthenticate),
|
||
|
{ 0 },
|
||
|
};
|
||
|
|
||
|
return QISearch(this, qit, riid, ppv);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CBSCLocalCopyHelper::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CBSCLocalCopyHelper::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::Authenticate(HWND *phwnd, LPWSTR *ppszUsername, LPWSTR *ppszPassword)
|
||
|
{
|
||
|
if (ppszUsername)
|
||
|
*ppszUsername = NULL;
|
||
|
if (ppszPassword)
|
||
|
*ppszPassword = NULL;
|
||
|
|
||
|
*phwnd = GetLastActivePopup(_hwnd);
|
||
|
|
||
|
return *phwnd ? S_OK : E_FAIL;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::OnStartBinding(DWORD dwReserved,IBinding *pib)
|
||
|
{
|
||
|
ATOMICRELEASE(_pib);
|
||
|
if (pib)
|
||
|
{
|
||
|
pib->AddRef();
|
||
|
_pib = pib;
|
||
|
}
|
||
|
|
||
|
if (_pdlg)
|
||
|
{
|
||
|
WCHAR sz[MAX_PATH];
|
||
|
// we are starting out here
|
||
|
_pdlg->Timer(PDTIMER_RESET, NULL);
|
||
|
_pdlg->SetProgress(0, 0);
|
||
|
LoadStringW(HINST_THISDLL, IDS_ACCESSINGMONIKER, sz, ARRAYSIZE(sz));
|
||
|
_pdlg->SetLine(1, sz, FALSE, NULL);
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::GetPriority(LONG *pnPriority)
|
||
|
{
|
||
|
if (pnPriority)
|
||
|
{
|
||
|
// we are a blocking UI thread
|
||
|
*pnPriority = THREAD_PRIORITY_ABOVE_NORMAL;
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::OnLowResource(DWORD reserved)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pszStatusText)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
// handle UI udpates
|
||
|
if (_pdlg)
|
||
|
{
|
||
|
if (_pdlg->HasUserCancelled())
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
||
|
}
|
||
|
|
||
|
if (ulProgressMax)
|
||
|
{
|
||
|
_pdlg->SetProgress(ulProgress, ulProgressMax);
|
||
|
}
|
||
|
|
||
|
if (pszStatusText)
|
||
|
_pdlg->SetLine(1, pszStatusText, FALSE, NULL);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::OnStopBinding(HRESULT hresult, LPCWSTR szError)
|
||
|
{
|
||
|
// handle something
|
||
|
ATOMICRELEASE(_pib);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::GetBindInfo(DWORD *grfBINDINFOF, BINDINFO *pbindinfo)
|
||
|
{
|
||
|
if (_fRosebudMagic && pbindinfo)
|
||
|
{
|
||
|
// this is the magic number that says its ok for URLMON to use DAV/rosebud/webfolders.
|
||
|
// we dont need this during download and in fact if we
|
||
|
// set it, we may not be able to retrieve the resource.
|
||
|
// we coudl do some kind of check on the moniker to verify the clsid
|
||
|
// comes from URLMON. right now this is how office handles
|
||
|
// all of its requests so we do too.
|
||
|
pbindinfo->dwOptions = 1;
|
||
|
}
|
||
|
|
||
|
if (grfBINDINFOF)
|
||
|
{
|
||
|
*grfBINDINFOF = BINDF_GETFROMCACHE_IF_NET_FAIL | BINDF_GETNEWESTVERSION;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
|
||
|
{
|
||
|
#if 0 // we might need this, but right now we are sync
|
||
|
// so we get the stream back in the BindToStorage()
|
||
|
|
||
|
if (grfBSCF & BSCF_LASTDATANOTIFICATION &&
|
||
|
pformatetc &&
|
||
|
pformatetc->tymed == TYMED_ISTREAM &&
|
||
|
pstgmed &&
|
||
|
pstgmed->pstm)
|
||
|
{
|
||
|
if (_ppstm)
|
||
|
{
|
||
|
pstgmed->pstm->AddRef();
|
||
|
*_ppstm = pstgmed->pstm;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CBSCLocalCopyHelper::OnObjectAvailable(REFIID riid, IUnknown *punk)
|
||
|
{
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
HRESULT _CreateUrlmonBindCtx(IBindCtx *pbcIn, BOOL fWebfolders, IBindCtx **ppbc, IBindStatusCallback **ppbsc)
|
||
|
{
|
||
|
IBindCtx *pbc;
|
||
|
HRESULT hr = CreateBindCtx(0, &pbc);
|
||
|
*ppbc = NULL;
|
||
|
*ppbsc = NULL;
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IBindStatusCallback *pbsc = (IBindStatusCallback *) new CBSCLocalCopyHelper(pbcIn, fWebfolders);
|
||
|
|
||
|
if (pbsc)
|
||
|
{
|
||
|
// maybe we should attach it to the existing
|
||
|
// pbc, but for now we will create a new one.
|
||
|
hr = RegisterBindStatusCallback(pbc, pbsc, NULL, 0);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
BIND_OPTS bo = {0};
|
||
|
bo.cbStruct = SIZEOF(bo);
|
||
|
bo.grfMode = BindCtx_GetMode(pbcIn, STGM_READ);
|
||
|
|
||
|
//
|
||
|
// on webfolders, (and possibly other URLMON
|
||
|
// monikers), if you are attempting to create a
|
||
|
// writable stream you also need to pass STGM_CREATE
|
||
|
// even if the file you are writing to already exists.
|
||
|
//
|
||
|
if (bo.grfMode & (STGM_WRITE | STGM_READWRITE))
|
||
|
bo.grfMode |= STGM_CREATE;
|
||
|
|
||
|
hr = pbc->SetBindOptions(&bo);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
*ppbc = pbc;
|
||
|
*ppbsc = pbsc;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pbc->Release();
|
||
|
if (pbsc)
|
||
|
pbsc->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
static const GUID CLSID_WEBFOLDERS = // {BDEADF00-C265-11D0-BCED-00A0C90AB50F}
|
||
|
{ 0xBDEADF00, 0xC265, 0x11D0, { 0xBC, 0xED, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x0F} };
|
||
|
|
||
|
BOOL _IsWebfolders(IShellItem *psi)
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
IShellItem *psiParent;
|
||
|
HRESULT hr = psi->GetParent(&psiParent);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IShellFolder *psf;
|
||
|
SFGAOF flags = SFGAO_LINK;
|
||
|
if (SUCCEEDED(psiParent->GetAttributes(flags, &flags))
|
||
|
&& (flags & SFGAO_LINK))
|
||
|
{
|
||
|
// this is a folder shortcut that needs derefing
|
||
|
IShellItem *psiTarget;
|
||
|
hr = psiParent->BindToHandler(NULL, BHID_LinkTargetItem, IID_PPV_ARG(IShellItem, &psiTarget));
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// switcheroo
|
||
|
psiParent->Release();
|
||
|
psiParent = psiTarget;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = psiParent->BindToHandler(NULL, BHID_SFObject, IID_PPV_ARG(IShellFolder, &psf));
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CLSID clsid;
|
||
|
if (SUCCEEDED(IUnknown_GetClassID(psf, &clsid)))
|
||
|
fRet = IsEqualGUID(clsid, CLSID_WEBFOLDERS);
|
||
|
|
||
|
psf->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
psiParent->Release();
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
HRESULT _CreateStorageHelper(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv)
|
||
|
{
|
||
|
IMoniker *pmk;
|
||
|
HRESULT hr = psi->BindToHandler(pbc, BHID_SFObject, IID_PPV_ARG(IMoniker, &pmk));
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IBindCtx *pbcMk;
|
||
|
IBindStatusCallback *pbsc;
|
||
|
hr = _CreateUrlmonBindCtx(pbc, _IsWebfolders(psi), &pbcMk, &pbsc);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pmk->BindToStorage(pbcMk, NULL, riid, ppv);
|
||
|
// urlmon + ftp url can cause this. remove when 3140245 is fixed
|
||
|
if (SUCCEEDED(hr) && NULL == *ppv)
|
||
|
hr = E_FAIL;
|
||
|
|
||
|
RevokeBindStatusCallback(pbcMk, pbsc);
|
||
|
|
||
|
pbcMk->Release();
|
||
|
pbsc->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
#if 0 // not needed right now
|
||
|
|
||
|
LPCWSTR CLocalCopyHelper::_GetTitle(void)
|
||
|
{
|
||
|
if (!*_szTitle)
|
||
|
{
|
||
|
WCHAR sz[MAX_PATH];
|
||
|
DWORD cch = ARRAYSIZE(_szTitle);
|
||
|
GetModuleFileNameW(NULL, sz, ARRAYSIZE(sz));
|
||
|
|
||
|
if (FAILED(AssocQueryStringW(ASSOCF_INIT_BYEXENAME | ASSOCF_VERIFY, ASSOCSTR_FRIENDLYAPPNAME, sz, NULL, _szTitle, &cch)))
|
||
|
StrCpyNW(_szTitle, PathFindFileNameW(sz), ARRAYSIZE(_szTitle));
|
||
|
}
|
||
|
|
||
|
return _szTitle;
|
||
|
}
|
||
|
void CLocalCopyHelper::_InitUI(MKHELPF flags, IProgressDialog **ppdlg, HWND *phwnd, LPCWSTR pszTitle)
|
||
|
{
|
||
|
*ppdlg = NULL;
|
||
|
|
||
|
if (flags & MKHELPF_NOUI)
|
||
|
{
|
||
|
*phwnd = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!(flags & MKHELPF_NOPROGRESSUI) && *phwnd)
|
||
|
{
|
||
|
IProgressDialog *pdlg;
|
||
|
if(SUCCEEDED(CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IProgressDialog, &pdlg))))
|
||
|
{
|
||
|
if (!pszTitle)
|
||
|
pszTitle = _GetTitle();
|
||
|
|
||
|
pdlg->SetTitle(pszTitle);
|
||
|
pdlg->SetAnimation(g_hinst, IDA_FILECOPY);
|
||
|
pdlg->SetLine(2, _pszName, TRUE, NULL);
|
||
|
if (SUCCEEDED(pdlg->StartProgressDialog(*phwnd, NULL, PROGDLG_MODAL | PROGDLG_AUTOTIME, NULL)))
|
||
|
*ppdlg = pdlg;
|
||
|
else
|
||
|
pdlg->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
EXTERN_C WINSHELLAPI HRESULT STDAPICALLTYPE SHCopyMonikerToTemp(IMoniker *pmk, LPCWSTR pszIn, LPWSTR pszOut, int cchOut)
|
||
|
{
|
||
|
// REMOVE this as soon as ComDlg32 is updated
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|