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.

1322 lines
38 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "idldata.h"
  4. #include "datautil.h"
  5. #include "ids.h"
  6. #include <obex.h>
  7. #pragma pack(1)
  8. typedef struct // typedef struct
  9. { // {
  10. // these need to line up -----------------------
  11. WORD cbSize; // WORD cbSize; // Size of entire item ID
  12. WORD wOuter; // WORD wOuter; // Private data owned by the outer folder
  13. WORD cbInner; // WORD cbInner; // Size of delegate's data
  14. // ---------------------------------------------
  15. DWORD dwMagic; // BYTE rgb[1]; // Inner folder's data,
  16. DWORD dwType; // } DELEGATEITEMID;
  17. DWORD dwAttributes;
  18. ULARGE_INTEGER cbTotal;
  19. ULARGE_INTEGER cbFree;
  20. union
  21. {
  22. FILETIME ftModified;
  23. ULARGE_INTEGER ulModified;
  24. };
  25. WCHAR szName[1]; // variable size
  26. } WIRELESSITEM;
  27. #pragma pack()
  28. typedef UNALIGNED WIRELESSITEM * LPWIRELESSITEM;
  29. typedef const UNALIGNED WIRELESSITEM * LPCWIRELESSITEM;
  30. #define WIRELESSITEM_MAGIC 0x98765432
  31. class CWirelessDeviceFolder;
  32. class CWirelessDeviceEnum;
  33. class CWirelessDeviceDropTarget;
  34. class CWirelessDeviceFolder : public IShellFolder2, IPersistFolder2, IShellFolderViewCB, IDelegateFolder
  35. {
  36. public:
  37. CWirelessDeviceFolder();
  38. // IUnknown
  39. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  40. STDMETHOD_(ULONG, AddRef)(void);
  41. STDMETHOD_(ULONG, Release)(void);
  42. // IPersist
  43. STDMETHOD(GetClassID)(CLSID *pClassID);
  44. // IPersistFolder
  45. STDMETHOD(Initialize)(LPCITEMIDLIST pidl);
  46. // IPersistFolder2
  47. STDMETHOD(GetCurFolder)(LPITEMIDLIST *ppidl);
  48. // IShellFolder
  49. STDMETHOD(ParseDisplayName)(HWND hwnd, LPBC pbc, LPOLESTR pszName, ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  50. STDMETHOD(EnumObjects)(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList);
  51. STDMETHOD(BindToObject)(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut);
  52. STDMETHOD(BindToStorage)(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  53. { return BindToObject(pidl, pbc, riid, ppv); };
  54. STDMETHOD(CompareIDs)(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  55. STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, void **ppvOut);
  56. STDMETHOD(GetAttributesOf)(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut);
  57. STDMETHOD(GetUIObjectOf)(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, void **ppvOut);
  58. STDMETHOD(GetDisplayNameOf)(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  59. STDMETHOD(SetNameOf)(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD uFlags, LPITEMIDLIST * ppidlOut);
  60. // IShellFolder2
  61. STDMETHOD(GetDefaultSearchGUID)(GUID *pGuid)
  62. { return E_NOTIMPL; };
  63. STDMETHOD(EnumSearches)(IEnumExtraSearch **ppenum)
  64. { return E_NOTIMPL; };
  65. STDMETHOD(GetDefaultColumn)(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  66. { return E_NOTIMPL; };
  67. STDMETHOD(GetDefaultColumnState)(UINT iColumn, DWORD *pbState)
  68. { return E_NOTIMPL; }
  69. STDMETHOD(GetDetailsEx)(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  70. { return E_NOTIMPL; };
  71. STDMETHOD(GetDetailsOf)(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails);
  72. STDMETHOD(MapColumnToSCID)(UINT iColumn, SHCOLUMNID *pscid)
  73. { return E_NOTIMPL; };
  74. // IShellFolderViewCB
  75. STDMETHOD(MessageSFVCB)(UINT uMsg, WPARAM wParam, LPARAM lParam);
  76. // IDelegateFolder
  77. STDMETHODIMP SetItemAlloc(IMalloc *pmalloc);
  78. private:
  79. ~CWirelessDeviceFolder();
  80. HRESULT _CreateIDList(LPCTSTR pszName, LPCTSTR pszAddress, LPCTSTR pszTransport, WIRELESSITEM **ppmditem);
  81. HRESULT _IDListForDevice(IObexDevice *pdev, LPITEMIDLIST *ppidl);
  82. HRESULT _GetTypeOf(LPCWIRELESSITEM pmdi, LPTSTR pszBuffer, INT cchBuffer);
  83. ULONG _GetAttributesOf(LPCWIRELESSITEM pmdi, ULONG rgfIn);
  84. HRESULT _CreateExtractIcon(LPCWIRELESSITEM pmdi, REFIID riid, void **ppv);
  85. HRESULT _Device(LPCWIRELESSITEM pmdi, REFIID riid, void **ppv);
  86. static HRESULT CALLBACK _ItemsMenuCB(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam);
  87. // folder view callback handlers
  88. HRESULT _OnBackgroundEnum(DWORD pv) { return S_OK; };
  89. HRESULT _OnGetNotify(DWORD pv, LPITEMIDLIST *ppidl, LONG *plEvents);
  90. LPCWIRELESSITEM _IsValid(LPCITEMIDLIST pidl);
  91. DWORD _IsFolder(LPCWIRELESSITEM pmditem);
  92. HRESULT _GetObex(REFIID riid, void **ppv);
  93. HRESULT _GetName(LPCWIRELESSITEM pmdi, LPTSTR pszName, LPTSTR pszAddress, LPTSTR pszTransport);
  94. HRESULT _CreateStgFolder(LPCITEMIDLIST pidl, IStorage *pstg, REFIID riid, void **ppv);
  95. void *_Alloc(SIZE_T cb);
  96. friend CWirelessDeviceEnum;
  97. friend CWirelessDeviceDropTarget;
  98. LONG _cRef;
  99. IMalloc *_pmalloc;
  100. LPITEMIDLIST _pidl;
  101. IObex *_pObex;
  102. };
  103. class CWirelessDeviceEnum : public IEnumIDList
  104. {
  105. public:
  106. CWirelessDeviceEnum(CWirelessDeviceFolder* prf, DWORD grfFlags);
  107. ~CWirelessDeviceEnum();
  108. // IUnknown
  109. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  110. STDMETHODIMP_(ULONG) AddRef();
  111. STDMETHODIMP_(ULONG) Release();
  112. // IEnumIDList
  113. STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
  114. STDMETHODIMP Skip(ULONG celt) { return E_NOTIMPL; };
  115. STDMETHODIMP Reset();
  116. STDMETHODIMP Clone(IEnumIDList **ppenum) { return E_NOTIMPL; };
  117. private:
  118. HRESULT _InitEnum();
  119. void _UnMarshall();
  120. LONG _cRef;
  121. CWirelessDeviceFolder* _pwdf;
  122. DWORD _grfFlags;
  123. IDeviceEnum *_pDeviceEnum;
  124. IObex *_pobex;
  125. IStream *_pstmDevice;
  126. };
  127. class CWirelessDeviceDropTarget : public IDropTarget
  128. {
  129. public:
  130. CWirelessDeviceDropTarget(CWirelessDeviceFolder *pFolder, HWND hwnd);
  131. // IUnknown
  132. STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
  133. STDMETHODIMP_(ULONG) AddRef(void);
  134. STDMETHODIMP_(ULONG) Release(void);
  135. // IDropTarget
  136. STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  137. STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  138. STDMETHODIMP DragLeave();
  139. STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  140. private:
  141. ~CWirelessDeviceDropTarget();
  142. DWORD _GetDropEffect(DWORD *pdwEffect, DWORD grfKeyState);
  143. HRESULT _Transfer(IDataObject *pdtobj, UINT uiCmd);
  144. LONG _cRef;
  145. CWirelessDeviceFolder *_pwdf;
  146. HWND _hwnd; // EVIL: used as a site and UI host
  147. IDataObject *_pdtobj; // used durring DragOver() and DoDrop(), don't use on background thread
  148. UINT _idCmd;
  149. DWORD _grfKeyStateLast; // for previous DragOver/Enter
  150. DWORD _dwEffectLastReturned; // stashed effect that's returned by base class's dragover
  151. DWORD _dwEffectPreferred; // if dwData & DTID_PREFERREDEFFECT
  152. };
  153. CWirelessDeviceFolder::CWirelessDeviceFolder() : _cRef(1)
  154. {
  155. ASSERT(NULL == _pidl);
  156. ASSERT(NULL == _pmalloc);
  157. DllAddRef();
  158. }
  159. CWirelessDeviceFolder::~CWirelessDeviceFolder()
  160. {
  161. ILFree(_pidl);
  162. ATOMICRELEASE(_pmalloc);
  163. if (_pObex)
  164. {
  165. _pObex->Shutdown();
  166. _pObex->Release();
  167. }
  168. DllRelease();
  169. }
  170. HRESULT CWirelessDeviceFolder::QueryInterface(REFIID riid, void **ppv)
  171. {
  172. static const QITAB qit[] =
  173. {
  174. QITABENTMULTI(CWirelessDeviceFolder, IShellFolder, IShellFolder2),
  175. QITABENT (CWirelessDeviceFolder, IShellFolder2),
  176. QITABENTMULTI(CWirelessDeviceFolder, IPersist, IPersistFolder2),
  177. QITABENTMULTI(CWirelessDeviceFolder, IPersistFolder, IPersistFolder2),
  178. QITABENT (CWirelessDeviceFolder, IPersistFolder2),
  179. QITABENT (CWirelessDeviceFolder, IShellFolderViewCB),
  180. QITABENT (CWirelessDeviceFolder, IDelegateFolder),
  181. { 0 },
  182. };
  183. return QISearch(this, qit, riid, ppv);
  184. }
  185. STDMETHODIMP_(ULONG) CWirelessDeviceFolder::AddRef()
  186. {
  187. return InterlockedIncrement(&_cRef);
  188. }
  189. STDMETHODIMP_(ULONG) CWirelessDeviceFolder::Release()
  190. {
  191. if (InterlockedDecrement(&_cRef))
  192. return _cRef;
  193. delete this;
  194. return 0;
  195. }
  196. STDAPI CWirelessDevices_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv)
  197. {
  198. CWirelessDeviceFolder *pwdf = new CWirelessDeviceFolder();
  199. if (!pwdf)
  200. return E_OUTOFMEMORY;
  201. HRESULT hr = pwdf->QueryInterface(riid, ppv);
  202. pwdf->Release();
  203. return hr;
  204. }
  205. const GUID CLSID_Obex = {0x30a7bc00, 0x59b6, 0x40bb, 0xaa, 0x2b, 0x89, 0xeb, 0x49, 0xef, 0x27, 0x4e};
  206. const IID IID_IObex = {0x0C5A5B12, 0x2979, 0x42D1, 0x9E, 0x15, 0xA6, 0x3E, 0x34, 0x38, 0x3B, 0x58};
  207. HRESULT CWirelessDeviceFolder::_GetObex(REFIID riid, void **ppv)
  208. {
  209. HRESULT hr;
  210. if (_pObex)
  211. {
  212. hr = _pObex->QueryInterface(riid, ppv);
  213. }
  214. else
  215. {
  216. hr = CoCreateInstance(CLSID_Obex, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IObex, &_pObex));
  217. if (SUCCEEDED(hr))
  218. {
  219. hr = _pObex->Initialize();
  220. if (SUCCEEDED(hr))
  221. {
  222. hr = _pObex->QueryInterface(riid, ppv);
  223. }
  224. else
  225. {
  226. _pObex->Release();
  227. _pObex = NULL;
  228. }
  229. }
  230. }
  231. return hr;
  232. }
  233. LPCWIRELESSITEM CWirelessDeviceFolder::_IsValid(LPCITEMIDLIST pidl)
  234. {
  235. if (pidl && ((LPCWIRELESSITEM)pidl)->dwMagic == WIRELESSITEM_MAGIC)
  236. return (LPCWIRELESSITEM)pidl;
  237. return NULL;
  238. }
  239. DWORD CWirelessDeviceFolder::_IsFolder(LPCWIRELESSITEM pmditem)
  240. {
  241. return FILE_ATTRIBUTE_DIRECTORY;
  242. }
  243. // helper to support being run as a delegate or a stand alone folder
  244. //
  245. // the cbInner is the size of the data needed by the delegate. we need to compute
  246. // the full size of the pidl for the allocation and init that we the outer folder data
  247. void *CWirelessDeviceFolder::_Alloc(SIZE_T cbInner)
  248. {
  249. DELEGATEITEMID *pidl;
  250. if (_pmalloc)
  251. {
  252. pidl = (DELEGATEITEMID *)_pmalloc->Alloc(cbInner);
  253. }
  254. else
  255. {
  256. SIZE_T cbAlloc =
  257. sizeof(DELEGATEITEMID) - sizeof(pidl->rgb[0]) + // header
  258. cbInner + // inner
  259. sizeof(WORD); // trailing null (pidl terminator)
  260. pidl = (DELEGATEITEMID *)SHAlloc(cbAlloc);
  261. if (pidl)
  262. {
  263. ZeroMemory(pidl, cbAlloc); // make it all empty
  264. pidl->cbSize = (WORD)cbAlloc - sizeof(WORD);
  265. pidl->cbInner = (WORD)cbInner;
  266. }
  267. }
  268. return (void *)pidl;
  269. }
  270. HRESULT CWirelessDeviceFolder::_CreateIDList(LPCTSTR pszName, LPCTSTR pszAddress, LPCTSTR pszTransport, WIRELESSITEM **ppmditem)
  271. {
  272. HRESULT hr;
  273. UINT cbName = lstrlen(pszName) + 1;
  274. UINT cbAddress = lstrlen(pszAddress) + 1;
  275. UINT cbTransport = lstrlen(pszTransport);
  276. UINT cbInner = sizeof(WIRELESSITEM) - (sizeof(DELEGATEITEMID) - 1) +
  277. (sizeof(WCHAR) * (cbName + cbAddress + cbTransport));
  278. *ppmditem = (WIRELESSITEM *)_Alloc(cbInner);
  279. if (*ppmditem)
  280. {
  281. (*ppmditem)->dwMagic = WIRELESSITEM_MAGIC;
  282. (*ppmditem)->dwAttributes = FILE_ATTRIBUTE_DIRECTORY;
  283. StrCpyW((*ppmditem)->szName, pszName);
  284. StrCpyW((*ppmditem)->szName + cbName, pszAddress);
  285. StrCpyW((*ppmditem)->szName + cbName + cbAddress, pszTransport);
  286. hr = S_OK;
  287. }
  288. else
  289. hr = E_OUTOFMEMORY;
  290. return hr;
  291. }
  292. // Creates an item identifier list for the objects in the namespace
  293. HRESULT CWirelessDeviceFolder::_IDListForDevice(IObexDevice *pdev, LPITEMIDLIST *ppidl)
  294. {
  295. IPropertyBag *ppb;
  296. HRESULT hr = pdev->EnumProperties(IID_PPV_ARG(IPropertyBag, &ppb));
  297. if (SUCCEEDED(hr))
  298. {
  299. TCHAR szName[MAX_PATH], szAddress[64], szTransport[64];
  300. SHPropertyBag_ReadStr(ppb, L"Name", szName, ARRAYSIZE(szName));
  301. SHPropertyBag_ReadStr(ppb, L"Address", szAddress, ARRAYSIZE(szAddress));
  302. SHPropertyBag_ReadStr(ppb, L"Transport", szTransport, ARRAYSIZE(szTransport));
  303. WIRELESSITEM *pmditem;
  304. hr = _CreateIDList(szName, szAddress, szTransport, &pmditem);
  305. if (SUCCEEDED(hr))
  306. {
  307. *ppidl = (LPITEMIDLIST)pmditem;
  308. }
  309. ppb->Release();
  310. }
  311. return hr;
  312. }
  313. HRESULT CWirelessDeviceFolder::_GetTypeOf(LPCWIRELESSITEM pmdi, LPTSTR pszBuffer, INT cchBuffer)
  314. {
  315. *pszBuffer = 0; // null out the return buffer
  316. LPCWSTR pwszName;
  317. WSTR_ALIGNED_STACK_COPY(&pwszName, pmdi->szName);
  318. LPTSTR pszExt = PathFindExtension(pwszName);
  319. if (pszExt)
  320. {
  321. StrCpyN(pszBuffer, pszExt, cchBuffer);
  322. }
  323. return S_OK;
  324. }
  325. // IPersist
  326. STDMETHODIMP CWirelessDeviceFolder::GetClassID(CLSID *pClassID)
  327. {
  328. *pClassID = CLSID_WirelessDevices;
  329. return S_OK;
  330. }
  331. // IPersistFolder
  332. STDMETHODIMP CWirelessDeviceFolder::Initialize(LPCITEMIDLIST pidl)
  333. {
  334. ILFree(_pidl);
  335. return SHILClone(pidl, &_pidl);
  336. }
  337. // IPersistFolder2
  338. HRESULT CWirelessDeviceFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  339. {
  340. if (_pidl)
  341. return SHILClone(_pidl, ppidl);
  342. *ppidl = NULL;
  343. return S_FALSE;
  344. }
  345. // IShellFolder(2)
  346. HRESULT CWirelessDeviceFolder::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszName, ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  347. {
  348. HRESULT hr;
  349. if (!pszName || !ppidl)
  350. return E_INVALIDARG;
  351. *ppidl = NULL;
  352. #if 1
  353. hr = E_NOTIMPL;
  354. #else
  355. TCHAR szName[MAX_PATH];
  356. hr = _NextSegment((LPCWSTR*)&pszName, szName, ARRAYSIZE(szName), TRUE);
  357. if (SUCCEEDED(hr))
  358. {
  359. hr = _IDListForDevice(szName, ppidl);
  360. if (SUCCEEDED(hr) && pszName)
  361. {
  362. IShellFolder *psf;
  363. hr = BindToObject(*ppidl, pbc, IID_PPV_ARG(IShellFolder, &psf));
  364. if (SUCCEEDED(hr))
  365. {
  366. ULONG chEaten;
  367. LPITEMIDLIST pidlNext;
  368. hr = psf->ParseDisplayName(hwnd, pbc, pszName, &chEaten, &pidlNext, pdwAttributes);
  369. if (SUCCEEDED(hr))
  370. hr = SHILAppend(pidlNext, ppidl);
  371. psf->Release();
  372. }
  373. }
  374. else if (SUCCEEDED(hr) && pdwAttributes && *pdwAttributes)
  375. {
  376. GetAttributesOf(1, (LPCITEMIDLIST *)ppidl, pdwAttributes);
  377. }
  378. }
  379. #endif
  380. // clean up if the parse failed.
  381. if (FAILED(hr))
  382. {
  383. ILFree(*ppidl);
  384. *ppidl = NULL;
  385. }
  386. return hr;
  387. }
  388. HRESULT CWirelessDeviceFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenum)
  389. {
  390. HRESULT hr;
  391. CWirelessDeviceEnum *penum = new CWirelessDeviceEnum(this, grfFlags);
  392. if (penum)
  393. {
  394. hr = penum->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenum));
  395. penum->Release();
  396. }
  397. else
  398. {
  399. hr = E_OUTOFMEMORY;
  400. *ppenum = NULL;
  401. }
  402. return hr;
  403. }
  404. HRESULT CWirelessDeviceFolder::_GetName(LPCWIRELESSITEM pmdi, LPTSTR pszName, LPTSTR pszAddress, LPTSTR pszTransport)
  405. {
  406. LPCWSTR psz = pmdi->szName;
  407. UINT cch = lstrlen(psz) + 1;
  408. if (pszName)
  409. StrCpy(pszName, psz);
  410. psz += cch;
  411. cch = lstrlen(psz) + 1;
  412. if (pszAddress)
  413. StrCpy(pszAddress, psz);
  414. psz += cch;
  415. cch = lstrlen(psz) + 1;
  416. if (pszTransport)
  417. StrCpy(pszTransport, psz);
  418. return S_OK;
  419. }
  420. HRESULT CWirelessDeviceFolder::_Device(LPCWIRELESSITEM pmdi, REFIID riid, void **ppv)
  421. {
  422. TCHAR szName[MAX_PATH], szAddress[64], szTransport[64];
  423. HRESULT hr = _GetName(pmdi, szName, szAddress, szTransport);
  424. if (SUCCEEDED(hr))
  425. {
  426. IPropertyBag *ppb;
  427. hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &ppb));
  428. if (SUCCEEDED(hr))
  429. {
  430. // store the class ID for the CD mastering folder
  431. SHPropertyBag_WriteStr(ppb, L"Name", szName);
  432. SHPropertyBag_WriteStr(ppb, L"Address", szAddress);
  433. SHPropertyBag_WriteStr(ppb, L"Transport", szTransport);
  434. IObex *pobex;
  435. hr = _GetObex(IID_PPV_ARG(IObex, &pobex));
  436. if (SUCCEEDED(hr))
  437. {
  438. IObexDevice *pdev;
  439. hr = pobex->BindToDevice(ppb, &pdev);
  440. if (SUCCEEDED(hr))
  441. {
  442. if (riid == IID_IStorage)
  443. hr = pdev->BindToStorage(OBEX_DEVICE_CAP_PUSH, (IStorage **)ppv);
  444. else
  445. hr = pdev->QueryInterface(riid, ppv);
  446. pdev->Release();
  447. }
  448. pobex->Release();
  449. }
  450. ppb->Release();
  451. }
  452. }
  453. return hr;
  454. }
  455. HRESULT CWirelessDeviceFolder::_CreateStgFolder(LPCITEMIDLIST pidl, IStorage *pstg, REFIID riid, void **ppv)
  456. {
  457. *ppv = NULL;
  458. IPersistStorage *ppstg;
  459. HRESULT hr = CoCreateInstance(CLSID_StgFolder, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPersistStorage, &ppstg));
  460. if (SUCCEEDED(hr))
  461. {
  462. hr = ppstg->Load(pstg);
  463. if (SUCCEEDED(hr))
  464. {
  465. IPersistFolder *ppf;
  466. hr = ppstg->QueryInterface(IID_PPV_ARG(IPersistFolder, &ppf));
  467. if (SUCCEEDED(hr))
  468. {
  469. hr = ppf->Initialize(pidl);
  470. if (SUCCEEDED(hr))
  471. hr = ppf->QueryInterface(riid, ppv);
  472. ppf->Release();
  473. }
  474. }
  475. ppstg->Release();
  476. }
  477. return hr;
  478. }
  479. HRESULT CWirelessDeviceFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  480. {
  481. *ppv = NULL;
  482. HRESULT hr = E_NOINTERFACE;
  483. LPCWIRELESSITEM pmdi = _IsValid(pidl);
  484. if (pmdi && _IsFolder(pmdi))
  485. {
  486. if (IID_IShellFolder == riid ||
  487. IID_IShellFolder2 == riid)
  488. {
  489. IStorage *pstg;
  490. hr = _Device(pmdi, IID_PPV_ARG(IStorage, &pstg));
  491. if (SUCCEEDED(hr))
  492. {
  493. LPCITEMIDLIST pidlNext = _ILNext(pidl);
  494. LPITEMIDLIST pidlSubFolder = ILCombineParentAndFirst(_pidl, pidl, pidlNext);
  495. if (pidlSubFolder)
  496. {
  497. IShellFolder *psf;
  498. hr = _CreateStgFolder(pidlSubFolder, pstg, IID_PPV_ARG(IShellFolder, &psf));
  499. if (SUCCEEDED(hr))
  500. {
  501. // if there's nothing left in the pidl, get the interface on this one.
  502. if (ILIsEmpty(pidlNext))
  503. hr = psf->QueryInterface(riid, ppv);
  504. else
  505. {
  506. // otherwise, hand the rest of it off to the new shellfolder.
  507. hr = psf->BindToObject(pidlNext, pbc, riid, ppv);
  508. }
  509. psf->Release();
  510. }
  511. ILFree(pidlSubFolder);
  512. }
  513. else
  514. hr = E_OUTOFMEMORY;
  515. pstg->Release();
  516. }
  517. }
  518. }
  519. else
  520. hr = E_FAIL;
  521. ASSERT((SUCCEEDED(hr) && *ppv) || (FAILED(hr) && (NULL == *ppv))); // Assert hr is consistent w/out param.
  522. return hr;
  523. }
  524. enum
  525. {
  526. DEV_COL_NAME = 0,
  527. DEV_COL_SIZE,
  528. DEV_COL_TYPE,
  529. DEV_COL_MODIFIED,
  530. };
  531. HRESULT CWirelessDeviceFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  532. {
  533. LPCWIRELESSITEM pmdi1 = _IsValid(pidl1);
  534. LPCWIRELESSITEM pmdi2 = _IsValid(pidl2);
  535. int nCmp = 0;
  536. if (!pmdi1 || !pmdi2)
  537. return E_INVALIDARG;
  538. // folders always sort to the top of the list, if either of these items
  539. // are folders then compare on the folderness
  540. if (_IsFolder(pmdi1) || _IsFolder(pmdi2))
  541. {
  542. if (_IsFolder(pmdi1) && !_IsFolder(pmdi2))
  543. nCmp = -1;
  544. else if (!_IsFolder(pmdi1) && _IsFolder(pmdi2))
  545. nCmp = 1;
  546. }
  547. // if they match (or are not folders, then lets compare based on the column ID.
  548. if (nCmp == 0)
  549. {
  550. switch (lParam & SHCIDS_COLUMNMASK)
  551. {
  552. case DEV_COL_NAME: // caught later on
  553. break;
  554. case DEV_COL_SIZE:
  555. {
  556. if (pmdi1->cbTotal.QuadPart < pmdi2->cbTotal.QuadPart)
  557. nCmp = -1;
  558. else if (pmdi1->cbTotal.QuadPart > pmdi2->cbTotal.QuadPart)
  559. nCmp = 1;
  560. break;
  561. }
  562. case DEV_COL_TYPE:
  563. {
  564. TCHAR szType1[MAX_PATH], szType2[MAX_PATH];
  565. _GetTypeOf(pmdi1, szType1, ARRAYSIZE(szType1));
  566. _GetTypeOf(pmdi2, szType2, ARRAYSIZE(szType2));
  567. nCmp = StrCmpI(szType1, szType2);
  568. break;
  569. }
  570. case DEV_COL_MODIFIED:
  571. {
  572. if (pmdi1->ulModified.QuadPart < pmdi2->ulModified.QuadPart)
  573. nCmp = -1;
  574. else if (pmdi1->ulModified.QuadPart > pmdi2->ulModified.QuadPart)
  575. nCmp = 1;
  576. break;
  577. }
  578. }
  579. if (nCmp == 0)
  580. {
  581. nCmp = ualstrcmpi(pmdi1->szName, pmdi2->szName);
  582. }
  583. }
  584. return ResultFromShort(nCmp);
  585. }
  586. HRESULT CWirelessDeviceFolder::_OnGetNotify(DWORD pv, LPITEMIDLIST *ppidl, LONG *plEvents)
  587. {
  588. *ppidl = _pidl;
  589. *plEvents = SHCNE_RENAMEITEM | SHCNE_RENAMEFOLDER | \
  590. SHCNE_CREATE | SHCNE_DELETE | SHCNE_UPDATEDIR | SHCNE_UPDATEITEM | \
  591. SHCNE_MKDIR | SHCNE_RMDIR;
  592. return S_OK;
  593. }
  594. STDMETHODIMP CWirelessDeviceFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
  595. {
  596. HRESULT hr = E_FAIL;
  597. switch (uMsg)
  598. {
  599. HANDLE_MSG(0, SFVM_BACKGROUNDENUM, _OnBackgroundEnum);
  600. HANDLE_MSG(0, SFVM_GETNOTIFY, _OnGetNotify);
  601. }
  602. return hr;
  603. }
  604. HRESULT CWirelessDeviceFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  605. {
  606. HRESULT hr = E_NOINTERFACE;
  607. *ppv = NULL;
  608. if (IsEqualIID(riid, IID_IShellView))
  609. {
  610. SFV_CREATE sSFV = { 0 };
  611. sSFV.cbSize = sizeof(sSFV);
  612. sSFV.psfvcb = this;
  613. sSFV.pshf = this;
  614. hr = SHCreateShellFolderView(&sSFV, (IShellView**)ppv);
  615. }
  616. else if (IsEqualIID(riid, IID_IContextMenu))
  617. {
  618. HKEY hkNoFiles = NULL;
  619. RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Directory\\Background"), &hkNoFiles);
  620. hr = CDefFolderMenu_Create2(_pidl, hwnd, 0, NULL, this, NULL,
  621. 1, &hkNoFiles, (IContextMenu **)ppv);
  622. if (hkNoFiles)
  623. RegCloseKey(hkNoFiles);
  624. }
  625. else if (IsEqualIID(riid, IID_IDropTarget))
  626. {
  627. CWirelessDeviceDropTarget *psdt = new CWirelessDeviceDropTarget(this, hwnd);
  628. if (psdt)
  629. {
  630. hr = psdt->QueryInterface(riid, ppv);
  631. psdt->Release();
  632. }
  633. else
  634. hr = E_OUTOFMEMORY;
  635. }
  636. return hr;
  637. }
  638. ULONG CWirelessDeviceFolder::_GetAttributesOf(LPCWIRELESSITEM pmdi, ULONG rgfIn)
  639. {
  640. return rgfIn & (SFGAO_FOLDER | SFGAO_CANLINK | SFGAO_CANCOPY | SFGAO_HASSUBFOLDER | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET);
  641. }
  642. HRESULT CWirelessDeviceFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *prgfInOut)
  643. {
  644. UINT rgfOut = *prgfInOut;
  645. // return attributes of the namespace root?
  646. if (!cidl || !apidl)
  647. {
  648. rgfOut &= SFGAO_FOLDER |
  649. SFGAO_LINK | SFGAO_DROPTARGET |
  650. SFGAO_CANRENAME | SFGAO_CANDELETE |
  651. SFGAO_CANLINK | SFGAO_CANCOPY |
  652. SFGAO_CANMOVE | SFGAO_HASSUBFOLDER;
  653. }
  654. else
  655. {
  656. for (UINT i = 0; i < cidl; i++)
  657. rgfOut &= _GetAttributesOf(_IsValid(apidl[i]), *prgfInOut);
  658. }
  659. *prgfInOut = rgfOut;
  660. return S_OK;
  661. }
  662. HRESULT CALLBACK CWirelessDeviceFolder::_ItemsMenuCB(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
  663. {
  664. HRESULT hr = S_OK;
  665. switch (uMsg)
  666. {
  667. case DFM_MERGECONTEXTMENU:
  668. break;
  669. case DFM_INVOKECOMMANDEX:
  670. {
  671. DFMICS *pdfmics = (DFMICS *)lParam;
  672. switch (wParam)
  673. {
  674. case DFM_CMD_DELETE:
  675. // hr = StgDeleteUsingDataObject(hwnd, pdfmics->fMask, pdtobj);
  676. break;
  677. case DFM_CMD_PROPERTIES:
  678. break;
  679. default:
  680. // This is common menu items, use the default code.
  681. hr = S_FALSE;
  682. break;
  683. }
  684. break;
  685. }
  686. default:
  687. hr = E_NOTIMPL;
  688. break;
  689. }
  690. return hr;
  691. }
  692. HRESULT CWirelessDeviceFolder::_CreateExtractIcon(LPCWIRELESSITEM pmdi, REFIID riid, void **ppv)
  693. {
  694. HRESULT hr = E_OUTOFMEMORY;
  695. if (_IsFolder(pmdi))
  696. {
  697. UINT iIcon = II_FOLDER;
  698. UINT iIconOpen = II_FOLDEROPEN;
  699. TCHAR szModule[MAX_PATH];
  700. GetModuleFileName(g_hinst, szModule, ARRAYSIZE(szModule));
  701. hr = SHCreateDefExtIcon(szModule, iIcon, iIconOpen, GIL_PERCLASS, -1, riid, ppv);
  702. }
  703. return hr;
  704. }
  705. HRESULT CWirelessDeviceFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  706. REFIID riid, UINT *prgfInOut, void **ppv)
  707. {
  708. HRESULT hr = E_INVALIDARG;
  709. LPCWIRELESSITEM pmdi = cidl ? _IsValid(apidl[0]) : NULL;
  710. if (pmdi &&
  711. (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)))
  712. {
  713. WCHAR szName[MAX_PATH];
  714. _GetName(pmdi, szName, NULL, NULL);
  715. hr = SHCreateFileExtractIconW(szName, _IsFolder(pmdi), riid, ppv);
  716. }
  717. else if (IsEqualIID(riid, IID_IDataObject) && cidl)
  718. {
  719. hr = CIDLData_CreateInstance(_pidl, cidl, apidl, NULL, (IDataObject **)ppv);
  720. }
  721. #if 0
  722. else if (IsEqualIID(riid, IID_IContextMenu) && pmdi)
  723. {
  724. // get the association for these files and lets attempt to
  725. // build the context menu for the selection.
  726. IQueryAssociations *pqa;
  727. hr = GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)&pmdi, IID_PPV_ARG_NULL(IQueryAssociations, &pqa));
  728. if (SUCCEEDED(hr))
  729. {
  730. HKEY ahk[3];
  731. // this is broken for docfiles (shell\ext\stgfldr's keys work though)
  732. // maybe because GetClassFile punts when it's not fs?
  733. DWORD cKeys = SHGetAssocKeys(pqa, ahk, ARRAYSIZE(ahk));
  734. hr = CDefFolderMenu_Create2(_pidl, hwnd, cidl, apidl,
  735. this, _ItemsMenuCB, cKeys, ahk,
  736. (IContextMenu **)ppv);
  737. SHRegCloseKeys(ahk, cKeys);
  738. pqa->Release();
  739. }
  740. }
  741. else if (IsEqualIID(riid, IID_IQueryAssociations) && pmdi)
  742. {
  743. // need to create a valid Assoc obj here
  744. }
  745. #endif
  746. else if (IsEqualIID(riid, IID_IDropTarget) && pmdi)
  747. {
  748. // If a directory is selected in the view, the drop is going to a folder,
  749. // so we need to bind to that folder and ask it to create a drop target
  750. if (_IsFolder(pmdi))
  751. {
  752. IShellFolder *psf;
  753. hr = BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psf));
  754. if (SUCCEEDED(hr))
  755. {
  756. hr = psf->CreateViewObject(hwnd, IID_IDropTarget, ppv);
  757. psf->Release();
  758. }
  759. }
  760. else
  761. {
  762. hr = CreateViewObject(hwnd, IID_IDropTarget, ppv);
  763. }
  764. }
  765. return hr;
  766. }
  767. HRESULT CWirelessDeviceFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, STRRET *pStrRet)
  768. {
  769. HRESULT hr;
  770. LPCWIRELESSITEM pmdi = _IsValid(pidl);
  771. if (pmdi)
  772. {
  773. WCHAR szName[MAX_PATH];
  774. _GetName(pmdi, szName, NULL, NULL);
  775. if (dwFlags & SHGDN_FORPARSING)
  776. {
  777. if (dwFlags & SHGDN_INFOLDER)
  778. {
  779. hr = StringToStrRetW(szName, pStrRet); // relative name
  780. }
  781. else
  782. {
  783. TCHAR szTemp[MAX_PATH];
  784. SHGetNameAndFlags(_pidl, dwFlags, szTemp, ARRAYSIZE(szTemp), NULL);
  785. PathAppend(szTemp, szName);
  786. hr = StringToStrRetW(szTemp, pStrRet);
  787. }
  788. }
  789. else
  790. {
  791. hr = StringToStrRetW(szName, pStrRet);
  792. }
  793. }
  794. else
  795. hr = E_INVALIDARG;
  796. return hr;
  797. }
  798. HRESULT CWirelessDeviceFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD dwFlags, LPITEMIDLIST *ppidlOut)
  799. {
  800. return E_NOTIMPL;
  801. }
  802. static const struct
  803. {
  804. UINT iTitle;
  805. UINT cchCol;
  806. UINT iFmt;
  807. }
  808. g_aMediaDeviceColumns[] =
  809. {
  810. {IDS_NAME_COL, 20, LVCFMT_LEFT},
  811. {IDS_SIZE_COL, 10, LVCFMT_RIGHT},
  812. {IDS_TYPE_COL, 20, LVCFMT_LEFT},
  813. {IDS_MODIFIED_COL, 20, LVCFMT_LEFT},
  814. };
  815. HRESULT CWirelessDeviceFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetail)
  816. {
  817. HRESULT hr = S_OK;
  818. TCHAR szTemp[MAX_PATH];
  819. // is this a valid column?
  820. if (iColumn >= ARRAYSIZE(g_aMediaDeviceColumns))
  821. return E_NOTIMPL;
  822. pDetail->str.uType = STRRET_CSTR;
  823. pDetail->str.cStr[0] = 0;
  824. if (NULL == pidl)
  825. {
  826. pDetail->fmt = g_aMediaDeviceColumns[iColumn].iFmt;
  827. pDetail->cxChar = g_aMediaDeviceColumns[iColumn].cchCol;
  828. LoadString(g_hinst, g_aMediaDeviceColumns[iColumn].iTitle, szTemp, ARRAYSIZE(szTemp));
  829. hr = StringToStrRetW(szTemp, &(pDetail->str));
  830. }
  831. else
  832. {
  833. LPCWIRELESSITEM pmdi = _IsValid(pidl);
  834. if (pmdi)
  835. {
  836. // return the property to the caller that is being requested, this is based on the
  837. // list of columns we gave out when the view was created.
  838. WCHAR szName[MAX_PATH];
  839. _GetName(pmdi, szName, NULL, NULL);
  840. switch (iColumn)
  841. {
  842. case DEV_COL_NAME:
  843. hr = StringToStrRetW(szName, &(pDetail->str));
  844. break;
  845. case DEV_COL_SIZE:
  846. if (!_IsFolder(pmdi))
  847. {
  848. ULARGE_INTEGER ullSize = pmdi->cbTotal;
  849. StrFormatKBSize(ullSize.QuadPart, szTemp, ARRAYSIZE(szTemp));
  850. hr = StringToStrRetW(szTemp, &(pDetail->str));
  851. }
  852. break;
  853. case DEV_COL_TYPE:
  854. {
  855. SHFILEINFO sfi = { 0 };
  856. if (SHGetFileInfo(szName, _IsFolder(pmdi), &sfi, sizeof(sfi), SHGFI_USEFILEATTRIBUTES|SHGFI_TYPENAME))
  857. hr = StringToStrRetW(sfi.szTypeName, &(pDetail->str));
  858. break;
  859. }
  860. case DEV_COL_MODIFIED:
  861. SHFormatDateTime(&pmdi->ftModified, NULL, szTemp, ARRAYSIZE(szTemp));
  862. hr = StringToStrRetW(szTemp, &(pDetail->str));
  863. break;
  864. }
  865. }
  866. }
  867. return hr;
  868. }
  869. // IDelegateFolder
  870. HRESULT CWirelessDeviceFolder::SetItemAlloc(IMalloc *pmalloc)
  871. {
  872. IUnknown_Set((IUnknown**)&_pmalloc, pmalloc);
  873. return S_OK;
  874. }
  875. CWirelessDeviceEnum::CWirelessDeviceEnum(CWirelessDeviceFolder *pmdf, DWORD grfFlags) : _cRef(1), _grfFlags(grfFlags)
  876. {
  877. _pwdf = pmdf;
  878. _pwdf->AddRef();
  879. IObex *pobex;
  880. if (SUCCEEDED(_pwdf->_GetObex(IID_PPV_ARG(IObex, &pobex))))
  881. {
  882. CoMarshalInterThreadInterfaceInStream(IID_IObex, pobex, &_pstmDevice);
  883. pobex->Release();
  884. }
  885. DllAddRef();
  886. }
  887. CWirelessDeviceEnum::~CWirelessDeviceEnum()
  888. {
  889. ATOMICRELEASE(_pobex);
  890. ATOMICRELEASE(_pDeviceEnum);
  891. ATOMICRELEASE(_pstmDevice);
  892. _pwdf->Release();
  893. DllRelease();
  894. }
  895. STDMETHODIMP_(ULONG) CWirelessDeviceEnum::AddRef()
  896. {
  897. return InterlockedIncrement(&_cRef);
  898. }
  899. STDMETHODIMP_(ULONG) CWirelessDeviceEnum::Release()
  900. {
  901. if (InterlockedDecrement(&_cRef))
  902. return _cRef;
  903. delete this;
  904. return 0;
  905. }
  906. HRESULT CWirelessDeviceEnum::QueryInterface(REFIID riid, void **ppv)
  907. {
  908. static const QITAB qit[] =
  909. {
  910. QITABENT(CWirelessDeviceEnum, IEnumIDList), // IID_IEnumIDList
  911. { 0 },
  912. };
  913. return QISearch(this, qit, riid, ppv);
  914. }
  915. void CWirelessDeviceEnum::_UnMarshall()
  916. {
  917. if (_pstmDevice)
  918. CoGetInterfaceAndReleaseStream(_pstmDevice, IID_PPV_ARG(IObex, &_pobex));
  919. _pstmDevice = NULL;
  920. }
  921. HRESULT CWirelessDeviceEnum::_InitEnum()
  922. {
  923. HRESULT hr = S_OK;
  924. _UnMarshall();
  925. if (NULL == _pDeviceEnum)
  926. {
  927. hr = _pobex ? _pobex->EnumDevices(&_pDeviceEnum, CLSID_NULL) : E_FAIL;
  928. }
  929. return hr;
  930. }
  931. HRESULT CWirelessDeviceEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
  932. {
  933. HRESULT hr = _InitEnum();
  934. if (SUCCEEDED(hr))
  935. {
  936. for (UINT cItems = 0; (cItems != celt) && (S_OK == hr); )
  937. {
  938. LPITEMIDLIST pidl;
  939. ULONG ulFetched;
  940. IObexDevice *pdev;
  941. hr = _pDeviceEnum->Next(1, &pdev, &ulFetched);
  942. if (S_OK == hr && ulFetched)
  943. {
  944. hr = _pwdf->_IDListForDevice(pdev, &pidl);
  945. pdev->Release();
  946. }
  947. else
  948. hr = S_FALSE;
  949. if (S_OK == hr)
  950. {
  951. if (!(_grfFlags & SHCONTF_FOLDERS))
  952. {
  953. ILFree(pidl);
  954. pidl = NULL;
  955. continue;
  956. }
  957. rgelt[cItems++] = pidl; // return the idlist
  958. }
  959. }
  960. if (pceltFetched)
  961. *pceltFetched = cItems;
  962. }
  963. return hr;
  964. }
  965. STDMETHODIMP CWirelessDeviceEnum::Reset()
  966. {
  967. ATOMICRELEASE(_pDeviceEnum);
  968. return S_OK;
  969. }
  970. CWirelessDeviceDropTarget::CWirelessDeviceDropTarget(CWirelessDeviceFolder *pmdf, HWND hwnd) :
  971. _cRef(1), _pwdf(pmdf), _hwnd(hwnd), _grfKeyStateLast(-1)
  972. {
  973. _pwdf->AddRef();
  974. DllAddRef();
  975. }
  976. CWirelessDeviceDropTarget::~CWirelessDeviceDropTarget()
  977. {
  978. DragLeave();
  979. ATOMICRELEASE(_pwdf);
  980. DllRelease();
  981. }
  982. STDMETHODIMP_(ULONG) CWirelessDeviceDropTarget::AddRef()
  983. {
  984. return InterlockedIncrement(&_cRef);
  985. }
  986. STDMETHODIMP_(ULONG) CWirelessDeviceDropTarget::Release()
  987. {
  988. if (InterlockedDecrement(&_cRef))
  989. return _cRef;
  990. delete this;
  991. return 0;
  992. }
  993. HRESULT CWirelessDeviceDropTarget::QueryInterface(REFIID riid, void** ppv)
  994. {
  995. static const QITAB qit[] = {
  996. QITABENT(CWirelessDeviceDropTarget, IDropTarget),
  997. { 0 },
  998. };
  999. return QISearch(this, qit, riid, ppv);
  1000. }
  1001. HRESULT CWirelessDeviceDropTarget::_Transfer(IDataObject *pdtobj, UINT uiCmd)
  1002. {
  1003. return E_FAIL;
  1004. }
  1005. DWORD CWirelessDeviceDropTarget::_GetDropEffect(DWORD *pdwEffect, DWORD grfKeyState)
  1006. {
  1007. DWORD dwEffectReturned = DROPEFFECT_NONE;
  1008. switch (grfKeyState & (MK_CONTROL | MK_SHIFT | MK_ALT))
  1009. {
  1010. case MK_CONTROL: dwEffectReturned = DROPEFFECT_COPY; break;
  1011. case MK_SHIFT: dwEffectReturned = DROPEFFECT_MOVE; break;
  1012. case MK_SHIFT | MK_CONTROL: dwEffectReturned = DROPEFFECT_LINK; break;
  1013. case MK_ALT: dwEffectReturned = DROPEFFECT_LINK; break;
  1014. default:
  1015. {
  1016. // no modifier keys:
  1017. // if the data object contains a preferred drop effect, try to use it
  1018. DWORD dwPreferred = DataObj_GetDWORD(_pdtobj, g_cfPreferredDropEffect, DROPEFFECT_NONE) & *pdwEffect;
  1019. if (dwPreferred)
  1020. {
  1021. if (dwPreferred & DROPEFFECT_MOVE)
  1022. {
  1023. dwEffectReturned = DROPEFFECT_MOVE;
  1024. }
  1025. else if (dwPreferred & DROPEFFECT_COPY)
  1026. {
  1027. dwEffectReturned = DROPEFFECT_COPY;
  1028. }
  1029. else if (dwPreferred & DROPEFFECT_LINK)
  1030. {
  1031. dwEffectReturned = DROPEFFECT_LINK;
  1032. }
  1033. }
  1034. else
  1035. {
  1036. dwEffectReturned = DROPEFFECT_COPY;
  1037. }
  1038. }
  1039. break;
  1040. }
  1041. return dwEffectReturned;
  1042. }
  1043. STDMETHODIMP CWirelessDeviceDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  1044. {
  1045. IUnknown_Set((IUnknown **)&_pdtobj, pdtobj);
  1046. _grfKeyStateLast = grfKeyState;
  1047. if (pdwEffect)
  1048. *pdwEffect = _dwEffectLastReturned = _GetDropEffect(pdwEffect, grfKeyState);
  1049. return S_OK;
  1050. }
  1051. STDMETHODIMP CWirelessDeviceDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  1052. {
  1053. // has the key state changed? if not then lets return the previously cached
  1054. // version, otherwise recompute.
  1055. if (_grfKeyStateLast == grfKeyState)
  1056. {
  1057. if (*pdwEffect)
  1058. *pdwEffect = _dwEffectLastReturned;
  1059. }
  1060. else if (*pdwEffect)
  1061. {
  1062. *pdwEffect = _GetDropEffect(pdwEffect, grfKeyState);
  1063. }
  1064. _dwEffectLastReturned = *pdwEffect;
  1065. _grfKeyStateLast = grfKeyState;
  1066. return S_OK;
  1067. }
  1068. STDMETHODIMP CWirelessDeviceDropTarget::DragLeave()
  1069. {
  1070. ATOMICRELEASE(_pdtobj);
  1071. return S_OK;
  1072. }
  1073. STDMETHODIMP CWirelessDeviceDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  1074. {
  1075. *pdwEffect = DROPEFFECT_NONE; // incase of failure
  1076. // determine the type of operation to performed, if the right button is down
  1077. // then lets display the menu, otherwise base it on the drop effect
  1078. UINT idCmd = 0; // Choice from drop popup menu
  1079. if (!(_grfKeyStateLast & MK_LBUTTON))
  1080. {
  1081. HMENU hMenu = SHLoadPopupMenu(g_hinst, POPUP_NONDEFAULTDD);
  1082. if (!hMenu)
  1083. {
  1084. DragLeave();
  1085. return E_FAIL;
  1086. }
  1087. SetMenuDefaultItem(hMenu, POPUP_NONDEFAULTDD, FALSE);
  1088. idCmd = TrackPopupMenu(hMenu,
  1089. TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTALIGN,
  1090. pt.x, pt.y, 0, _hwnd, NULL);
  1091. DestroyMenu(hMenu);
  1092. }
  1093. else
  1094. {
  1095. switch (_GetDropEffect(pdwEffect, grfKeyState))
  1096. {
  1097. case DROPEFFECT_COPY: idCmd = DDIDM_COPY; break;
  1098. case DROPEFFECT_MOVE: idCmd = DDIDM_MOVE; break;
  1099. case DROPEFFECT_LINK: idCmd = DDIDM_LINK; break;
  1100. }
  1101. }
  1102. // now perform the operation, based on the command ID we have.
  1103. HRESULT hr = E_FAIL;
  1104. switch (idCmd)
  1105. {
  1106. case DDIDM_COPY:
  1107. case DDIDM_MOVE:
  1108. hr = _Transfer(pdtobj, idCmd);
  1109. if (SUCCEEDED(hr))
  1110. *pdwEffect = (idCmd == DDIDM_COPY) ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
  1111. else
  1112. *pdwEffect = 0;
  1113. break;
  1114. case DDIDM_LINK:
  1115. {
  1116. WCHAR wzPath[MAX_PATH];
  1117. SHGetNameAndFlags(_pwdf->_pidl, SHGDN_FORPARSING, wzPath, ARRAYSIZE(wzPath), NULL);
  1118. hr = SHCreateLinks(_hwnd, wzPath, pdtobj, 0, NULL);
  1119. break;
  1120. }
  1121. }
  1122. // success so lets populate the new changes to the effect
  1123. if (SUCCEEDED(hr) && *pdwEffect)
  1124. {
  1125. DataObj_SetDWORD(pdtobj, g_cfLogicalPerformedDropEffect, *pdwEffect);
  1126. DataObj_SetDWORD(pdtobj, g_cfPerformedDropEffect, *pdwEffect);
  1127. }
  1128. DragLeave();
  1129. return hr;
  1130. }