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.

372 lines
10 KiB

  1. #include "pch.h"
  2. #include "stddef.h"
  3. #pragma hdrstop
  4. // free a DSA
  5. int _DestroyCB(LPVOID pItem, LPVOID pData)
  6. {
  7. DATAOBJECTITEM *pdoi = (DATAOBJECTITEM*)pItem;
  8. LocalFreeStringW(&pdoi->pszPath);
  9. LocalFreeStringW(&pdoi->pszObjectClass);
  10. return 1;
  11. }
  12. STDAPI_(void) FreeDataObjectDSA(HDSA hdsaObjects)
  13. {
  14. DSA_DestroyCallback(hdsaObjects, _DestroyCB, NULL);
  15. }
  16. // IDataObject stuff
  17. CLIPFORMAT g_cfDsObjectNames = 0;
  18. typedef struct
  19. {
  20. UINT cfFormat;
  21. STGMEDIUM medium;
  22. } OTHERFMT;
  23. class CDataObject : public IDataObject
  24. {
  25. public:
  26. CDataObject(HDSA hdsaObjects, BOOL fAdmin);
  27. ~CDataObject();
  28. // IUnknown
  29. STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject);
  30. STDMETHOD_(ULONG, AddRef)();
  31. STDMETHOD_(ULONG, Release)();
  32. // IDataObject
  33. STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
  34. STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
  35. { return E_NOTIMPL; }
  36. STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
  37. STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
  38. { return DATA_S_SAMEFORMATETC; }
  39. STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
  40. STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
  41. { return E_NOTIMPL; }
  42. STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
  43. { return OLE_E_ADVISENOTSUPPORTED; }
  44. STDMETHODIMP DUnadvise(DWORD dwConnection)
  45. { return OLE_E_ADVISENOTSUPPORTED; }
  46. STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
  47. { return OLE_E_ADVISENOTSUPPORTED; }
  48. private:
  49. LONG _cRef;
  50. BOOL _fAdmin;
  51. HDSA _hdsaObjects; // array of the objects
  52. HDSA _hdsaOtherFmt;
  53. static INT s_OtherFmtDestroyCB(LPVOID pVoid, LPVOID pData);
  54. void _RegisterClipFormats(void);
  55. HRESULT _GetDsObjectNames(FORMATETC* pFmt, STGMEDIUM* pMedium);
  56. };
  57. STDAPI CDataObject_CreateInstance(HDSA dsaObjects, BOOL fAdmin, REFIID riid, void **ppv)
  58. {
  59. CDataObject *pdo = new CDataObject(dsaObjects, fAdmin);
  60. if (!pdo)
  61. return E_OUTOFMEMORY;
  62. HRESULT hr = pdo->QueryInterface(riid, ppv);
  63. pdo->Release();
  64. return hr;
  65. }
  66. // IDataObject implementation
  67. void CDataObject::_RegisterClipFormats(void)
  68. {
  69. if (!g_cfDsObjectNames)
  70. g_cfDsObjectNames = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES);
  71. }
  72. CDataObject::CDataObject(HDSA dsaObjects, BOOL fAdmin) :
  73. _hdsaObjects(dsaObjects),
  74. _fAdmin(fAdmin),
  75. _cRef(1)
  76. {
  77. DllAddRef();
  78. _RegisterClipFormats(); // ensure our private formats are registered
  79. }
  80. // destruction
  81. INT CDataObject::s_OtherFmtDestroyCB(LPVOID pVoid, LPVOID pData)
  82. {
  83. OTHERFMT *pOtherFmt = (OTHERFMT*)pVoid;
  84. ReleaseStgMedium(&pOtherFmt->medium);
  85. return 1;
  86. }
  87. CDataObject::~CDataObject()
  88. {
  89. FreeDataObjectDSA(_hdsaObjects);
  90. if ( _hdsaOtherFmt )
  91. DSA_DestroyCallback(_hdsaOtherFmt, s_OtherFmtDestroyCB, NULL);
  92. DllRelease();
  93. }
  94. // QI handling
  95. ULONG CDataObject::AddRef()
  96. {
  97. return InterlockedIncrement(&_cRef);
  98. }
  99. ULONG CDataObject::Release()
  100. {
  101. if (InterlockedDecrement(&_cRef))
  102. return _cRef;
  103. delete this;
  104. return 0;
  105. }
  106. HRESULT CDataObject::QueryInterface(REFIID riid, void **ppv)
  107. {
  108. static const QITAB qit[] =
  109. {
  110. QITABENT(CDataObject, IDataObject), // IID_IDataObject
  111. {0, 0 },
  112. };
  113. return QISearch(this, qit, riid, ppv);
  114. }
  115. // fetch the object names from the IDataObject
  116. HRESULT CDataObject::_GetDsObjectNames(FORMATETC* pFmt, STGMEDIUM* pMedium)
  117. {
  118. IDsDisplaySpecifier *pdds;
  119. HRESULT hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&pdds);
  120. if (SUCCEEDED(hr))
  121. {
  122. int count = DSA_GetItemCount(_hdsaObjects);
  123. int i;
  124. // lets walk the array of items trying to determine which items
  125. // are to be returned to the caller.
  126. DWORD cbStruct = SIZEOF(DSOBJECTNAMES);
  127. DWORD offset = SIZEOF(DSOBJECTNAMES);
  128. for (i = 0 ; i < count; i++)
  129. {
  130. DATAOBJECTITEM* pdoi = (DATAOBJECTITEM*)DSA_GetItemPtr(_hdsaObjects, i);
  131. // string offset is offset by the number of structures
  132. offset += SIZEOF(DSOBJECT);
  133. // adjust the size of the total structure
  134. cbStruct += SIZEOF(DSOBJECT);
  135. cbStruct += StringByteSizeW(pdoi->pszPath);
  136. cbStruct += StringByteSizeW(pdoi->pszObjectClass);
  137. }
  138. // we have walked the structure, we know the size so lets return
  139. // the structure to the caller.
  140. DSOBJECTNAMES *pDsObjectNames;
  141. hr = AllocStorageMedium(pFmt, pMedium, cbStruct, (LPVOID*)&pDsObjectNames);
  142. if (SUCCEEDED(hr))
  143. {
  144. pDsObjectNames->clsidNamespace = CLSID_MicrosoftDS;
  145. pDsObjectNames->cItems = count;
  146. for (i = 0 ; i < count; i++)
  147. {
  148. DATAOBJECTITEM* pdoi = (DATAOBJECTITEM*)DSA_GetItemPtr(_hdsaObjects, i);
  149. // is this class a conatiner, if so then lets return that to the caller
  150. if (pdoi->fIsContainer)
  151. pDsObjectNames->aObjects[i].dwFlags |= DSOBJECT_ISCONTAINER;
  152. if (_fAdmin)
  153. pDsObjectNames->aObjects[i].dwProviderFlags = DSPROVIDER_ADVANCED;
  154. // copy the strings to the buffer
  155. pDsObjectNames->aObjects[i].offsetName = offset;
  156. StringByteCopyW(pDsObjectNames, offset, pdoi->pszPath);
  157. offset += StringByteSizeW(pdoi->pszPath);
  158. pDsObjectNames->aObjects[i].offsetClass = offset;
  159. StringByteCopyW(pDsObjectNames, offset, pdoi->pszObjectClass);
  160. offset += StringByteSizeW(pdoi->pszObjectClass);
  161. }
  162. if ( FAILED(hr) )
  163. ReleaseStgMedium(pMedium);
  164. }
  165. pdds->Release();
  166. }
  167. return hr;
  168. }
  169. // IDataObject methods
  170. STDMETHODIMP CDataObject::GetData(FORMATETC* pFmt, STGMEDIUM* pMedium)
  171. {
  172. int i;
  173. HRESULT hr = S_OK;
  174. TraceEnter(TRACE_DATAOBJ, "CDataObject::GetData");
  175. if ( !pFmt || !pMedium )
  176. ExitGracefully(hr, E_INVALIDARG, "Bad arguments to GetData");
  177. if ( pFmt->cfFormat == g_cfDsObjectNames )
  178. {
  179. hr = _GetDsObjectNames(pFmt, pMedium);
  180. FailGracefully(hr, "Failed when build CF_DSOBJECTNAMES");
  181. }
  182. else
  183. {
  184. hr = DV_E_FORMATETC; // failed
  185. for ( i = 0 ; _hdsaOtherFmt && (i < DSA_GetItemCount(_hdsaOtherFmt)); i++ )
  186. {
  187. OTHERFMT *pOtherFmt = (OTHERFMT*)DSA_GetItemPtr(_hdsaOtherFmt, i);
  188. TraceAssert(pOtherFmt);
  189. if ( pOtherFmt->cfFormat == pFmt->cfFormat )
  190. {
  191. hr = CopyStorageMedium(pFmt, pMedium, &pOtherFmt->medium);
  192. FailGracefully(hr, "Failed to copy the storage medium");
  193. }
  194. }
  195. }
  196. exit_gracefully:
  197. TraceLeaveResult(hr);
  198. }
  199. STDMETHODIMP CDataObject::QueryGetData(FORMATETC* pFmt)
  200. {
  201. HRESULT hr;
  202. INT i;
  203. BOOL fSupported = FALSE;
  204. TraceEnter(TRACE_DATAOBJ, "CDataObject::QueryGetData");
  205. // check the valid clipboard formats either the static list, or the
  206. // DSA which contains the ones we have been set with.
  207. if (pFmt->cfFormat == g_cfDsObjectNames)
  208. {
  209. fSupported = TRUE;
  210. }
  211. else
  212. {
  213. for ( i = 0 ; !fSupported && _hdsaOtherFmt && (i < DSA_GetItemCount(_hdsaOtherFmt)) ; i++ )
  214. {
  215. OTHERFMT *pOtherFmt = (OTHERFMT*)DSA_GetItemPtr(_hdsaOtherFmt, i);
  216. TraceAssert(pOtherFmt);
  217. if ( pOtherFmt->cfFormat == pFmt->cfFormat )
  218. {
  219. TraceMsg("Format is supported (set via ::SetData");
  220. fSupported = TRUE;
  221. }
  222. }
  223. }
  224. if ( !fSupported )
  225. ExitGracefully(hr, DV_E_FORMATETC, "Bad format passed to QueryGetData");
  226. // format looks good, lets check the other parameters
  227. if ( !( pFmt->tymed & TYMED_HGLOBAL ) )
  228. ExitGracefully(hr, E_INVALIDARG, "Non HGLOBAL StgMedium requested");
  229. if ( ( pFmt->ptd ) || !( pFmt->dwAspect & DVASPECT_CONTENT) || !( pFmt->lindex == -1 ) )
  230. ExitGracefully(hr, E_INVALIDARG, "Bad format requested");
  231. hr = S_OK; // successs
  232. exit_gracefully:
  233. TraceLeaveResult(hr);
  234. }
  235. STDMETHODIMP CDataObject::SetData(FORMATETC* pFmt, STGMEDIUM* pMedium, BOOL fRelease)
  236. {
  237. HRESULT hr;
  238. INT i;
  239. OTHERFMT otherfmt = { 0 };
  240. USES_CONVERSION;
  241. TraceEnter(TRACE_DATAOBJ, "CDataObject::SetData");
  242. // All the user to store data with our DataObject, however we are
  243. // only interested in allowing them to this with particular clipboard formats
  244. if ( fRelease && !( pFmt->tymed & TYMED_HGLOBAL ) )
  245. ExitGracefully(hr, E_INVALIDARG, "fRelease == TRUE, but not a HGLOBAL allocation");
  246. if ( !_hdsaOtherFmt )
  247. {
  248. _hdsaOtherFmt = DSA_Create(SIZEOF(OTHERFMT), 4);
  249. TraceAssert(_hdsaOtherFmt);
  250. if ( !_hdsaOtherFmt )
  251. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate the DSA for items");
  252. }
  253. // if there is another copy of this data in the IDataObject then lets discard it.
  254. for ( i = 0 ; i < DSA_GetItemCount(_hdsaOtherFmt) ; i++ )
  255. {
  256. OTHERFMT *pOtherFmt = (OTHERFMT*)DSA_GetItemPtr(_hdsaOtherFmt, i);
  257. TraceAssert(pOtherFmt);
  258. if ( pOtherFmt->cfFormat == pFmt->cfFormat )
  259. {
  260. Trace(TEXT("Discarding previous entry for this format at index %d"), i);
  261. ReleaseStgMedium(&pOtherFmt->medium);
  262. DSA_DeleteItem(_hdsaOtherFmt, i);
  263. break;
  264. }
  265. }
  266. // now put a copy of the data passed to ::SetData into the DSA.
  267. otherfmt.cfFormat = pFmt->cfFormat;
  268. hr = CopyStorageMedium(pFmt, &otherfmt.medium, pMedium);
  269. FailGracefully(hr, "Failed to copy the STORAGEMEIDUM");
  270. if ( -1 == DSA_AppendItem(_hdsaOtherFmt, &otherfmt) )
  271. {
  272. ReleaseStgMedium(&otherfmt.medium);
  273. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to add the data to the DSA");
  274. }
  275. hr = S_OK; // success
  276. exit_gracefully:
  277. TraceLeaveResult(hr);
  278. }