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.

690 lines
22 KiB

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. #include "datautil.h"
  4. #include "_security.h"
  5. #include <urlmon.h>
  6. #define COPYMOVETO_REGKEY TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer")
  7. #define COPYMOVETO_SUBKEY TEXT("CopyMoveTo")
  8. #define COPYMOVETO_VALUE TEXT("LastFolder")
  9. class CCopyMoveToMenu : public IContextMenu3
  10. , public IShellExtInit
  11. , public CObjectWithSite
  12. , public IFolderFilter
  13. {
  14. public:
  15. // IUnknown
  16. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
  17. STDMETHOD_(ULONG,AddRef)(void);
  18. STDMETHOD_(ULONG,Release)(void);
  19. // IContextMenu
  20. STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
  21. STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici);
  22. STDMETHOD(GetCommandString)(UINT_PTR idCmd, UINT uType, UINT *pRes, LPSTR pszName, UINT cchMax);
  23. // IContextMenu2
  24. STDMETHOD(HandleMenuMsg)(UINT uMsg, WPARAM wParam, LPARAM lParam);
  25. // IContextMenu3
  26. STDMETHOD(HandleMenuMsg2)(UINT uMsg, WPARAM wParam, LPARAM lParam,LRESULT *lResult);
  27. // IShellExtInit
  28. STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
  29. // IFolderFilter
  30. STDMETHODIMP ShouldShow(IShellFolder* psf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem);
  31. STDMETHODIMP GetEnumFlags(IShellFolder* psf, LPCITEMIDLIST pidlFolder, HWND *phwnd, DWORD *pgrfFlags);
  32. private:
  33. BOOL m_bMoveTo;
  34. LONG m_cRef;
  35. HMENU m_hmenu;
  36. UINT m_idCmdFirst;
  37. BOOL m_bFirstTime;
  38. LPITEMIDLIST m_pidlSource;
  39. IDataObject * m_pdtobj;
  40. CCopyMoveToMenu(BOOL bMoveTo = FALSE);
  41. ~CCopyMoveToMenu();
  42. HRESULT _DoDragDrop(LPCMINVOKECOMMANDINFO pici, LPCITEMIDLIST pidlFolder);
  43. BOOL _DidZoneCheckPass(LPCITEMIDLIST pidlFolder);
  44. void _GenerateDialogTitle(LPTSTR szTitle, int nBuffer);
  45. friend HRESULT CCopyToMenu_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut);
  46. friend HRESULT CMoveToMenu_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut);
  47. };
  48. CCopyMoveToMenu::CCopyMoveToMenu(BOOL bMoveTo) : m_cRef(1), m_bMoveTo(bMoveTo)
  49. {
  50. DllAddRef();
  51. // Assert that the member variables are zero initialized during construction
  52. ASSERT(!m_pidlSource);
  53. }
  54. CCopyMoveToMenu::~CCopyMoveToMenu()
  55. {
  56. Pidl_Set(&m_pidlSource, NULL);
  57. ATOMICRELEASE(m_pdtobj);
  58. DllRelease();
  59. }
  60. HRESULT CCopyToMenu_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut)
  61. {
  62. CCopyMoveToMenu *pcopyto = new CCopyMoveToMenu();
  63. if (pcopyto)
  64. {
  65. HRESULT hres = pcopyto->QueryInterface(riid, ppvOut);
  66. pcopyto->Release();
  67. return hres;
  68. }
  69. *ppvOut = NULL;
  70. return E_OUTOFMEMORY;
  71. }
  72. HRESULT CMoveToMenu_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut)
  73. {
  74. CCopyMoveToMenu *pmoveto = new CCopyMoveToMenu(TRUE);
  75. if (pmoveto)
  76. {
  77. HRESULT hres = pmoveto->QueryInterface(riid, ppvOut);
  78. pmoveto->Release();
  79. return hres;
  80. }
  81. *ppvOut = NULL;
  82. return E_OUTOFMEMORY;
  83. }
  84. HRESULT CCopyMoveToMenu::QueryInterface(REFIID riid, void **ppvObj)
  85. {
  86. static const QITAB qit[] = {
  87. QITABENT(CCopyMoveToMenu, IContextMenu3),
  88. QITABENTMULTI(CCopyMoveToMenu, IContextMenu, IContextMenu3),
  89. QITABENTMULTI(CCopyMoveToMenu, IContextMenu2, IContextMenu3),
  90. QITABENT(CCopyMoveToMenu, IShellExtInit),
  91. QITABENT(CCopyMoveToMenu, IObjectWithSite),
  92. QITABENT(CCopyMoveToMenu, IFolderFilter),
  93. { 0 },
  94. };
  95. return QISearch(this, qit, riid, ppvObj);
  96. }
  97. ULONG CCopyMoveToMenu::AddRef()
  98. {
  99. return InterlockedIncrement(&m_cRef);
  100. }
  101. ULONG CCopyMoveToMenu::Release()
  102. {
  103. if (InterlockedDecrement(&m_cRef))
  104. return m_cRef;
  105. delete this;
  106. return 0;
  107. }
  108. HRESULT CCopyMoveToMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  109. {
  110. // if they want the default menu only (CMF_DEFAULTONLY) OR
  111. // this is being called for a shortcut (CMF_VERBSONLY)
  112. // we don't want to be on the context menu
  113. if (uFlags & (CMF_DEFAULTONLY | CMF_VERBSONLY))
  114. return NOERROR;
  115. UINT idCmd = idCmdFirst;
  116. TCHAR szMenuItem[80];
  117. m_idCmdFirst = idCmdFirst;
  118. LoadString(g_hinst, m_bMoveTo? IDS_CMTF_MOVETO: IDS_CMTF_COPYTO, szMenuItem, ARRAYSIZE(szMenuItem));
  119. InsertMenu(hmenu, indexMenu++, MF_BYPOSITION, idCmd++, szMenuItem);
  120. return ResultFromShort(idCmd-idCmdFirst);
  121. }
  122. struct BROWSEINFOINITSTRUCT
  123. {
  124. LPITEMIDLIST *ppidl;
  125. BOOL bMoveTo;
  126. IDataObject *pdtobj;
  127. CCopyMoveToMenu *pCMTM;
  128. LPITEMIDLIST *ppidlSource;
  129. };
  130. int BrowseCallback(HWND hwnd, UINT msg, LPARAM lParam, LPARAM lpData)
  131. {
  132. int idResource = 0;
  133. switch (msg)
  134. {
  135. case BFFM_IUNKNOWN:
  136. // Try to get an IFolderFilterSite from the lParam, so we can set ourselves as the filter.
  137. if (lParam)
  138. {
  139. IFolderFilterSite *pFilterSite;
  140. HRESULT hr = ((IUnknown*)lParam)->QueryInterface(IID_PPV_ARG(IFolderFilterSite, &pFilterSite));
  141. if (SUCCEEDED(hr))
  142. {
  143. IUnknown *pUnk = NULL;
  144. if (SUCCEEDED(((BROWSEINFOINITSTRUCT *)lpData)->pCMTM->QueryInterface(IID_PPV_ARG(IUnknown, &pUnk))))
  145. {
  146. pFilterSite->SetFilter(pUnk);
  147. pUnk->Release();
  148. }
  149. pFilterSite->Release();
  150. }
  151. }
  152. #if 0
  153. // If CCopyMoveToMenu ever holds onto the IUnknown passed in, this is our indication to stop using it/release it.
  154. else
  155. {
  156. // Release our ref to the IUnknown
  157. }
  158. #endif
  159. break;
  160. case BFFM_INITIALIZED:
  161. {
  162. BROWSEINFOINITSTRUCT* pbiis = (BROWSEINFOINITSTRUCT*)lpData;
  163. // Set the caption. ('Select a destination')
  164. TCHAR szTitle[100];
  165. if (LoadString(g_hinst, pbiis->bMoveTo ? IDS_CMTF_CAPTION_MOVE : IDS_CMTF_CAPTION_COPY, szTitle, ARRAYSIZE(szTitle)))
  166. {
  167. SetWindowText(hwnd, szTitle);
  168. }
  169. // Set the text of the Ok Button.
  170. SendMessage(hwnd, BFFM_SETOKTEXT, 0, (LPARAM)MAKEINTRESOURCE((pbiis->bMoveTo) ? IDS_MOVE : IDS_COPY));
  171. // Set My Computer expanded.
  172. // NOTE: If IShellNameSpace is made public, we can get this from IObjectWithSite on the IUnknown
  173. // passed to us by BFFM_IUNKNOWN. Then we can call Expand() on IShellNameSpace instead.
  174. LPITEMIDLIST pidlMyComputer;
  175. HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer);
  176. if (SUCCEEDED(hr))
  177. {
  178. SendMessage(hwnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pidlMyComputer);
  179. ILFree(pidlMyComputer);
  180. }
  181. // Set the default selected pidl
  182. SendMessage(hwnd, BFFM_SETSELECTION, FALSE, (LPARAM)*(((BROWSEINFOINITSTRUCT *)lpData)->ppidl));
  183. break;
  184. }
  185. case BFFM_VALIDATEFAILEDW:
  186. idResource = IDS_PathNotFoundW;
  187. // FALL THRU...
  188. case BFFM_VALIDATEFAILEDA:
  189. if (0 == idResource) // Make sure we didn't come from BFFM_VALIDATEFAILEDW
  190. idResource = IDS_PathNotFoundA;
  191. ShellMessageBox(g_hinst, hwnd,
  192. MAKEINTRESOURCE(idResource),
  193. MAKEINTRESOURCE(IDS_CMTF_COPYORMOVE_DLG_TITLE),
  194. MB_OK|MB_ICONERROR, (LPVOID)lParam);
  195. return 1; // 1:leave dialog up for another try...
  196. /*NOTREACHED*/
  197. case BFFM_SELCHANGED:
  198. if (lParam)
  199. {
  200. // Here, during a move operation, we want to disable the move (ok) button when the destination
  201. // folder is the same as the source.
  202. // During a move or copy operation, we want to disable the move/copy (ok) button when the
  203. // destination is not a drop target.
  204. // In all other cases, we enable the ok/move/copy button.
  205. BROWSEINFOINITSTRUCT *pbiis = (BROWSEINFOINITSTRUCT *)lpData;
  206. if (pbiis)
  207. {
  208. BOOL bEnableOK = FALSE;
  209. IShellFolder *psf;
  210. if ((!pbiis->bMoveTo || !ILIsEqual(*pbiis->ppidlSource, (LPITEMIDLIST)lParam)) &&
  211. (SUCCEEDED(SHBindToObjectEx(NULL, (LPITEMIDLIST)lParam, NULL, IID_PPV_ARG(IShellFolder, &psf)))))
  212. {
  213. IDropTarget *pdt;
  214. if (SUCCEEDED(psf->CreateViewObject(hwnd, IID_PPV_ARG(IDropTarget, &pdt))))
  215. {
  216. POINTL pt = {0, 0};
  217. DWORD dwEffect;
  218. DWORD grfKeyState;
  219. if (pbiis->bMoveTo)
  220. {
  221. dwEffect = DROPEFFECT_MOVE;
  222. grfKeyState = MK_SHIFT | MK_LBUTTON;
  223. }
  224. else
  225. {
  226. dwEffect = DROPEFFECT_COPY;
  227. grfKeyState = MK_CONTROL | MK_LBUTTON;
  228. }
  229. if (SUCCEEDED(pdt->DragEnter(pbiis->pdtobj, grfKeyState, pt, &dwEffect)))
  230. {
  231. if (dwEffect)
  232. {
  233. bEnableOK = TRUE;
  234. }
  235. pdt->DragLeave();
  236. }
  237. pdt->Release();
  238. }
  239. psf->Release();
  240. }
  241. SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)bEnableOK);
  242. }
  243. }
  244. break;
  245. }
  246. return 0;
  247. }
  248. BOOL CCopyMoveToMenu::_DidZoneCheckPass(LPCITEMIDLIST pidlFolder)
  249. {
  250. BOOL fPass = TRUE;
  251. IInternetSecurityMgrSite * pisms;
  252. // We plan on doing UI and we need to go modal during the UI.
  253. ASSERT(_punkSite && pidlFolder);
  254. IUnknown_QueryService(_punkSite, SID_SFolderView, IID_PPV_ARG(IInternetSecurityMgrSite, &pisms));
  255. if (S_OK != ZoneCheckPidl(pidlFolder, URLACTION_SHELL_FILE_DOWNLOAD, (PUAF_FORCEUI_FOREGROUND | PUAF_WARN_IF_DENIED), pisms))
  256. {
  257. fPass = FALSE;
  258. }
  259. ATOMICRELEASE(pisms);
  260. return fPass;
  261. }
  262. HRESULT CCopyMoveToMenu::_DoDragDrop(LPCMINVOKECOMMANDINFO pici, LPCITEMIDLIST pidlFolder)
  263. {
  264. // This should always succeed because the caller (SHBrowseForFolder) should
  265. // have weeded out the non-folders.
  266. IShellFolder *psf;
  267. HRESULT hr = SHBindToObjectEx(NULL, pidlFolder, NULL, IID_PPV_ARG(IShellFolder, &psf));
  268. if (SUCCEEDED(hr))
  269. {
  270. IDropTarget *pdrop;
  271. hr = psf->CreateViewObject(pici->hwnd, IID_PPV_ARG(IDropTarget, &pdrop));
  272. if (SUCCEEDED(hr)) // Will fail for some targets. (Like Nethood->Entire Network)
  273. {
  274. DWORD grfKeyState;
  275. DWORD dwEffect;
  276. if (m_bMoveTo)
  277. {
  278. grfKeyState = MK_SHIFT | MK_LBUTTON;
  279. dwEffect = DROPEFFECT_MOVE;
  280. }
  281. else
  282. {
  283. grfKeyState = MK_CONTROL | MK_LBUTTON;
  284. dwEffect = DROPEFFECT_COPY;
  285. }
  286. hr = SimulateDropWithPasteSucceeded(pdrop, m_pdtobj, grfKeyState, NULL, dwEffect, NULL, FALSE);
  287. pdrop->Release();
  288. }
  289. psf->Release();
  290. }
  291. if (FAILED_AND_NOT_CANCELED(hr))
  292. {
  293. // Go modal during the UI.
  294. IUnknown_EnableModless(_punkSite, FALSE);
  295. ShellMessageBox(g_hinst, pici->hwnd, MAKEINTRESOURCE(IDS_CMTF_ERRORMSG),
  296. MAKEINTRESOURCE(IDS_CABINET), MB_OK|MB_ICONEXCLAMATION);
  297. IUnknown_EnableModless(_punkSite, TRUE);
  298. }
  299. return hr;
  300. }
  301. void CCopyMoveToMenu::_GenerateDialogTitle(LPTSTR szTitle, int nBuffer)
  302. {
  303. szTitle[0] = 0;
  304. if (m_pdtobj)
  305. {
  306. int nItemCount = DataObj_GetHIDACount(m_pdtobj);
  307. TCHAR szDescription[200];
  308. if (nItemCount > 1)
  309. {
  310. DWORD_PTR rg[1];
  311. rg[0] = (DWORD_PTR)nItemCount;
  312. // More than one item is selected. Don't bother listing all items.
  313. DWORD dwMessageId = m_bMoveTo ? IDS_CMTF_MOVE_MULTIPLE_DLG_TITLE2 : IDS_CMTF_COPY_MULTIPLE_DLG_TITLE2;
  314. if (LoadString(g_hinst, dwMessageId, szDescription, ARRAYSIZE(szDescription)) > 0)
  315. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, szDescription, 0, 0, szTitle, nBuffer, (va_list*)rg);
  316. }
  317. else if (nItemCount == 1)
  318. {
  319. // We have only one item selected. Use its name.
  320. STGMEDIUM medium;
  321. LPIDA pida = DataObj_GetHIDA(m_pdtobj, &medium);
  322. if (pida)
  323. {
  324. LPITEMIDLIST pidlFull = IDA_FullIDList(pida, 0);
  325. if (pidlFull)
  326. {
  327. TCHAR szItemName[MAX_PATH];
  328. HRESULT hres = SHGetNameAndFlags(pidlFull, SHGDN_INFOLDER, szItemName, ARRAYSIZE(szItemName), NULL);
  329. if (SUCCEEDED(hres))
  330. {
  331. DWORD_PTR rg[1];
  332. rg[0] = (DWORD_PTR)szItemName;
  333. DWORD dwMessageId = m_bMoveTo ? IDS_CMTF_MOVE_DLG_TITLE2 : IDS_CMTF_COPY_DLG_TITLE2;
  334. if (LoadString(g_hinst, dwMessageId, szDescription, ARRAYSIZE(szDescription)))
  335. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, szDescription, 0, 0, szTitle, nBuffer, (va_list*)rg);
  336. }
  337. ILFree(pidlFull);
  338. }
  339. HIDA_ReleaseStgMedium(pida, &medium);
  340. }
  341. }
  342. else
  343. {
  344. // no HIDA, just default to something.
  345. DWORD dwMessageId = m_bMoveTo ? IDS_CMTF_MOVE_DLG_TITLE : IDS_CMTF_COPY_DLG_TITLE;
  346. LoadString(g_hinst, dwMessageId, szTitle, nBuffer);
  347. }
  348. }
  349. }
  350. /**
  351. * Determines if the pidl still exists. If it does not, if frees it
  352. * and replaces it with a My Documents pidl
  353. */
  354. void _BFFSwitchToMyDocsIfPidlNotExist(LPITEMIDLIST *ppidl)
  355. {
  356. IShellFolder *psf;
  357. LPCITEMIDLIST pidlChild;
  358. if (SUCCEEDED(SHBindToIDListParent(*ppidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
  359. {
  360. DWORD dwAttr = SFGAO_VALIDATE;
  361. if (FAILED(psf->GetAttributesOf(1, &pidlChild, &dwAttr)))
  362. {
  363. // This means the pidl no longer exists.
  364. // Use my documents instead.
  365. LPITEMIDLIST pidlMyDocs;
  366. if (SUCCEEDED(SHGetFolderLocation(NULL, CSIDL_PERSONAL, NULL, 0, &pidlMyDocs)))
  367. {
  368. // Good. Now we can get rid of the old pidl and use this one.
  369. ILFree(*ppidl);
  370. *ppidl = pidlMyDocs;
  371. }
  372. }
  373. psf->Release();
  374. }
  375. }
  376. HRESULT CCopyMoveToMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  377. {
  378. HRESULT hres;
  379. if (m_pdtobj)
  380. {
  381. HKEY hkey = NULL;
  382. IStream *pstrm = NULL;
  383. LPITEMIDLIST pidlSelectedFolder = NULL;
  384. LPITEMIDLIST pidlFolder = NULL;
  385. TCHAR szTitle[MAX_PATH + 200];
  386. BROWSEINFOINITSTRUCT biis =
  387. { // passing the address of pidl because it is not init-ed yet
  388. // but it will be before call to SHBrowseForFolder so save one assignment
  389. &pidlSelectedFolder,
  390. m_bMoveTo,
  391. m_pdtobj,
  392. this,
  393. &m_pidlSource
  394. };
  395. BROWSEINFO bi =
  396. {
  397. pici->hwnd,
  398. NULL,
  399. NULL,
  400. szTitle,
  401. BIF_VALIDATE | BIF_NEWDIALOGSTYLE | BIF_UAHINT | BIF_NOTRANSLATETARGETS,
  402. BrowseCallback,
  403. (LPARAM)&biis
  404. };
  405. _GenerateDialogTitle(szTitle, ARRAYSIZE(szTitle));
  406. if (RegOpenKeyEx(HKEY_CURRENT_USER, COPYMOVETO_REGKEY, 0, KEY_READ | KEY_WRITE, &hkey) == ERROR_SUCCESS)
  407. {
  408. pstrm = OpenRegStream(hkey, COPYMOVETO_SUBKEY, COPYMOVETO_VALUE, STGM_READWRITE);
  409. if (pstrm) // OpenRegStream will fail if the reg key is empty.
  410. ILLoadFromStream(pstrm, &pidlSelectedFolder);
  411. // This will switch the pidl to My Docs if the pidl does not exist.
  412. // This prevents us from having My Computer as the default (that's what happens if our
  413. // initial set selected call fails).
  414. // Note: ideally, we would check in BFFM_INITIALIZED, if our BFFM_SETSELECTION failed
  415. // then do a BFFM_SETSELECTION on My Documents instead. However, BFFM_SETSELECTION always
  416. // returns zero (it's doc'd to do this to, so we can't change). So we do the validation
  417. // here instead. There is still a small chance that this folder will be deleted in between our
  418. // check here, and when we call BFFM_SETSELECTION, but oh well.
  419. _BFFSwitchToMyDocsIfPidlNotExist(&pidlSelectedFolder);
  420. }
  421. if (_DidZoneCheckPass(m_pidlSource))
  422. {
  423. // Go modal during the UI.
  424. IUnknown_EnableModless(_punkSite, FALSE);
  425. pidlFolder = SHBrowseForFolder(&bi);
  426. IUnknown_EnableModless(_punkSite, TRUE);
  427. if (pidlFolder)
  428. {
  429. hres = _DoDragDrop(pici, pidlFolder);
  430. }
  431. else
  432. hres = E_FAIL;
  433. }
  434. else
  435. hres = E_FAIL;
  436. if (pstrm)
  437. {
  438. if (S_OK == hres)
  439. {
  440. TCHAR szFolder[MAX_PATH];
  441. if (SUCCEEDED(SHGetNameAndFlags(pidlFolder, SHGDN_FORPARSING, szFolder, SIZECHARS(szFolder), NULL))
  442. && !PathIsRemote(szFolder))
  443. {
  444. ULARGE_INTEGER uli;
  445. // rewind the stream to the beginning so that when we
  446. // add a new pidl it does not get appended to the first one
  447. pstrm->Seek(g_li0, STREAM_SEEK_SET, &uli);
  448. ILSaveToStream(pstrm, pidlFolder);
  449. #if DEBUG
  450. // pfortier 3/23/01:
  451. // We've been seeing a problem where the result of this is the My Computer folder.
  452. // Since we can never copy there, that doesn't make any sense.
  453. // ASSERT that this isn't true!
  454. LPITEMIDLIST pidlMyComputer;
  455. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer)))
  456. {
  457. ASSERTMSG(!ILIsEqual(pidlMyComputer, pidlFolder), "SHBrowseForFolder returned My Computer as a copyto destination!");
  458. ILFree(pidlMyComputer);
  459. }
  460. #endif
  461. }
  462. }
  463. pstrm->Release();
  464. }
  465. if (hkey)
  466. {
  467. RegCloseKey(hkey);
  468. }
  469. ILFree(pidlFolder); // ILFree() works for NULL pidls.
  470. ILFree(pidlSelectedFolder); // ILFree() works for NULL pidls.
  471. }
  472. else
  473. hres = E_INVALIDARG;
  474. return hres;
  475. }
  476. HRESULT CCopyMoveToMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pRes, LPSTR pszName, UINT cchMax)
  477. {
  478. return E_NOTIMPL;
  479. }
  480. HRESULT CCopyMoveToMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
  481. {
  482. return HandleMenuMsg2(uMsg, wParam, lParam, NULL);
  483. }
  484. HRESULT CCopyMoveToMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  485. {
  486. HRESULT hr = S_OK;
  487. switch(uMsg)
  488. {
  489. //case WM_INITMENUPOPUP:
  490. // break;
  491. case WM_DRAWITEM:
  492. {
  493. DRAWITEMSTRUCT * pdi = (DRAWITEMSTRUCT *)lParam;
  494. if (pdi->CtlType == ODT_MENU && pdi->itemID == m_idCmdFirst)
  495. {
  496. FileMenu_DrawItem(NULL, pdi);
  497. }
  498. break;
  499. }
  500. case WM_MEASUREITEM:
  501. {
  502. MEASUREITEMSTRUCT *pmi = (MEASUREITEMSTRUCT *)lParam;
  503. if (pmi->CtlType == ODT_MENU && pmi->itemID == m_idCmdFirst)
  504. {
  505. FileMenu_MeasureItem(NULL, pmi);
  506. }
  507. break;
  508. }
  509. default:
  510. hr = E_NOTIMPL;
  511. break;
  512. }
  513. if (plres)
  514. *plres = 0;
  515. return hr;
  516. }
  517. HRESULT CCopyMoveToMenu::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
  518. {
  519. HRESULT hres = S_OK;
  520. if (!pdtobj)
  521. return E_INVALIDARG;
  522. IUnknown_Set((IUnknown **) &m_pdtobj, (IUnknown *) pdtobj);
  523. ASSERT(m_pdtobj);
  524. // (jeffreys) pidlFolder is now NULL when pdtobj is non-NULL
  525. // See comments above the call to HDXA_AppendMenuItems2 in
  526. // defcm.cpp!CDefFolderMenu::QueryContextMenu. Raid #232106
  527. if (!pidlFolder)
  528. {
  529. hres = PidlFromDataObject(m_pdtobj, &m_pidlSource);
  530. if (SUCCEEDED(hres))
  531. {
  532. // Make it the parent pidl of this pidl
  533. if (!ILRemoveLastID(m_pidlSource))
  534. {
  535. hres = E_INVALIDARG;
  536. }
  537. }
  538. }
  539. else if (!Pidl_Set(&m_pidlSource, pidlFolder))
  540. {
  541. hres = E_OUTOFMEMORY;
  542. }
  543. return hres;
  544. }
  545. HRESULT CCopyMoveToMenu::ShouldShow(IShellFolder* psf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem)
  546. {
  547. LPITEMIDLIST pidlNotShown;
  548. HRESULT hr = S_OK;
  549. LPITEMIDLIST pidlFolderActual; // Why is pidlFolder is NULL???
  550. if (SUCCEEDED(SHGetIDListFromUnk(psf, &pidlFolderActual)))
  551. {
  552. LPITEMIDLIST pidlFull = ILCombine(pidlFolderActual, pidlItem);
  553. if (pidlFull)
  554. {
  555. // Filter out control panel and recycle bin.
  556. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlNotShown)))
  557. {
  558. if (ILIsEqual(pidlFull, pidlNotShown))
  559. hr = S_FALSE;
  560. ILFree(pidlNotShown);
  561. }
  562. if ((hr == S_OK) && (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_BITBUCKET, &pidlNotShown))))
  563. {
  564. if (ILIsEqual(pidlFull, pidlNotShown))
  565. hr = S_FALSE;
  566. ILFree(pidlNotShown);
  567. }
  568. ILFree(pidlFull);
  569. }
  570. ILFree(pidlFolderActual);
  571. }
  572. return hr;
  573. }
  574. HRESULT CCopyMoveToMenu::GetEnumFlags(IShellFolder* psf, LPCITEMIDLIST pidlFolder, HWND *phwnd, DWORD *pgrfFlags)
  575. {
  576. // Only want drop targets - this doesn't appear to work.
  577. *pgrfFlags |= SFGAO_DROPTARGET;
  578. return S_OK;
  579. }