Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
11 KiB

  1. #include "shellprv.h"
  2. //#include "mkhelp.h"
  3. #include "urlmon.h"
  4. #include "ids.h"
  5. class CBSCLocalCopyHelper : public IBindStatusCallback,
  6. public IAuthenticate
  7. {
  8. public:
  9. CBSCLocalCopyHelper(IBindCtx *pbc, BOOL fWebfolders);
  10. // IUnknown methods
  11. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  12. STDMETHODIMP_(ULONG) AddRef () ;
  13. STDMETHODIMP_(ULONG) Release ();
  14. // *** IAuthenticate ***
  15. virtual STDMETHODIMP Authenticate(
  16. HWND *phwnd,
  17. LPWSTR *pszUsername,
  18. LPWSTR *pszPassword);
  19. // *** IBindStatusCallback ***
  20. virtual STDMETHODIMP OnStartBinding(
  21. /* [in] */ DWORD grfBSCOption,
  22. /* [in] */ IBinding *pib);
  23. virtual STDMETHODIMP GetPriority(
  24. /* [out] */ LONG *pnPriority);
  25. virtual STDMETHODIMP OnLowResource(
  26. /* [in] */ DWORD reserved);
  27. virtual STDMETHODIMP OnProgress(
  28. /* [in] */ ULONG ulProgress,
  29. /* [in] */ ULONG ulProgressMax,
  30. /* [in] */ ULONG ulStatusCode,
  31. /* [in] */ LPCWSTR szStatusText);
  32. virtual STDMETHODIMP OnStopBinding(
  33. /* [in] */ HRESULT hresult,
  34. /* [in] */ LPCWSTR szError);
  35. virtual STDMETHODIMP GetBindInfo(
  36. /* [out] */ DWORD *grfBINDINFOF,
  37. /* [unique][out][in] */ BINDINFO *pbindinfo);
  38. virtual STDMETHODIMP OnDataAvailable(
  39. /* [in] */ DWORD grfBSCF,
  40. /* [in] */ DWORD dwSize,
  41. /* [in] */ FORMATETC *pformatetc,
  42. /* [in] */ STGMEDIUM *pstgmed);
  43. virtual STDMETHODIMP OnObjectAvailable(
  44. /* [in] */ REFIID riid,
  45. /* [iid_is][in] */ IUnknown *punk);
  46. protected:
  47. ~CBSCLocalCopyHelper();
  48. long _cRef;
  49. IBinding *_pib;
  50. IProgressDialog *_pdlg;
  51. HWND _hwnd;
  52. BOOL _fRosebudMagic;
  53. };
  54. CBSCLocalCopyHelper::CBSCLocalCopyHelper(IBindCtx *pbc, BOOL fWebfolders)
  55. : _cRef(1) , _fRosebudMagic(fWebfolders)
  56. {
  57. // we should use the pbc to
  58. // get our simpler uiprogress
  59. // interface. but for now
  60. // we will do nothing
  61. }
  62. CBSCLocalCopyHelper::~CBSCLocalCopyHelper()
  63. {
  64. ATOMICRELEASE(_pib);
  65. ATOMICRELEASE(_pdlg);
  66. // NOTE dont need to release _ppstm because we dont own it
  67. }
  68. STDMETHODIMP CBSCLocalCopyHelper::QueryInterface(REFIID riid, void **ppv)
  69. {
  70. static const QITAB qit[] =
  71. {
  72. QITABENT(CBSCLocalCopyHelper, IBindStatusCallback),
  73. QITABENT(CBSCLocalCopyHelper, IAuthenticate),
  74. { 0 },
  75. };
  76. return QISearch(this, qit, riid, ppv);
  77. }
  78. STDMETHODIMP_(ULONG) CBSCLocalCopyHelper::AddRef()
  79. {
  80. return InterlockedIncrement(&_cRef);
  81. }
  82. STDMETHODIMP_(ULONG) CBSCLocalCopyHelper::Release()
  83. {
  84. if (InterlockedDecrement(&_cRef))
  85. return _cRef;
  86. delete this;
  87. return 0;
  88. }
  89. STDMETHODIMP CBSCLocalCopyHelper::Authenticate(HWND *phwnd, LPWSTR *ppszUsername, LPWSTR *ppszPassword)
  90. {
  91. if (ppszUsername)
  92. *ppszUsername = NULL;
  93. if (ppszPassword)
  94. *ppszPassword = NULL;
  95. *phwnd = GetLastActivePopup(_hwnd);
  96. return *phwnd ? S_OK : E_FAIL;
  97. }
  98. STDMETHODIMP CBSCLocalCopyHelper::OnStartBinding(DWORD dwReserved,IBinding *pib)
  99. {
  100. ATOMICRELEASE(_pib);
  101. if (pib)
  102. {
  103. pib->AddRef();
  104. _pib = pib;
  105. }
  106. if (_pdlg)
  107. {
  108. WCHAR sz[MAX_PATH];
  109. // we are starting out here
  110. _pdlg->Timer(PDTIMER_RESET, NULL);
  111. _pdlg->SetProgress(0, 0);
  112. LoadStringW(HINST_THISDLL, IDS_ACCESSINGMONIKER, sz, ARRAYSIZE(sz));
  113. _pdlg->SetLine(1, sz, FALSE, NULL);
  114. }
  115. return S_OK;
  116. }
  117. STDMETHODIMP CBSCLocalCopyHelper::GetPriority(LONG *pnPriority)
  118. {
  119. if (pnPriority)
  120. {
  121. // we are a blocking UI thread
  122. *pnPriority = THREAD_PRIORITY_ABOVE_NORMAL;
  123. }
  124. return S_OK;
  125. }
  126. STDMETHODIMP CBSCLocalCopyHelper::OnLowResource(DWORD reserved)
  127. {
  128. return S_OK;
  129. }
  130. STDMETHODIMP CBSCLocalCopyHelper::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pszStatusText)
  131. {
  132. HRESULT hr = S_OK;
  133. // handle UI udpates
  134. if (_pdlg)
  135. {
  136. if (_pdlg->HasUserCancelled())
  137. {
  138. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  139. }
  140. if (ulProgressMax)
  141. {
  142. _pdlg->SetProgress(ulProgress, ulProgressMax);
  143. }
  144. if (pszStatusText)
  145. _pdlg->SetLine(1, pszStatusText, FALSE, NULL);
  146. }
  147. return hr;
  148. }
  149. STDMETHODIMP CBSCLocalCopyHelper::OnStopBinding(HRESULT hresult, LPCWSTR szError)
  150. {
  151. // handle something
  152. ATOMICRELEASE(_pib);
  153. return S_OK;
  154. }
  155. STDMETHODIMP CBSCLocalCopyHelper::GetBindInfo(DWORD *grfBINDINFOF, BINDINFO *pbindinfo)
  156. {
  157. if (_fRosebudMagic && pbindinfo)
  158. {
  159. // this is the magic number that says its ok for URLMON to use DAV/rosebud/webfolders.
  160. // we dont need this during download and in fact if we
  161. // set it, we may not be able to retrieve the resource.
  162. // we coudl do some kind of check on the moniker to verify the clsid
  163. // comes from URLMON. right now this is how office handles
  164. // all of its requests so we do too.
  165. pbindinfo->dwOptions = 1;
  166. }
  167. if (grfBINDINFOF)
  168. {
  169. *grfBINDINFOF = BINDF_GETFROMCACHE_IF_NET_FAIL | BINDF_GETNEWESTVERSION;
  170. }
  171. return S_OK;
  172. }
  173. STDMETHODIMP CBSCLocalCopyHelper::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
  174. {
  175. #if 0 // we might need this, but right now we are sync
  176. // so we get the stream back in the BindToStorage()
  177. if (grfBSCF & BSCF_LASTDATANOTIFICATION &&
  178. pformatetc &&
  179. pformatetc->tymed == TYMED_ISTREAM &&
  180. pstgmed &&
  181. pstgmed->pstm)
  182. {
  183. if (_ppstm)
  184. {
  185. pstgmed->pstm->AddRef();
  186. *_ppstm = pstgmed->pstm;
  187. }
  188. }
  189. #endif
  190. return S_OK;
  191. }
  192. STDMETHODIMP CBSCLocalCopyHelper::OnObjectAvailable(REFIID riid, IUnknown *punk)
  193. {
  194. return E_UNEXPECTED;
  195. }
  196. HRESULT _CreateUrlmonBindCtx(IBindCtx *pbcIn, BOOL fWebfolders, IBindCtx **ppbc, IBindStatusCallback **ppbsc)
  197. {
  198. IBindCtx *pbc;
  199. HRESULT hr = CreateBindCtx(0, &pbc);
  200. *ppbc = NULL;
  201. *ppbsc = NULL;
  202. if (SUCCEEDED(hr))
  203. {
  204. IBindStatusCallback *pbsc = (IBindStatusCallback *) new CBSCLocalCopyHelper(pbcIn, fWebfolders);
  205. if (pbsc)
  206. {
  207. // maybe we should attach it to the existing
  208. // pbc, but for now we will create a new one.
  209. hr = RegisterBindStatusCallback(pbc, pbsc, NULL, 0);
  210. if (SUCCEEDED(hr))
  211. {
  212. BIND_OPTS bo = {0};
  213. bo.cbStruct = SIZEOF(bo);
  214. bo.grfMode = BindCtx_GetMode(pbcIn, STGM_READ);
  215. //
  216. // on webfolders, (and possibly other URLMON
  217. // monikers), if you are attempting to create a
  218. // writable stream you also need to pass STGM_CREATE
  219. // even if the file you are writing to already exists.
  220. //
  221. if (bo.grfMode & (STGM_WRITE | STGM_READWRITE))
  222. bo.grfMode |= STGM_CREATE;
  223. hr = pbc->SetBindOptions(&bo);
  224. }
  225. }
  226. else
  227. hr = E_OUTOFMEMORY;
  228. if (SUCCEEDED(hr))
  229. {
  230. *ppbc = pbc;
  231. *ppbsc = pbsc;
  232. }
  233. else
  234. {
  235. pbc->Release();
  236. if (pbsc)
  237. pbsc->Release();
  238. }
  239. }
  240. return hr;
  241. }
  242. static const GUID CLSID_WEBFOLDERS = // {BDEADF00-C265-11D0-BCED-00A0C90AB50F}
  243. { 0xBDEADF00, 0xC265, 0x11D0, { 0xBC, 0xED, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x0F} };
  244. BOOL _IsWebfolders(IShellItem *psi)
  245. {
  246. BOOL fRet = FALSE;
  247. IShellItem *psiParent;
  248. HRESULT hr = psi->GetParent(&psiParent);
  249. if (SUCCEEDED(hr))
  250. {
  251. IShellFolder *psf;
  252. SFGAOF flags = SFGAO_LINK;
  253. if (SUCCEEDED(psiParent->GetAttributes(flags, &flags))
  254. && (flags & SFGAO_LINK))
  255. {
  256. // this is a folder shortcut that needs derefing
  257. IShellItem *psiTarget;
  258. hr = psiParent->BindToHandler(NULL, BHID_LinkTargetItem, IID_PPV_ARG(IShellItem, &psiTarget));
  259. if (SUCCEEDED(hr))
  260. {
  261. // switcheroo
  262. psiParent->Release();
  263. psiParent = psiTarget;
  264. }
  265. }
  266. if (SUCCEEDED(hr))
  267. {
  268. hr = psiParent->BindToHandler(NULL, BHID_SFObject, IID_PPV_ARG(IShellFolder, &psf));
  269. if (SUCCEEDED(hr))
  270. {
  271. CLSID clsid;
  272. if (SUCCEEDED(IUnknown_GetClassID(psf, &clsid)))
  273. fRet = IsEqualGUID(clsid, CLSID_WEBFOLDERS);
  274. psf->Release();
  275. }
  276. }
  277. psiParent->Release();
  278. }
  279. return fRet;
  280. }
  281. HRESULT _CreateStorageHelper(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv)
  282. {
  283. IMoniker *pmk;
  284. HRESULT hr = psi->BindToHandler(pbc, BHID_SFObject, IID_PPV_ARG(IMoniker, &pmk));
  285. if (SUCCEEDED(hr))
  286. {
  287. IBindCtx *pbcMk;
  288. IBindStatusCallback *pbsc;
  289. hr = _CreateUrlmonBindCtx(pbc, _IsWebfolders(psi), &pbcMk, &pbsc);
  290. if (SUCCEEDED(hr))
  291. {
  292. hr = pmk->BindToStorage(pbcMk, NULL, riid, ppv);
  293. // urlmon + ftp url can cause this. remove when 3140245 is fixed
  294. if (SUCCEEDED(hr) && NULL == *ppv)
  295. hr = E_FAIL;
  296. RevokeBindStatusCallback(pbcMk, pbsc);
  297. pbcMk->Release();
  298. pbsc->Release();
  299. }
  300. }
  301. return hr;
  302. }
  303. #if 0 // not needed right now
  304. LPCWSTR CLocalCopyHelper::_GetTitle(void)
  305. {
  306. if (!*_szTitle)
  307. {
  308. WCHAR sz[MAX_PATH];
  309. DWORD cch = ARRAYSIZE(_szTitle);
  310. GetModuleFileNameW(NULL, sz, ARRAYSIZE(sz));
  311. if (FAILED(AssocQueryStringW(ASSOCF_INIT_BYEXENAME | ASSOCF_VERIFY, ASSOCSTR_FRIENDLYAPPNAME, sz, NULL, _szTitle, &cch)))
  312. StrCpyNW(_szTitle, PathFindFileNameW(sz), ARRAYSIZE(_szTitle));
  313. }
  314. return _szTitle;
  315. }
  316. void CLocalCopyHelper::_InitUI(MKHELPF flags, IProgressDialog **ppdlg, HWND *phwnd, LPCWSTR pszTitle)
  317. {
  318. *ppdlg = NULL;
  319. if (flags & MKHELPF_NOUI)
  320. {
  321. *phwnd = NULL;
  322. return;
  323. }
  324. if (!(flags & MKHELPF_NOPROGRESSUI) && *phwnd)
  325. {
  326. IProgressDialog *pdlg;
  327. if(SUCCEEDED(CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IProgressDialog, &pdlg))))
  328. {
  329. if (!pszTitle)
  330. pszTitle = _GetTitle();
  331. pdlg->SetTitle(pszTitle);
  332. pdlg->SetAnimation(g_hinst, IDA_FILECOPY);
  333. pdlg->SetLine(2, _pszName, TRUE, NULL);
  334. if (SUCCEEDED(pdlg->StartProgressDialog(*phwnd, NULL, PROGDLG_MODAL | PROGDLG_AUTOTIME, NULL)))
  335. *ppdlg = pdlg;
  336. else
  337. pdlg->Release();
  338. }
  339. }
  340. }
  341. #endif
  342. EXTERN_C WINSHELLAPI HRESULT STDAPICALLTYPE SHCopyMonikerToTemp(IMoniker *pmk, LPCWSTR pszIn, LPWSTR pszOut, int cchOut)
  343. {
  344. // REMOVE this as soon as ComDlg32 is updated
  345. return E_NOTIMPL;
  346. }