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.

468 lines
11 KiB

  1. //
  2. // DropTarget.cpp
  3. //
  4. #include "pch.h"
  5. #pragma hdrstop
  6. #include "foldinc.h" // Standard shell\folder includes
  7. #include "droptarget.h"
  8. CDropTarget::CDropTarget(IShellFolder *psfParent)
  9. {
  10. m_uiRefCount = 1;
  11. m_psfParent = psfParent;
  12. if(m_psfParent)
  13. {
  14. m_psfParent->AddRef();
  15. }
  16. m_bAcceptFmt = FALSE;
  17. // TODO : Register your own clipboard format here
  18. m_cfPrivatePidlData = static_cast<CLIPFORMAT>(RegisterClipboardFormat(CFSTR_SHELLIDLIST));
  19. m_cfPrivateFileData = CF_HDROP;
  20. }
  21. CDropTarget::~CDropTarget()
  22. {
  23. if(m_psfParent)
  24. {
  25. m_psfParent->Release();
  26. }
  27. }
  28. ///////////////////////////////////////////////////////////
  29. // IUnknown Implementation
  30. //
  31. STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID *ppReturn)
  32. {
  33. *ppReturn = NULL;
  34. //IUnknown
  35. if(IsEqualIID(riid, IID_IUnknown))
  36. {
  37. *ppReturn = this;
  38. }
  39. //IDropTarget
  40. else if(IsEqualIID(riid, IID_IDropTarget))
  41. {
  42. *ppReturn = (IDropTarget*)this;
  43. }
  44. if(*ppReturn)
  45. {
  46. (*(LPUNKNOWN*)ppReturn)->AddRef();
  47. return S_OK;
  48. }
  49. return E_NOINTERFACE;
  50. }
  51. STDMETHODIMP_(DWORD) CDropTarget::AddRef(VOID)
  52. {
  53. return ++m_uiRefCount;
  54. }
  55. STDMETHODIMP_(DWORD) CDropTarget::Release(VOID)
  56. {
  57. if(--m_uiRefCount == 0)
  58. {
  59. delete this;
  60. return 0;
  61. }
  62. return m_uiRefCount;
  63. }
  64. ///////////////////////////////////////////////////////////
  65. // IDropTarget implemenatation
  66. //
  67. STDMETHODIMP CDropTarget::DragEnter( LPDATAOBJECT pDataObj,
  68. DWORD dwKeyState,
  69. POINTL pt,
  70. LPDWORD pdwEffect)
  71. {
  72. // TODO : Handle DragEnter here
  73. FORMATETC fmtetc;
  74. fmtetc.cfFormat = m_cfPrivatePidlData;
  75. fmtetc.ptd = NULL;
  76. fmtetc.dwAspect = DVASPECT_CONTENT;
  77. fmtetc.lindex = -1;
  78. fmtetc.tymed = TYMED_HGLOBAL;
  79. // QueryGetData for pDataObject for our format
  80. m_bAcceptFmt = (S_OK == pDataObj->QueryGetData(&fmtetc)) ? TRUE : FALSE;
  81. if (m_bAcceptFmt)
  82. {
  83. if (queryDrop(dwKeyState, pdwEffect))
  84. {
  85. HRESULT hr;
  86. FORMATETC fe;
  87. STGMEDIUM stgmed;
  88. fe.cfFormat = m_cfPrivatePidlData;
  89. fe.ptd = NULL;
  90. fe.dwAspect = DVASPECT_CONTENT;
  91. fe.lindex = -1;
  92. fe.tymed = TYMED_HGLOBAL;
  93. // Get the storage medium from the data object.
  94. hr = pDataObj->GetData(&fe, &stgmed);
  95. if (SUCCEEDED(hr))
  96. {
  97. m_bAcceptFmt = CanDropPidl(stgmed.hGlobal);
  98. }
  99. else
  100. {
  101. m_bAcceptFmt = FALSE;
  102. }
  103. }
  104. else
  105. {
  106. m_bAcceptFmt = FALSE;
  107. }
  108. }
  109. if (!m_bAcceptFmt)
  110. {
  111. *pdwEffect = DROPEFFECT_NONE;
  112. }
  113. return m_bAcceptFmt ? E_FAIL : E_FAIL;
  114. }
  115. STDMETHODIMP CDropTarget::DragOver(DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect)
  116. {
  117. BOOL bRet = queryDrop(dwKeyState, pdwEffect);
  118. return bRet ? E_FAIL : E_FAIL;
  119. }
  120. STDMETHODIMP CDropTarget::DragLeave(VOID)
  121. {
  122. m_bAcceptFmt = FALSE;
  123. return S_OK;
  124. }
  125. STDMETHODIMP CDropTarget::Drop(LPDATAOBJECT pDataObj,
  126. DWORD dwKeyState,
  127. POINTL pt,
  128. LPDWORD pdwEffect)
  129. {
  130. HRESULT hr = E_FAIL;
  131. if (queryDrop(dwKeyState, pdwEffect))
  132. {
  133. FORMATETC fe;
  134. STGMEDIUM stgmed;
  135. fe.cfFormat = m_cfPrivatePidlData;
  136. fe.ptd = NULL;
  137. fe.dwAspect = DVASPECT_CONTENT;
  138. fe.lindex = -1;
  139. fe.tymed = TYMED_HGLOBAL;
  140. // Get the storage medium from the data object.
  141. hr = pDataObj->GetData(&fe, &stgmed);
  142. if (SUCCEEDED(hr))
  143. {
  144. BOOL bRet = doPIDLDrop(stgmed.hGlobal, DROPEFFECT_MOVE == *pdwEffect);
  145. //release the STGMEDIUM
  146. ReleaseStgMedium(&stgmed);
  147. return bRet ? S_OK : E_FAIL;
  148. }
  149. }
  150. *pdwEffect = DROPEFFECT_NONE;
  151. return hr;
  152. }
  153. // Private helper functions:
  154. // TODO : Modify to suit your needs
  155. BOOL CDropTarget::queryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
  156. {
  157. DWORD dwOKEffects = *pdwEffect;
  158. *pdwEffect = DROPEFFECT_NONE;
  159. if (m_bAcceptFmt)
  160. {
  161. *pdwEffect = getDropEffectFromKeyState(dwKeyState);
  162. if(DROPEFFECT_LINK == *pdwEffect)
  163. {
  164. *pdwEffect = DROPEFFECT_NONE;
  165. }
  166. if(*pdwEffect & dwOKEffects)
  167. {
  168. return TRUE;
  169. }
  170. }
  171. return FALSE;
  172. }
  173. // TODO : Modify to suit your needs
  174. DWORD CDropTarget::getDropEffectFromKeyState(DWORD dwKeyState)
  175. {
  176. DWORD dwDropEffect = DROPEFFECT_MOVE;
  177. if(dwKeyState & MK_CONTROL)
  178. {
  179. if(dwKeyState & MK_SHIFT)
  180. {
  181. dwDropEffect = DROPEFFECT_LINK;
  182. }
  183. else
  184. {
  185. dwDropEffect = DROPEFFECT_COPY;
  186. }
  187. }
  188. return dwDropEffect;
  189. }
  190. #define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
  191. #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
  192. LPCITEMIDLIST IDA_GetIDListPtr(LPIDA pida, UINT i)
  193. {
  194. if (NULL == pida)
  195. {
  196. return NULL;
  197. }
  198. if (i == (UINT)-1 || i < pida->cidl)
  199. {
  200. return HIDA_GetPIDLItem(pida, i);
  201. }
  202. return NULL;
  203. }
  204. // in:
  205. // psf OPTIONAL, if NULL assume psfDesktop
  206. // pidl to bind to from psfParent
  207. // pbc bind context
  208. STDAPI SHBindToObjectEx(IShellFolder *psf, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut)
  209. {
  210. HRESULT hr;
  211. IShellFolder *psfRelease;
  212. if (!psf)
  213. {
  214. SHGetDesktopFolder(&psf);
  215. psfRelease = psf;
  216. }
  217. else
  218. {
  219. psfRelease = NULL;
  220. }
  221. if (psf)
  222. {
  223. if (!pidl || ILIsEmpty(pidl))
  224. {
  225. hr = psf->QueryInterface(riid, ppvOut);
  226. }
  227. else
  228. {
  229. hr = psf->BindToObject(pidl, pbc, riid, ppvOut);
  230. }
  231. }
  232. else
  233. {
  234. *ppvOut = NULL;
  235. hr = E_FAIL;
  236. }
  237. if (psfRelease)
  238. {
  239. psfRelease->Release();
  240. }
  241. if (SUCCEEDED(hr) && (*ppvOut == NULL))
  242. {
  243. // Some shell extensions (eg WS_FTP) will return success and a null out pointer
  244. hr = E_FAIL;
  245. }
  246. return hr;
  247. }
  248. STDAPI SHBindToObject(IShellFolder *psf, REFIID riid, LPCITEMIDLIST pidl, void **ppvOut)
  249. {
  250. // NOTE: callers should use SHBindToObjectEx!!!
  251. return SHBindToObjectEx(psf, pidl, NULL, riid, ppvOut);
  252. }
  253. BOOL CDropTarget::CanDropPidl(HGLOBAL hMem)
  254. {
  255. CONFOLDENTRY cfeEmpty;
  256. return CanDropPidl(hMem, cfeEmpty);
  257. }
  258. BOOL CDropTarget::CanDropPidl(HGLOBAL hMem, CONFOLDENTRY& cfe)
  259. {
  260. BOOL fSuccess = FALSE;
  261. USES_CONVERSION;
  262. if(hMem)
  263. {
  264. LPIDA pida = (LPIDA)GlobalLock(hMem);
  265. if (pida)
  266. {
  267. if (pida->cidl != 1)
  268. {
  269. return FALSE; // Don't support multiple files
  270. }
  271. HRESULT hr;
  272. IShellFolder *psf;
  273. LPCITEMIDLIST pIdList = IDA_GetIDListPtr(pida, (UINT)-1);
  274. hr = SHBindToObject(NULL, IID_IShellFolder, pIdList, reinterpret_cast<LPVOID *>(&psf) );
  275. if (SUCCEEDED(hr))
  276. {
  277. for (UINT i = 0; i < pida->cidl; i++)
  278. {
  279. LPCITEMIDLIST pidlLast = IDA_GetIDListPtr(pida, i);
  280. IShellLink *psl;
  281. hr = psf->GetUIObjectOf(NULL, 1, &pidlLast, IID_IShellLink, NULL, reinterpret_cast<LPVOID *>(&psl) );
  282. if (SUCCEEDED(hr))
  283. {
  284. LPITEMIDLIST pItemIdList = NULL;
  285. hr = psl->GetIDList(&pItemIdList);
  286. if (SUCCEEDED(hr))
  287. {
  288. pItemIdList = ILFindLastIDPriv(pItemIdList); // Desktop
  289. if (pItemIdList)
  290. {
  291. PCONFOLDPIDL cfp;
  292. hr = cfp.InitializeFromItemIDList(pItemIdList);
  293. if (SUCCEEDED(hr))
  294. {
  295. hr = cfp.ConvertToConFoldEntry(cfe);
  296. if (SUCCEEDED(hr))
  297. {
  298. if ( !(cfe.GetCharacteristics() & NCCF_BRANDED) &&
  299. ((cfe.GetNetConMediaType() == NCM_PHONE) || (cfe.GetNetConMediaType() == NCM_TUNNEL)) )
  300. {
  301. fSuccess = TRUE;
  302. }
  303. }
  304. }
  305. }
  306. }
  307. psl->Release();
  308. }
  309. }
  310. }
  311. GlobalUnlock(hMem);
  312. }
  313. }
  314. return fSuccess;
  315. }
  316. #include "nccom.h"
  317. #include "..\\dun\\dunimport.h"
  318. HRESULT HrGetNewConnection (INetConnection** ppCon, const CONFOLDENTRY& cfe)
  319. {
  320. static const CLSID CLSID_DialupConnection =
  321. {0xBA126AD7,0x2166,0x11D1,{0xB1,0xD0,0x00,0x80,0x5F,0xC1,0x27,0x0E}};
  322. HRESULT hr;
  323. // Validate parameters.
  324. //
  325. if (!ppCon)
  326. {
  327. hr = E_POINTER;
  328. }
  329. else if (!cfe.GetName())
  330. {
  331. hr = E_INVALIDARG;
  332. }
  333. else
  334. {
  335. // Create an uninitialized dialup connection object.
  336. // Ask for the INetRasConnection interface so we can
  337. // initialize it.
  338. //
  339. INetRasConnection* pRasCon;
  340. hr = HrCreateInstance(
  341. CLSID_DialupConnection,
  342. CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  343. &pRasCon);
  344. TraceHr(ttidError, FAL, hr, FALSE, "HrCreateInstance");
  345. if (SUCCEEDED(hr))
  346. {
  347. NcSetProxyBlanket (pRasCon);
  348. tstring strPhoneBook;
  349. hr = HrGetPhoneBookFile(strPhoneBook);
  350. if (SUCCEEDED(hr))
  351. {
  352. RASENTRY RasEntry = {0};
  353. wcsncpy(RasEntry.szLocalPhoneNumber, cfe.GetPhoneOrHostAddress(), RAS_MaxPhoneNumber);
  354. RasEntry.dwfOptions |= RASEO_PreviewUserPw;
  355. RasEntry.dwSize = sizeof(RASENTRY);
  356. if (cfe.GetNetConMediaType() == NCM_PHONE)
  357. {
  358. lstrcpyW(RasEntry.szDeviceType, RASDT_Modem);
  359. }
  360. if (cfe.GetNetConMediaType() == NCM_TUNNEL)
  361. {
  362. lstrcpyW(RasEntry.szDeviceType, RASDT_Vpn);
  363. }
  364. lstrcpyW(RasEntry.szDeviceName, L"Standard Modem");
  365. RasEntry.dwFramingProtocol = RASFP_Ras;
  366. DWORD dwRet = RasSetEntryProperties(strPhoneBook.c_str(),
  367. cfe.GetName(),
  368. &RasEntry,
  369. sizeof(RASENTRY),
  370. NULL,
  371. 0);
  372. hr = HRESULT_FROM_WIN32(dwRet);
  373. Assert(SUCCEEDED(hr));
  374. }
  375. ReleaseObj (pRasCon);
  376. }
  377. }
  378. TraceError ("CRasUiBase::HrGetNewConnection", hr);
  379. return hr;
  380. }
  381. BOOL CDropTarget::doPIDLDrop(HGLOBAL hMem, BOOL bCut)
  382. {
  383. BOOL fSuccess = FALSE;
  384. CONFOLDENTRY cfe;
  385. if (CanDropPidl(hMem, cfe))
  386. {
  387. ConnListEntry cle;
  388. HRESULT hr = g_ccl.HrFindConnectionByGuid(&cfe.GetGuidID(), cle);
  389. if (S_FALSE == hr)
  390. {
  391. INetConnection *pInetcon;
  392. HrGetNewConnection(&pInetcon, cfe);
  393. }
  394. else
  395. {
  396. ::MessageBox(NULL, L"This item already exists in the Network Connections folder", L"Error", MB_OK);
  397. }
  398. fSuccess = TRUE;
  399. }
  400. return fSuccess;
  401. }