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.

434 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. ASSERT( 0 != _cRef );
  61. ULONG cRef = InterlockedDecrement(&_cRef);
  62. if ( 0 == cRef )
  63. {
  64. delete this;
  65. }
  66. return cRef;
  67. }
  68. STDMETHODIMP CIDLDataObj::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
  69. {
  70. HRESULT hr = E_INVALIDARG;
  71. pmedium->hGlobal = NULL;
  72. pmedium->pUnkForRelease = NULL;
  73. for (int i = 0; i < MAX_FORMATS; i++)
  74. {
  75. if ((_fmte[i].cfFormat == pformatetcIn->cfFormat) &&
  76. (_fmte[i].tymed & pformatetcIn->tymed) &&
  77. (_fmte[i].dwAspect == pformatetcIn->dwAspect))
  78. {
  79. *pmedium = _medium[i];
  80. if (pmedium->hGlobal)
  81. {
  82. // Indicate that the caller should not release hmem.
  83. if (pmedium->tymed == TYMED_HGLOBAL)
  84. {
  85. InterlockedIncrement(&_cRef);
  86. pmedium->pUnkForRelease = SAFECAST(this, IDataObject *);
  87. return S_OK;
  88. }
  89. // if the type is stream then clone the stream.
  90. if (pmedium->tymed == TYMED_ISTREAM)
  91. {
  92. hr = CreateStreamOnHGlobal(NULL, TRUE, &pmedium->pstm);
  93. if (SUCCEEDED(hr))
  94. {
  95. STATSTG stat;
  96. // Get the Current Stream size
  97. hr = _medium[i].pstm->Stat(&stat, STATFLAG_NONAME);
  98. if (SUCCEEDED(hr))
  99. {
  100. // Seek the source stream to the beginning.
  101. _medium[i].pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  102. // Copy the entire source into the destination. Since the destination stream is created using
  103. // CreateStreamOnHGlobal, it seek pointer is at the beginning.
  104. hr = _medium[i].pstm->CopyTo(pmedium->pstm, stat.cbSize, NULL,NULL );
  105. // Before returning Set the destination seek pointer back at the beginning.
  106. pmedium->pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  107. // If this medium has a punk for release, make sure to add ref that...
  108. pmedium->pUnkForRelease = _medium[i].pUnkForRelease;
  109. if (pmedium->pUnkForRelease)
  110. pmedium->pUnkForRelease->AddRef();
  111. //Hoooh its done.
  112. return hr;
  113. }
  114. else
  115. {
  116. hr = E_OUTOFMEMORY;
  117. }
  118. }
  119. }
  120. }
  121. }
  122. }
  123. if (hr == E_INVALIDARG && _pdtInner)
  124. hr = _pdtInner->GetData(pformatetcIn, pmedium);
  125. return hr;
  126. }
  127. STDMETHODIMP CIDLDataObj::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
  128. {
  129. #ifdef DEBUG
  130. if (pformatetc->cfFormat<CF_MAX)
  131. {
  132. TraceMsg(TF_IDLIST, "CIDLDataObj::GetDataHere called with %x,%x,%x",
  133. pformatetc->cfFormat, pformatetc->tymed, pmedium->tymed);
  134. }
  135. else
  136. {
  137. TCHAR szName[256];
  138. GetClipboardFormatName(pformatetc->cfFormat, szName, ARRAYSIZE(szName));
  139. TraceMsg(TF_IDLIST, "CIDLDataObj::GetDataHere called with %s,%x,%x",
  140. szName, pformatetc->tymed, pmedium->tymed);
  141. }
  142. #endif
  143. return _pdtInner ? _pdtInner->GetDataHere(pformatetc, pmedium) : E_NOTIMPL;
  144. }
  145. STDMETHODIMP CIDLDataObj::QueryGetData(FORMATETC *pformatetcIn)
  146. {
  147. #ifdef DEBUG
  148. if (pformatetcIn->cfFormat<CF_MAX)
  149. {
  150. TraceMsg(TF_IDLIST, "CIDLDataObj::QueryGetData called with %x,%x",
  151. pformatetcIn->cfFormat, pformatetcIn->tymed);
  152. }
  153. else
  154. {
  155. TCHAR szName[256];
  156. GetClipboardFormatName(pformatetcIn->cfFormat, szName, ARRAYSIZE(szName));
  157. TraceMsg(TF_IDLIST, "CIDLDataObj::QueryGetData called with %s,%x",
  158. szName, pformatetcIn->tymed);
  159. }
  160. #endif
  161. for (int i = 0; i < MAX_FORMATS; i++)
  162. {
  163. if ((_fmte[i].cfFormat == pformatetcIn->cfFormat) &&
  164. (_fmte[i].tymed & pformatetcIn->tymed) &&
  165. (_fmte[i].dwAspect == pformatetcIn->dwAspect))
  166. return S_OK;
  167. }
  168. HRESULT hr = S_FALSE;
  169. if (_pdtInner)
  170. hr = _pdtInner->QueryGetData(pformatetcIn);
  171. return hr;
  172. }
  173. STDMETHODIMP CIDLDataObj::GetCanonicalFormatEtc(FORMATETC *pformatetc, FORMATETC *pformatetcOut)
  174. {
  175. // This is the simplest implemtation. It means we always return
  176. // the data in the format requested.
  177. return DATA_S_SAMEFORMATETC;
  178. }
  179. STDMETHODIMP CIDLDataObj::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
  180. {
  181. HRESULT hr;
  182. ASSERT(pformatetc->tymed == pmedium->tymed);
  183. if (fRelease)
  184. {
  185. // first add it if that format is already present
  186. // on a NULL medium (render on demand)
  187. for (int i = 0; i < MAX_FORMATS; i++)
  188. {
  189. if ((_fmte[i].cfFormat == pformatetc->cfFormat) &&
  190. (_fmte[i].tymed == pformatetc->tymed) &&
  191. (_fmte[i].dwAspect == pformatetc->dwAspect))
  192. {
  193. //
  194. // We are simply adding a format, ignore.
  195. //
  196. if (pmedium->hGlobal == NULL)
  197. return S_OK;
  198. // if we are set twice on the same object
  199. if (_medium[i].hGlobal)
  200. ReleaseStgMedium(&_medium[i]);
  201. _medium[i] = *pmedium;
  202. return S_OK;
  203. }
  204. }
  205. //
  206. // This is a new clipboard format. Give the inner a chance first.
  207. // This is important for formats like "Performed DropEffect" and
  208. // "TargetCLSID", which are used by us to communicate information
  209. // into the data object.
  210. //
  211. if (_pdtInner == NULL ||
  212. FAILED(hr = _pdtInner->SetData(pformatetc, pmedium, fRelease)))
  213. {
  214. // Inner object doesn't want it; let's keep it ourselves
  215. // now look for a free slot
  216. for (i = 0; i < MAX_FORMATS; i++)
  217. {
  218. if (_fmte[i].cfFormat == 0)
  219. {
  220. // found a free slot
  221. _medium[i] = *pmedium;
  222. _fmte[i] = *pformatetc;
  223. return S_OK;
  224. }
  225. }
  226. // fixed size table
  227. hr = E_OUTOFMEMORY;
  228. }
  229. }
  230. else
  231. {
  232. if (_pdtInner)
  233. hr = _pdtInner->SetData(pformatetc, pmedium, fRelease);
  234. else
  235. hr = E_INVALIDARG;
  236. }
  237. return hr;
  238. }
  239. STDMETHODIMP CIDLDataObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
  240. {
  241. // If this is the first time, build the format list by calling
  242. // QueryGetData with each clipboard format.
  243. if (!_fEnumFormatCalled)
  244. {
  245. UINT ifmt;
  246. FORMATETC fmte = { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  247. STGMEDIUM medium = { TYMED_HGLOBAL, NULL, NULL };
  248. for (ifmt = 0; ifmt < ICF_MAX; ifmt++)
  249. {
  250. fmte.cfFormat = g_acfIDLData[ifmt];
  251. if (QueryGetData(&fmte) == S_OK)
  252. {
  253. SetData(&fmte, &medium, TRUE);
  254. }
  255. }
  256. _fEnumFormatCalled = TRUE;
  257. }
  258. // Get the number of formatetc
  259. for (UINT cfmt = 0; cfmt < MAX_FORMATS; cfmt++)
  260. {
  261. if (_fmte[cfmt].cfFormat == 0)
  262. break;
  263. }
  264. return SHCreateStdEnumFmtEtcEx(cfmt, _fmte, _pdtInner, ppenumFormatEtc);
  265. }
  266. STDMETHODIMP CIDLDataObj::DAdvise(FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD *pdwConnection)
  267. {
  268. return OLE_E_ADVISENOTSUPPORTED;
  269. }
  270. STDMETHODIMP CIDLDataObj::DUnadvise(DWORD dwConnection)
  271. {
  272. return OLE_E_ADVISENOTSUPPORTED;
  273. }
  274. STDMETHODIMP CIDLDataObj::EnumDAdvise(LPENUMSTATDATA *ppenumAdvise)
  275. {
  276. return OLE_E_ADVISENOTSUPPORTED;
  277. }
  278. // *** IAsyncOperation methods ***
  279. HRESULT CIDLDataObj::SetAsyncMode(BOOL fDoOpAsync)
  280. {
  281. return E_NOTIMPL;
  282. }
  283. HRESULT CIDLDataObj::GetAsyncMode(BOOL *pfIsOpAsync)
  284. {
  285. if (_punkThread || IsMainShellProcess())
  286. {
  287. *pfIsOpAsync = TRUE;
  288. }
  289. else
  290. {
  291. *pfIsOpAsync = FALSE;
  292. }
  293. return S_OK;
  294. }
  295. HRESULT CIDLDataObj::StartOperation(IBindCtx * pbc)
  296. {
  297. _fDidAsynchStart = TRUE;
  298. return S_OK;
  299. }
  300. HRESULT CIDLDataObj::InOperation(BOOL * pfInAsyncOp)
  301. {
  302. if (_fDidAsynchStart)
  303. {
  304. *pfInAsyncOp = TRUE;
  305. }
  306. else
  307. {
  308. *pfInAsyncOp = FALSE;
  309. }
  310. return S_OK;
  311. }
  312. HRESULT CIDLDataObj::EndOperation(HRESULT hResult, IBindCtx * pbc, DWORD dwEffects)
  313. {
  314. _fDidAsynchStart = FALSE;
  315. return S_OK;
  316. }
  317. void CIDLDataObj::InitIDLData1(IDataObject *pdtInner)
  318. {
  319. _cRef = 1;
  320. _pdtInner = pdtInner;
  321. if (pdtInner)
  322. pdtInner->AddRef();
  323. SHGetThreadRef(&_punkThread);
  324. }
  325. void CIDLDataObj::InitIDLData2(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[])
  326. {
  327. if (apidl)
  328. {
  329. HIDA hida = HIDA_Create(pidlFolder, cidl, apidl);
  330. if (hida)
  331. {
  332. IDLData_InitializeClipboardFormats(); // init our registerd formats
  333. DataObj_SetGlobal(this, g_cfHIDA, hida);
  334. }
  335. }
  336. }
  337. CIDLDataObj::CIDLDataObj(IDataObject *pdtInner)
  338. {
  339. InitIDLData1(pdtInner);
  340. }
  341. CIDLDataObj::CIDLDataObj(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[], IDataObject *pdtInner)
  342. {
  343. InitIDLData1(pdtInner);
  344. InitIDLData2(pidlFolder, cidl, apidl);
  345. }
  346. CIDLDataObj::CIDLDataObj(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[])
  347. {
  348. InitIDLData1(NULL);
  349. InitIDLData2(pidlFolder, cidl, apidl);
  350. }
  351. CIDLDataObj::~CIDLDataObj()
  352. {
  353. for (int i = 0; i < MAX_FORMATS; i++)
  354. {
  355. if (_medium[i].hGlobal)
  356. ReleaseStgMedium(&_medium[i]);
  357. }
  358. if (_pdtInner)
  359. _pdtInner->Release();
  360. if (_punkThread)
  361. _punkThread->Release();
  362. }
  363. //
  364. // Create an instance of CIDLDataObj with default Vtable pointer.
  365. //
  366. STDAPI CIDLData_CreateFromIDArray(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[], IDataObject **ppdtobj)
  367. {
  368. return CIDLData_CreateInstance(pidlFolder, cidl, apidl, NULL, ppdtobj);
  369. }
  370. HRESULT CIDLData_CreateInstance(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[], IDataObject *pdtInner, IDataObject **ppdtobj)
  371. {
  372. *ppdtobj = new CIDLDataObj(pidlFolder, cidl, apidl, pdtInner);
  373. return *ppdtobj ? S_OK : E_OUTOFMEMORY;
  374. }