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.

638 lines
16 KiB

  1. //-------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation, 1996 - 1999
  3. //
  4. // File: dragdrop.cpp
  5. //
  6. // Contents: The cpp file to implement IDataObject and IDragSource
  7. //
  8. // History: March-9th-98 xiaohs created
  9. //
  10. //--------------------------------------------------------------
  11. #include <windows.h>
  12. #include <shlobj.h>
  13. #include "dragdrop.h"
  14. #include "unicode.h"
  15. //=========================================================================
  16. //
  17. // The APIs to establish the drag source BLOB and start the drag and drop
  18. // operations
  19. //
  20. //=========================================================================
  21. HRESULT CertMgrUIStartDragDrop(LPNMLISTVIEW pvmn,
  22. HWND hwndControl,
  23. DWORD dwExportFormat,
  24. BOOL fExportChain)
  25. {
  26. HRESULT hr=E_FAIL;
  27. IDropSource *pdsrc=NULL;
  28. IDataObject *pdtobj=NULL;
  29. DWORD dwEffect=0;
  30. DWORD dwCount=0;
  31. LPWSTR *prgwszFileName=NULL;
  32. BYTE **prgBlob=NULL;
  33. DWORD *prgdwSize=NULL;
  34. if(!pvmn || !hwndControl)
  35. {
  36. hr=E_INVALIDARG;
  37. goto CLEANUP;
  38. }
  39. //get the list of file names and their BLOBs
  40. if(!GetFileNameAndContent(pvmn, hwndControl, dwExportFormat, fExportChain,
  41. &dwCount, &prgwszFileName, &prgBlob, &prgdwSize))
  42. {
  43. hr=GetLastError();
  44. goto CLEANUP;
  45. }
  46. if(!SUCCEEDED(hr=CDataObj_CreateInstance(dwCount,
  47. prgwszFileName,
  48. prgBlob,
  49. prgdwSize,
  50. &pdtobj)))
  51. goto CLEANUP;
  52. if(!SUCCEEDED(hr=CDropSource_CreateInstance(&pdsrc)))
  53. goto CLEANUP;
  54. __try {
  55. DoDragDrop(pdtobj, pdsrc, DROPEFFECT_COPY, &dwEffect);
  56. } __except(EXCEPTION_EXECUTE_HANDLER) {
  57. hr = GetExceptionCode();
  58. goto CLEANUP;
  59. }
  60. pdsrc->lpVtbl->Release(pdsrc);
  61. pdsrc=NULL;
  62. pdtobj->lpVtbl->Release(pdtobj);
  63. pdtobj=NULL;
  64. hr=S_OK;
  65. CLEANUP:
  66. FreeFileNameAndContent(dwCount,
  67. prgwszFileName,
  68. prgBlob,
  69. prgdwSize);
  70. if(pdsrc)
  71. pdsrc->lpVtbl->Release(pdsrc);
  72. if(pdtobj)
  73. pdtobj->lpVtbl->Release(pdtobj);
  74. return hr;
  75. }
  76. //=========================================================================
  77. //
  78. // IEnumFORMATETC implementation
  79. //
  80. //=========================================================================
  81. typedef struct _StdEnumFmt // idt
  82. {
  83. IEnumFORMATETC efmt;
  84. UINT cRef;
  85. UINT ifmt;
  86. UINT cfmt;
  87. FORMATETC afmt[1];
  88. } CStdEnumFmt;
  89. extern IEnumFORMATETCVtbl c_CStdEnumFmtVtbl; // forward
  90. HRESULT CreateStdEnumFmtEtc(UINT cfmt, const FORMATETC afmt[], LPENUMFORMATETC *ppenumFormatEtc)
  91. {
  92. CStdEnumFmt * this = (CStdEnumFmt*)LocalAlloc( LPTR, sizeof(CStdEnumFmt) + (cfmt - 1) * sizeof(FORMATETC));
  93. if (this)
  94. {
  95. this->efmt.lpVtbl = &c_CStdEnumFmtVtbl;
  96. this->cRef = 1;
  97. this->cfmt = cfmt;
  98. MoveMemory(this->afmt, afmt, cfmt * sizeof(FORMATETC));
  99. *ppenumFormatEtc = &this->efmt;
  100. return S_OK;
  101. }
  102. else
  103. {
  104. *ppenumFormatEtc = NULL;
  105. return E_OUTOFMEMORY;
  106. }
  107. }
  108. HRESULT CStdEnumFmt_QueryInterface(LPENUMFORMATETC pefmt, REFIID riid, LPVOID * ppvObj)
  109. {
  110. CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
  111. if (IsEqualIID(riid, &IID_IEnumFORMATETC) || IsEqualIID(riid, &IID_IUnknown))
  112. {
  113. *ppvObj = &this->efmt;
  114. this->cRef++;
  115. return S_OK;
  116. }
  117. *ppvObj = NULL;
  118. return E_NOINTERFACE;
  119. }
  120. ULONG CStdEnumFmt_AddRef(LPENUMFORMATETC pefmt)
  121. {
  122. CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
  123. return ++this->cRef;
  124. }
  125. ULONG CStdEnumFmt_Release(LPENUMFORMATETC pefmt)
  126. {
  127. CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
  128. this->cRef--;
  129. if (this->cRef > 0)
  130. return this->cRef;
  131. LocalFree((HLOCAL)this);
  132. return 0;
  133. }
  134. HRESULT CStdEnumFmt_Next(LPENUMFORMATETC pefmt, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
  135. {
  136. CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
  137. UINT cfetch;
  138. HRESULT hres = S_FALSE; // assume less numbers
  139. if (this->ifmt < this->cfmt)
  140. {
  141. cfetch = this->cfmt - this->ifmt;
  142. if (cfetch >= celt)
  143. {
  144. cfetch = celt;
  145. hres = S_OK;
  146. }
  147. CopyMemory(rgelt, &this->afmt[this->ifmt], cfetch * sizeof(FORMATETC));
  148. this->ifmt += cfetch;
  149. }
  150. else
  151. {
  152. cfetch = 0;
  153. }
  154. if (pceltFethed)
  155. *pceltFethed = cfetch;
  156. return hres;
  157. }
  158. HRESULT CStdEnumFmt_Skip(LPENUMFORMATETC pefmt, ULONG celt)
  159. {
  160. CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
  161. this->ifmt += celt;
  162. if (this->ifmt > this->cfmt)
  163. {
  164. this->ifmt = this->cfmt;
  165. return S_FALSE;
  166. }
  167. return S_OK;
  168. }
  169. HRESULT CStdEnumFmt_Reset(LPENUMFORMATETC pefmt)
  170. {
  171. CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
  172. this->ifmt = 0;
  173. return S_OK;
  174. }
  175. HRESULT CStdEnumFmt_Clone(LPENUMFORMATETC pefmt, IEnumFORMATETC ** ppenum)
  176. {
  177. CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
  178. return CreateStdEnumFmtEtc(this->cfmt, this->afmt, ppenum);
  179. }
  180. #pragma data_seg(".text", "CODE")
  181. IEnumFORMATETCVtbl c_CStdEnumFmtVtbl = {
  182. CStdEnumFmt_QueryInterface,
  183. CStdEnumFmt_AddRef,
  184. CStdEnumFmt_Release,
  185. CStdEnumFmt_Next,
  186. CStdEnumFmt_Skip,
  187. CStdEnumFmt_Reset,
  188. CStdEnumFmt_Clone,
  189. };
  190. #pragma data_seg()
  191. //===========================================================================
  192. //
  193. // IDataObject implementation
  194. //
  195. //=========================================================================
  196. typedef struct {
  197. IDataObject dtobj;
  198. UINT cRef;
  199. DWORD dwCount;
  200. LPWSTR *prgwszFileName;
  201. BYTE **prgBlob;
  202. DWORD *prgdwSize;
  203. } CDataObj;
  204. // registered clipboard formats
  205. UINT g_cfFileContents = 0;
  206. UINT g_cfFileGroupDescriptorA = 0;
  207. UINT g_cfFileGroupDescriptorW = 0;
  208. #pragma data_seg(".text", "CODE")
  209. const char c_szFileContents[] = CFSTR_FILECONTENTS; // "FileContents"
  210. const char c_szFileGroupDescriptorA[] = CFSTR_FILEDESCRIPTORA; // "FileGroupDescriptor"
  211. const char c_szFileGroupDescriptorW[] = CFSTR_FILEDESCRIPTORW; // "FileGroupDescriptorW"
  212. #pragma data_seg()
  213. IDataObjectVtbl c_CDataObjVtbl; // forward decl
  214. HRESULT CDataObj_CreateInstance(DWORD dwCount,
  215. LPWSTR *prgwszFileName,
  216. BYTE **prgBlob,
  217. DWORD *prgdwSize,
  218. IDataObject **ppdtobj)
  219. {
  220. CDataObj *this = (CDataObj *)LocalAlloc(LPTR, sizeof(CDataObj));
  221. if (this)
  222. {
  223. this->dtobj.lpVtbl = &c_CDataObjVtbl;
  224. this->cRef = 1;
  225. this->dwCount = dwCount;
  226. this->prgwszFileName = prgwszFileName;
  227. this->prgBlob = prgBlob;
  228. this->prgdwSize = prgdwSize;
  229. *ppdtobj = &this->dtobj;
  230. if (g_cfFileContents == 0)
  231. {
  232. g_cfFileContents = RegisterClipboardFormat(c_szFileContents);
  233. g_cfFileGroupDescriptorW = RegisterClipboardFormat(c_szFileGroupDescriptorW);
  234. g_cfFileGroupDescriptorA = RegisterClipboardFormat(c_szFileGroupDescriptorA);
  235. }
  236. return S_OK;
  237. }
  238. *ppdtobj = NULL;
  239. return E_OUTOFMEMORY;
  240. }
  241. HRESULT CDataObj_QueryInterface(IDataObject *pdtobj, REFIID riid, LPVOID * ppvObj)
  242. {
  243. CDataObj *this = IToClass(CDataObj, dtobj, pdtobj);
  244. if (IsEqualIID(riid, &IID_IDataObject) || IsEqualIID(riid, &IID_IUnknown))
  245. {
  246. *ppvObj = this;
  247. this->cRef++;
  248. return S_OK;
  249. }
  250. *ppvObj = NULL;
  251. return E_NOINTERFACE;
  252. }
  253. ULONG CDataObj_AddRef(IDataObject *pdtobj)
  254. {
  255. CDataObj *this = IToClass(CDataObj, dtobj, pdtobj);
  256. this->cRef++;
  257. return this->cRef;
  258. }
  259. ULONG CDataObj_Release(IDataObject *pdtobj)
  260. {
  261. CDataObj *this = IToClass(CDataObj, dtobj, pdtobj);
  262. this->cRef--;
  263. if (this->cRef > 0)
  264. return this->cRef;
  265. LocalFree((HLOCAL)this);
  266. return 0;
  267. }
  268. HRESULT CDataObj_GetData(IDataObject *pdtobj, FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
  269. {
  270. CDataObj *this = IToClass(CDataObj, dtobj, pdtobj);
  271. HRESULT hres = E_INVALIDARG;
  272. DWORD dwIndex=0;
  273. LPSTR psz=NULL;
  274. pmedium->hGlobal = NULL;
  275. pmedium->pUnkForRelease = NULL;
  276. if ( ((g_cfFileGroupDescriptorA == pformatetcIn->cfFormat) &&
  277. (pformatetcIn->tymed & TYMED_HGLOBAL)) ||
  278. ((g_cfFileGroupDescriptorW == pformatetcIn->cfFormat) &&
  279. (pformatetcIn->tymed & TYMED_HGLOBAL))
  280. )
  281. {
  282. if(g_cfFileGroupDescriptorA == pformatetcIn->cfFormat)
  283. {
  284. if(!FIsWinNT())
  285. {
  286. //allocate dwCount-1 file descrptors
  287. pmedium->hGlobal = GlobalAlloc(GPTR,
  288. (sizeof(FILEGROUPDESCRIPTORA)+(this->dwCount -1 )*sizeof(FILEDESCRIPTORA)));
  289. if(NULL == pmedium->hGlobal)
  290. return E_OUTOFMEMORY;
  291. #define pdesc ((FILEGROUPDESCRIPTORA *)pmedium->hGlobal)
  292. //populate all the file descriptors
  293. for(dwIndex =0; dwIndex < this->dwCount; dwIndex++)
  294. {
  295. //get the anscii version of the file name
  296. if(((this->prgwszFileName)[dwIndex] == NULL) ||
  297. (!MkMBStr(NULL, 0, (this->prgwszFileName)[dwIndex], &psz)))
  298. return E_OUTOFMEMORY;
  299. lstrcpy(pdesc->fgd[dwIndex].cFileName, psz);
  300. // specify the file for our HGLOBAL since GlobalSize() will round up
  301. pdesc->fgd[dwIndex].dwFlags = FD_FILESIZE;
  302. pdesc->fgd[dwIndex].nFileSizeLow = (this->prgdwSize)[dwIndex];
  303. FreeMBStr(NULL,psz);
  304. psz=NULL;
  305. }
  306. //specify the number of files
  307. pdesc->cItems = this->dwCount;
  308. #undef pdesc
  309. }
  310. else
  311. return E_INVALIDARG;
  312. }
  313. else
  314. {
  315. //allocate dwCount-1 file descrptors
  316. pmedium->hGlobal = GlobalAlloc(GPTR,
  317. (sizeof(FILEGROUPDESCRIPTORW)+(this->dwCount -1 )*sizeof(FILEDESCRIPTORW)));
  318. if(NULL == pmedium->hGlobal)
  319. return E_OUTOFMEMORY;
  320. #define pdesc ((FILEGROUPDESCRIPTORW *)pmedium->hGlobal)
  321. //populate all the file descriptors
  322. for(dwIndex =0; dwIndex < this->dwCount; dwIndex++)
  323. {
  324. wcscpy(pdesc->fgd[dwIndex].cFileName, (this->prgwszFileName)[dwIndex]);
  325. // specify the file for our HGLOBAL since GlobalSize() will round up
  326. pdesc->fgd[dwIndex].dwFlags = FD_FILESIZE;
  327. pdesc->fgd[dwIndex].nFileSizeLow = (this->prgdwSize)[dwIndex];
  328. }
  329. //specify the number of files
  330. pdesc->cItems = this->dwCount;
  331. #undef pdesc
  332. }
  333. pmedium->tymed = TYMED_HGLOBAL;
  334. hres = S_OK;
  335. }
  336. else if ((g_cfFileContents == pformatetcIn->cfFormat) &&
  337. (pformatetcIn->tymed & TYMED_HGLOBAL))
  338. {
  339. if((pformatetcIn->lindex) < (int)(this->dwCount))
  340. {
  341. pmedium->hGlobal = GlobalAlloc(GPTR, (this->prgdwSize)[pformatetcIn->lindex]);
  342. if (pmedium->hGlobal)
  343. {
  344. CopyMemory(pmedium->hGlobal,
  345. (this->prgBlob)[pformatetcIn->lindex],
  346. (this->prgdwSize)[pformatetcIn->lindex]);
  347. pmedium->tymed = TYMED_HGLOBAL;
  348. hres = S_OK;
  349. }
  350. else
  351. hres=E_OUTOFMEMORY;
  352. }
  353. else
  354. hres = E_INVALIDARG;
  355. }
  356. return hres;
  357. }
  358. HRESULT CDataObj_GetDataHere(IDataObject *pdtobj, FORMATETC *pformatetc, STGMEDIUM *pmedium)
  359. {
  360. return E_NOTIMPL;
  361. }
  362. HRESULT CDataObj_QueryGetData(IDataObject *pdtobj, LPFORMATETC pformatetcIn)
  363. {
  364. CDataObj *this = IToClass(CDataObj, dtobj, pdtobj);
  365. if (((pformatetcIn->cfFormat == g_cfFileContents) &&
  366. (pformatetcIn->tymed & TYMED_HGLOBAL ))||
  367. ((pformatetcIn->cfFormat == g_cfFileGroupDescriptorW) &&
  368. (pformatetcIn->tymed & TYMED_HGLOBAL))
  369. )
  370. {
  371. return S_OK;
  372. }
  373. else
  374. {
  375. //on NT, we do not support A version in order to be
  376. //unicode compliant. The shell query the A version first on NT.
  377. if(!FIsWinNT())
  378. {
  379. if((pformatetcIn->cfFormat == g_cfFileGroupDescriptorA) &&
  380. (pformatetcIn->tymed & TYMED_HGLOBAL))
  381. return S_OK;
  382. else
  383. return S_FALSE;
  384. }
  385. else
  386. return S_FALSE;
  387. }
  388. }
  389. HRESULT CDataObj_GetCanonicalFormatEtc(IDataObject *pdtobj, FORMATETC *pformatetc, FORMATETC *pformatetcOut)
  390. {
  391. return DATA_S_SAMEFORMATETC;
  392. }
  393. HRESULT CDataObj_SetData(IDataObject *pdtobj, FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
  394. {
  395. return E_NOTIMPL;
  396. }
  397. HRESULT CDataObj_EnumFormatEtc(IDataObject *pdtobj, DWORD dwDirection, LPENUMFORMATETC *ppenumFormatEtc)
  398. {
  399. CDataObj *this = IToClass(CDataObj, dtobj, pdtobj);
  400. FORMATETC fmte[3] = {
  401. {(WORD)g_cfFileContents, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  402. {(WORD)g_cfFileGroupDescriptorA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  403. {(WORD)g_cfFileGroupDescriptorW, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  404. };
  405. return CreateStdEnumFmtEtc(ARRAYSIZE(fmte), fmte, ppenumFormatEtc);
  406. }
  407. HRESULT CDataObj_Advise(IDataObject *pdtobj, FORMATETC *pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD *pdwConnection)
  408. {
  409. return OLE_E_ADVISENOTSUPPORTED;
  410. }
  411. HRESULT CDataObj_Unadvise(IDataObject *pdtobj, DWORD dwConnection)
  412. {
  413. return OLE_E_ADVISENOTSUPPORTED;
  414. }
  415. HRESULT CDataObj_EnumAdvise(IDataObject *pdtobj, LPENUMSTATDATA *ppenumAdvise)
  416. {
  417. return OLE_E_ADVISENOTSUPPORTED;
  418. }
  419. #pragma data_seg(".text", "CODE")
  420. IDataObjectVtbl c_CDataObjVtbl = {
  421. CDataObj_QueryInterface,
  422. CDataObj_AddRef,
  423. CDataObj_Release,
  424. CDataObj_GetData,
  425. CDataObj_GetDataHere,
  426. CDataObj_QueryGetData,
  427. CDataObj_GetCanonicalFormatEtc,
  428. CDataObj_SetData,
  429. CDataObj_EnumFormatEtc,
  430. CDataObj_Advise,
  431. CDataObj_Unadvise,
  432. CDataObj_EnumAdvise
  433. };
  434. #pragma data_seg()
  435. //=========================================================================
  436. //
  437. // IDropSource implementation
  438. //
  439. //=========================================================================
  440. typedef struct {
  441. IDropSource dsrc;
  442. UINT cRef;
  443. DWORD grfInitialKeyState;
  444. } CDropSource;
  445. IDropSourceVtbl c_CDropSourceVtbl; // forward decl
  446. HRESULT CDropSource_CreateInstance(IDropSource **ppdsrc)
  447. {
  448. CDropSource *this = (CDropSource *)LocalAlloc(LPTR, sizeof(CDropSource));
  449. if (this)
  450. {
  451. this->dsrc.lpVtbl = &c_CDropSourceVtbl;
  452. this->cRef = 1;
  453. *ppdsrc = &this->dsrc;
  454. return S_OK;
  455. }
  456. else
  457. {
  458. *ppdsrc = NULL;
  459. return E_OUTOFMEMORY;
  460. }
  461. }
  462. HRESULT CDropSource_QueryInterface(IDropSource *pdsrc, REFIID riid, LPVOID *ppvObj)
  463. {
  464. CDropSource *this = IToClass(CDropSource, dsrc, pdsrc);
  465. if (IsEqualIID(riid, &IID_IDropSource) || IsEqualIID(riid, &IID_IUnknown))
  466. {
  467. *ppvObj = this;
  468. this->cRef++;
  469. return S_OK;
  470. }
  471. *ppvObj = NULL;
  472. return E_NOINTERFACE;
  473. }
  474. ULONG CDropSource_AddRef(IDropSource *pdsrc)
  475. {
  476. CDropSource *this = IToClass(CDropSource, dsrc, pdsrc);
  477. this->cRef++;
  478. return this->cRef;
  479. }
  480. ULONG CDropSource_Release(IDropSource *pdsrc)
  481. {
  482. CDropSource *this = IToClass(CDropSource, dsrc, pdsrc);
  483. this->cRef--;
  484. if (this->cRef > 0)
  485. return this->cRef;
  486. LocalFree((HLOCAL)this);
  487. return 0;
  488. }
  489. HRESULT CDropSource_QueryContinueDrag(IDropSource *pdsrc, BOOL fEscapePressed, DWORD grfKeyState)
  490. {
  491. CDropSource *this = IToClass(CDropSource, dsrc, pdsrc);
  492. if (fEscapePressed)
  493. return DRAGDROP_S_CANCEL;
  494. // initialize ourself with the drag begin button
  495. if (this->grfInitialKeyState == 0)
  496. this->grfInitialKeyState = (grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON));
  497. if (!(grfKeyState & this->grfInitialKeyState))
  498. return DRAGDROP_S_DROP;
  499. else
  500. return S_OK;
  501. }
  502. HRESULT CDropSource_GiveFeedback(IDropSource *pdsrc, DWORD dwEffect)
  503. {
  504. CDropSource *this = IToClass(CDropSource, dsrc, pdsrc);
  505. return DRAGDROP_S_USEDEFAULTCURSORS;
  506. }
  507. #pragma data_seg(".text", "CODE")
  508. IDropSourceVtbl c_CDropSourceVtbl = {
  509. CDropSource_QueryInterface,
  510. CDropSource_AddRef,
  511. CDropSource_Release,
  512. CDropSource_QueryContinueDrag,
  513. CDropSource_GiveFeedback
  514. };
  515. #pragma data_seg()