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.

442 lines
14 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "bookmk.h"
  4. #include "idldata.h"
  5. #include "datautil.h"
  6. #include <brfcasep.h>
  7. // External prototypes
  8. CLIPFORMAT g_acfIDLData[ICF_MAX] = { CF_HDROP, 0 };
  9. #define RCF(x) (CLIPFORMAT) RegisterClipboardFormat(x)
  10. STDAPI_(void) IDLData_InitializeClipboardFormats(void)
  11. {
  12. if (g_cfBriefObj == 0)
  13. {
  14. g_cfHIDA = RCF(CFSTR_SHELLIDLIST);
  15. g_cfOFFSETS = RCF(CFSTR_SHELLIDLISTOFFSET);
  16. g_cfNetResource = RCF(CFSTR_NETRESOURCES);
  17. g_cfFileContents = RCF(CFSTR_FILECONTENTS); // "FileContents"
  18. g_cfFileGroupDescriptorA = RCF(CFSTR_FILEDESCRIPTORA); // "FileGroupDescriptor"
  19. g_cfFileGroupDescriptorW = RCF(CFSTR_FILEDESCRIPTORW); // "FileGroupDescriptor"
  20. g_cfPrivateShellData = RCF(CFSTR_SHELLIDLISTP);
  21. g_cfFileNameA = RCF(CFSTR_FILENAMEA); // "FileName"
  22. g_cfFileNameW = RCF(CFSTR_FILENAMEW); // "FileNameW"
  23. g_cfFileNameMapA = RCF(CFSTR_FILENAMEMAP); // "FileNameMap"
  24. g_cfFileNameMapW = RCF(CFSTR_FILENAMEMAPW); // "FileNameMapW"
  25. g_cfPrinterFriendlyName = RCF(CFSTR_PRINTERGROUP);
  26. g_cfHTML = RCF(TEXT("HTML Format"));
  27. g_cfPreferredDropEffect = RCF(CFSTR_PREFERREDDROPEFFECT); // "Preferred DropEffect"
  28. g_cfPerformedDropEffect = RCF(CFSTR_PERFORMEDDROPEFFECT); // "Performed DropEffect"
  29. g_cfLogicalPerformedDropEffect = RCF(CFSTR_LOGICALPERFORMEDDROPEFFECT); // "Logical Performed DropEffect"
  30. g_cfPasteSucceeded = RCF(CFSTR_PASTESUCCEEDED); // "Paste Succeeded"
  31. g_cfShellURL = RCF(CFSTR_SHELLURL); // "Uniform Resource Locator"
  32. g_cfInDragLoop = RCF(CFSTR_INDRAGLOOP); // "InShellDragLoop"
  33. g_cfDragContext = RCF(CFSTR_DRAGCONTEXT); // "DragContext"
  34. g_cfTargetCLSID = RCF(CFSTR_TARGETCLSID); // "TargetCLSID", who the drag drop went to
  35. g_cfEmbeddedObject = RCF(TEXT("Embedded Object"));
  36. g_cfObjectDescriptor = RCF(TEXT("Object Descriptor"));
  37. g_cfNotRecyclable = RCF(TEXT("NotRecyclable")); // This object is not recyclable in the recycle bin.
  38. g_cfBriefObj = RCF(CFSTR_BRIEFOBJECT);
  39. g_cfText = CF_TEXT;
  40. g_cfUnicodeText = CF_UNICODETEXT;
  41. g_cfDropEffectFolderList = RCF(CFSTR_DROPEFFECTFOLDERLIST);
  42. g_cfAutoPlayHIDA = RCF(CFSTR_AUTOPLAY_SHELLIDLISTS);
  43. }
  44. }
  45. STDMETHODIMP CIDLDataObj::QueryInterface(REFIID riid, void **ppvObj)
  46. {
  47. static const QITAB qit[] = {
  48. QITABENT(CIDLDataObj, IDataObject),
  49. QITABENT(CIDLDataObj, IAsyncOperation),
  50. { 0 },
  51. };
  52. return QISearch(this, qit, riid, ppvObj);
  53. }
  54. STDMETHODIMP_(ULONG) CIDLDataObj::AddRef()
  55. {
  56. return InterlockedIncrement(&_cRef);
  57. }
  58. STDMETHODIMP_(ULONG) CIDLDataObj::Release()
  59. {
  60. if (InterlockedDecrement(&_cRef))
  61. return _cRef;
  62. delete this;
  63. return 0;
  64. }
  65. STDMETHODIMP CIDLDataObj::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
  66. {
  67. HRESULT hr = E_INVALIDARG;
  68. pmedium->hGlobal = NULL;
  69. pmedium->pUnkForRelease = NULL;
  70. for (int i = 0; i < MAX_FORMATS; i++)
  71. {
  72. if ((_fmte[i].cfFormat == pformatetcIn->cfFormat) &&
  73. (_fmte[i].tymed & pformatetcIn->tymed) &&
  74. (_fmte[i].dwAspect == pformatetcIn->dwAspect))
  75. {
  76. *pmedium = _medium[i];
  77. if (pmedium->hGlobal)
  78. {
  79. // Indicate that the caller should not release hmem.
  80. if (pmedium->tymed == TYMED_HGLOBAL)
  81. {
  82. InterlockedIncrement(&_cRef);
  83. pmedium->pUnkForRelease = SAFECAST(this, IDataObject *);
  84. return S_OK;
  85. }
  86. // if the type is stream then clone the stream.
  87. if (pmedium->tymed == TYMED_ISTREAM)
  88. {
  89. hr = CreateStreamOnHGlobal(NULL, TRUE, &pmedium->pstm);
  90. if (SUCCEEDED(hr))
  91. {
  92. STATSTG stat;
  93. // Get the Current Stream size
  94. hr = _medium[i].pstm->Stat(&stat, STATFLAG_NONAME);
  95. if (SUCCEEDED(hr))
  96. {
  97. // Seek the source stream to the beginning.
  98. _medium[i].pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  99. // Copy the entire source into the destination. Since the destination stream is created using
  100. // CreateStreamOnHGlobal, it seek pointer is at the beginning.
  101. hr = _medium[i].pstm->CopyTo(pmedium->pstm, stat.cbSize, NULL,NULL );
  102. // Before returning Set the destination seek pointer back at the beginning.
  103. pmedium->pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  104. // If this medium has a punk for release, make sure to add ref that...
  105. pmedium->pUnkForRelease = _medium[i].pUnkForRelease;
  106. if (pmedium->pUnkForRelease)
  107. pmedium->pUnkForRelease->AddRef();
  108. //Hoooh its done.
  109. return hr;
  110. }
  111. else
  112. {
  113. hr = E_OUTOFMEMORY;
  114. }
  115. }
  116. }
  117. }
  118. }
  119. }
  120. if (hr == E_INVALIDARG && _pdtInner)
  121. hr = _pdtInner->GetData(pformatetcIn, pmedium);
  122. return hr;
  123. }
  124. STDMETHODIMP CIDLDataObj::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
  125. {
  126. #ifdef DEBUG
  127. if (pformatetc->cfFormat<CF_MAX)
  128. {
  129. TraceMsg(TF_IDLIST, "CIDLDataObj::GetDataHere called with %x,%x,%x",
  130. pformatetc->cfFormat, pformatetc->tymed, pmedium->tymed);
  131. }
  132. else
  133. {
  134. TCHAR szName[256];
  135. GetClipboardFormatName(pformatetc->cfFormat, szName, ARRAYSIZE(szName));
  136. TraceMsg(TF_IDLIST, "CIDLDataObj::GetDataHere called with %s,%x,%x",
  137. szName, pformatetc->tymed, pmedium->tymed);
  138. }
  139. #endif
  140. return _pdtInner ? _pdtInner->GetDataHere(pformatetc, pmedium) : E_NOTIMPL;
  141. }
  142. STDMETHODIMP CIDLDataObj::QueryGetData(FORMATETC *pformatetcIn)
  143. {
  144. #ifdef DEBUG
  145. if (pformatetcIn->cfFormat<CF_MAX)
  146. {
  147. TraceMsg(TF_IDLIST, "CIDLDataObj::QueryGetData called with %x,%x",
  148. pformatetcIn->cfFormat, pformatetcIn->tymed);
  149. }
  150. else
  151. {
  152. TCHAR szName[256];
  153. GetClipboardFormatName(pformatetcIn->cfFormat, szName, ARRAYSIZE(szName));
  154. TraceMsg(TF_IDLIST, "CIDLDataObj::QueryGetData called with %s,%x",
  155. szName, pformatetcIn->tymed);
  156. }
  157. #endif
  158. for (int i = 0; i < MAX_FORMATS; i++)
  159. {
  160. if ((_fmte[i].cfFormat == pformatetcIn->cfFormat) &&
  161. (_fmte[i].tymed & pformatetcIn->tymed) &&
  162. (_fmte[i].dwAspect == pformatetcIn->dwAspect))
  163. return S_OK;
  164. }
  165. HRESULT hr = S_FALSE;
  166. if (_pdtInner)
  167. hr = _pdtInner->QueryGetData(pformatetcIn);
  168. return hr;
  169. }
  170. STDMETHODIMP CIDLDataObj::GetCanonicalFormatEtc(FORMATETC *pformatetc, FORMATETC *pformatetcOut)
  171. {
  172. // This is the simplest implemtation. It means we always return
  173. // the data in the format requested.
  174. return DATA_S_SAMEFORMATETC;
  175. }
  176. STDMETHODIMP CIDLDataObj::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
  177. {
  178. HRESULT hr;
  179. ASSERT(pformatetc->tymed == pmedium->tymed);
  180. if (fRelease)
  181. {
  182. // first add it if that format is already present
  183. // on a NULL medium (render on demand)
  184. for (int i = 0; i < MAX_FORMATS; i++)
  185. {
  186. if ((_fmte[i].cfFormat == pformatetc->cfFormat) &&
  187. (_fmte[i].tymed == pformatetc->tymed) &&
  188. (_fmte[i].dwAspect == pformatetc->dwAspect))
  189. {
  190. //
  191. // We are simply adding a format, ignore.
  192. //
  193. if (pmedium->hGlobal == NULL)
  194. return S_OK;
  195. // if we are set twice on the same object
  196. if (_medium[i].hGlobal)
  197. ReleaseStgMedium(&_medium[i]);
  198. _medium[i] = *pmedium;
  199. return S_OK;
  200. }
  201. }
  202. //
  203. // This is a new clipboard format. Give the inner a chance first.
  204. // This is important for formats like "Performed DropEffect" and
  205. // "TargetCLSID", which are used by us to communicate information
  206. // into the data object.
  207. //
  208. if (_pdtInner == NULL ||
  209. FAILED(hr = _pdtInner->SetData(pformatetc, pmedium, fRelease)))
  210. {
  211. // Inner object doesn't want it; let's keep it ourselves
  212. // now look for a free slot
  213. for (i = 0; i < MAX_FORMATS; i++)
  214. {
  215. if (_fmte[i].cfFormat == 0)
  216. {
  217. // found a free slot
  218. _medium[i] = *pmedium;
  219. _fmte[i] = *pformatetc;
  220. return S_OK;
  221. }
  222. }
  223. // fixed size table
  224. hr = E_OUTOFMEMORY;
  225. }
  226. }
  227. else
  228. {
  229. if (_pdtInner)
  230. hr = _pdtInner->SetData(pformatetc, pmedium, fRelease);
  231. else
  232. hr = E_INVALIDARG;
  233. }
  234. return hr;
  235. }
  236. STDMETHODIMP CIDLDataObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
  237. {
  238. // If this is the first time, build the format list by calling
  239. // QueryGetData with each clipboard format.
  240. if (!_fEnumFormatCalled)
  241. {
  242. UINT ifmt;
  243. FORMATETC fmte = { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  244. STGMEDIUM medium = { TYMED_HGLOBAL, NULL, NULL };
  245. for (ifmt = 0; ifmt < ICF_MAX; ifmt++)
  246. {
  247. fmte.cfFormat = g_acfIDLData[ifmt];
  248. if (QueryGetData(&fmte) == S_OK)
  249. {
  250. SetData(&fmte, &medium, TRUE);
  251. }
  252. }
  253. _fEnumFormatCalled = TRUE;
  254. }
  255. // Get the number of formatetc
  256. for (UINT cfmt = 0; cfmt < MAX_FORMATS; cfmt++)
  257. {
  258. if (_fmte[cfmt].cfFormat == 0)
  259. break;
  260. }
  261. return SHCreateStdEnumFmtEtcEx(cfmt, _fmte, _pdtInner, ppenumFormatEtc);
  262. }
  263. STDMETHODIMP CIDLDataObj::DAdvise(FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD *pdwConnection)
  264. {
  265. return OLE_E_ADVISENOTSUPPORTED;
  266. }
  267. STDMETHODIMP CIDLDataObj::DUnadvise(DWORD dwConnection)
  268. {
  269. return OLE_E_ADVISENOTSUPPORTED;
  270. }
  271. STDMETHODIMP CIDLDataObj::EnumDAdvise(LPENUMSTATDATA *ppenumAdvise)
  272. {
  273. return OLE_E_ADVISENOTSUPPORTED;
  274. }
  275. // *** IAsyncOperation methods ***
  276. HRESULT CIDLDataObj::SetAsyncMode(BOOL fDoOpAsync)
  277. {
  278. return E_NOTIMPL;
  279. }
  280. HRESULT CIDLDataObj::GetAsyncMode(BOOL *pfIsOpAsync)
  281. {
  282. if (_punkThread || IsMainShellProcess())
  283. {
  284. *pfIsOpAsync = TRUE;
  285. }
  286. else
  287. {
  288. *pfIsOpAsync = FALSE;
  289. }
  290. return S_OK;
  291. }
  292. HRESULT CIDLDataObj::StartOperation(IBindCtx * pbc)
  293. {
  294. _fDidAsynchStart = TRUE;
  295. return S_OK;
  296. }
  297. HRESULT CIDLDataObj::InOperation(BOOL * pfInAsyncOp)
  298. {
  299. if (_fDidAsynchStart)
  300. {
  301. *pfInAsyncOp = TRUE;
  302. }
  303. else
  304. {
  305. *pfInAsyncOp = FALSE;
  306. }
  307. return S_OK;
  308. }
  309. HRESULT CIDLDataObj::EndOperation(HRESULT hResult, IBindCtx * pbc, DWORD dwEffects)
  310. {
  311. _fDidAsynchStart = FALSE;
  312. return S_OK;
  313. }
  314. void CIDLDataObj::InitIDLData1(IDataObject *pdtInner)
  315. {
  316. _cRef = 1;
  317. _pdtInner = pdtInner;
  318. if (pdtInner)
  319. pdtInner->AddRef();
  320. SHGetThreadRef(&_punkThread);
  321. }
  322. void CIDLDataObj::InitIDLData2(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[])
  323. {
  324. if (apidl)
  325. {
  326. HIDA hida = HIDA_Create(pidlFolder, cidl, apidl);
  327. if (hida)
  328. {
  329. #if 0 // not yet
  330. // QueryGetData/SetData on HDROP before calling DataObj_SetGlobal with
  331. // HIDA to insure that CF_HDROP will come first in the enumerator
  332. FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  333. STGMEDIUM medium = { TYMED_HGLOBAL, NULL, NULL };
  334. if (QueryGetData(&fmte) == S_OK)
  335. {
  336. SetData(&fmte, &medium, TRUE);
  337. }
  338. #endif // 0
  339. IDLData_InitializeClipboardFormats(); // init our registerd formats
  340. DataObj_SetGlobal(this, g_cfHIDA, hida);
  341. }
  342. }
  343. }
  344. CIDLDataObj::CIDLDataObj(IDataObject *pdtInner)
  345. {
  346. InitIDLData1(pdtInner);
  347. }
  348. CIDLDataObj::CIDLDataObj(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[], IDataObject *pdtInner)
  349. {
  350. InitIDLData1(pdtInner);
  351. InitIDLData2(pidlFolder, cidl, apidl);
  352. }
  353. CIDLDataObj::CIDLDataObj(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[])
  354. {
  355. InitIDLData1(NULL);
  356. InitIDLData2(pidlFolder, cidl, apidl);
  357. }
  358. CIDLDataObj::~CIDLDataObj()
  359. {
  360. for (int i = 0; i < MAX_FORMATS; i++)
  361. {
  362. if (_medium[i].hGlobal)
  363. ReleaseStgMedium(&_medium[i]);
  364. }
  365. if (_pdtInner)
  366. _pdtInner->Release();
  367. if (_punkThread)
  368. _punkThread->Release();
  369. }
  370. //
  371. // Create an instance of CIDLDataObj with default Vtable pointer.
  372. //
  373. STDAPI CIDLData_CreateFromIDArray(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[], IDataObject **ppdtobj)
  374. {
  375. return CIDLData_CreateInstance(pidlFolder, cidl, apidl, NULL, ppdtobj);
  376. }
  377. HRESULT CIDLData_CreateInstance(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[], IDataObject *pdtInner, IDataObject **ppdtobj)
  378. {
  379. *ppdtobj = new CIDLDataObj(pidlFolder, cidl, apidl, pdtInner);
  380. return *ppdtobj ? S_OK : E_OUTOFMEMORY;
  381. }