|
|
#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() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
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) { 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; }
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; }
|