Leaked source code of windows server 2003
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.

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