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.

559 lines
15 KiB

  1. /*======================================================================================//
  2. | Process Control //
  3. | //
  4. |Copyright (c) 1998 Sequent Computer Systems, Incorporated. All rights reserved. //
  5. | //
  6. |File Name: DataObj.cpp //
  7. | //
  8. |Description: //
  9. | //
  10. |Created: //
  11. | //
  12. |Rev History: //
  13. | //
  14. |=======================================================================================*/
  15. // from samples...
  16. #include "StdAfx.h"
  17. #include "DataObj.h"
  18. #include "BaseNode.h"
  19. #include "Resource.h"
  20. //#define COUNT_DEBUG
  21. // not required but needed formats
  22. UINT CDataObject::s_cfNodeID = ::RegisterClipboardFormat(CCF_NODEID); // not used in MMC 1.2 if CCF_NODEID2 is supported
  23. UINT CDataObject::s_cfNodeID2 = ::RegisterClipboardFormat(CCF_NODEID2);
  24. UINT CDataObject::s_cfSnapinPreloads = ::RegisterClipboardFormat(CCF_SNAPIN_PRELOADS);
  25. UINT CDataObject::s_cfWindowTitle = ::RegisterClipboardFormat(CCF_WINDOW_TITLE);
  26. // required formats
  27. UINT CDataObject::s_cfNodeType = ::RegisterClipboardFormat(CCF_NODETYPE);
  28. UINT CDataObject::s_cfNodeTypeString = ::RegisterClipboardFormat(CCF_SZNODETYPE);
  29. UINT CDataObject::s_cfDisplayName = ::RegisterClipboardFormat(CCF_DISPLAY_NAME);
  30. UINT CDataObject::s_cfSnapinClsid = ::RegisterClipboardFormat(CCF_SNAPIN_CLASSID);
  31. // our additional formats...
  32. UINT CDataObject::s_cfInternal = ::RegisterClipboardFormat(CCF_SNAPIN_INTERNAL);
  33. UINT CDataObject::s_cfBaseInternal = ::RegisterClipboardFormat(CCF_SNAPIN_BASEINTERNAL);
  34. LONG CDataObject::s_nCount = 0;
  35. /////////////////////////////////////////////////////////////////////////////
  36. // CDataObject - This class is used to pass data back and forth with MMC. It
  37. // uses a standard interface, IDataObject to acomplish this.
  38. // Refer to OLE documentation for a description of clipboard
  39. // formats and the IdataObject interface.
  40. CDataObject::CDataObject()
  41. {
  42. m_Cookie = SPECIAL_COOKIE_MIN;
  43. m_Context = CCT_UNINITIALIZED;
  44. m_pFolderObj = NULL;
  45. m_bResultItem = FALSE;
  46. InterlockedIncrement(&s_nCount);
  47. #ifdef COUNT_DEBUG
  48. ATLTRACE( _T("CDataObj::CDataObj() %ld\n"), s_nCount );
  49. #endif
  50. } // end Constructor()
  51. //---------------------------------------------------------------------------
  52. CDataObject::~CDataObject()
  53. {
  54. InterlockedDecrement(&s_nCount);
  55. #ifdef COUNT_DEBUG
  56. ATLTRACE( _T("CDataObj::~CDataObj() %ld\n"), s_nCount );
  57. #endif
  58. } // end Destructor()
  59. /////////////////////////////////////////////////////////////////////////////
  60. // IDataObject implementation
  61. //
  62. STDMETHODIMP
  63. CDataObject::GetDataHere
  64. (
  65. FORMATETC *pFormatEtc, // [in] Pointer to the FORMATETC structure
  66. STGMEDIUM *pStgMedium // [out] Pointer to the STGMEDIUM structure
  67. )
  68. {
  69. ASSERT(pFormatEtc && pStgMedium );
  70. if (!pFormatEtc || !pStgMedium)
  71. return E_UNEXPECTED;
  72. HRESULT hr = DV_E_FORMATETC; // Unknown format
  73. const CLIPFORMAT cf = pFormatEtc->cfFormat;
  74. IStream *pStream = NULL;
  75. pStgMedium->pUnkForRelease = NULL; // by OLE spec
  76. // Make sure FORMATETC is something we can handle...
  77. if( (DVASPECT_CONTENT != pFormatEtc->dwAspect) || (TYMED_HGLOBAL != pFormatEtc->tymed) )
  78. return DV_E_FORMATETC;
  79. SIZE_T Size = GlobalSize(pStgMedium->hGlobal);
  80. //
  81. // $$ potential problem...
  82. // the stream just gets bigger as needed
  83. // but GetDataHere is not suppose to do that...
  84. // is this an issue?
  85. //
  86. hr = CreateStreamOnHGlobal( pStgMedium->hGlobal, FALSE, &pStream );
  87. if( FAILED(hr) )
  88. return hr;
  89. if( cf == s_cfNodeType )
  90. {
  91. hr = WriteNodeTypeGUID( pStream );
  92. }
  93. else if( cf == s_cfNodeTypeString )
  94. {
  95. hr = WriteNodeTypeGUIDString( pStream );
  96. }
  97. else if( cf == s_cfDisplayName )
  98. {
  99. hr = WriteDisplayName( pStream );
  100. }
  101. else if( cf == s_cfSnapinClsid )
  102. {
  103. hr = WriteClsid( pStream );
  104. }
  105. else if( cf == s_cfInternal )
  106. {
  107. hr = WriteInternal( pStream );
  108. }
  109. else if( cf == s_cfBaseInternal )
  110. {
  111. hr = WriteBaseInternal( pStream );
  112. }
  113. else if (cf == s_cfSnapinPreloads )
  114. {
  115. hr = WriteSnapinPreloads( pStream );
  116. }
  117. /* // wait and verify first, I haven't seen this yet
  118. // and don't want to discover that some time down the
  119. // road microsoft starts calling this and I'm not handling this correctly...
  120. // see QueryDataObject() special cookies too... and IS_SPECIAL_COOKIE in sdk help
  121. else if (cf == s_cfWindowTitle )
  122. {
  123. hr = WriteWindowTitle( pStream );
  124. }
  125. */
  126. else
  127. {
  128. hr = DV_E_FORMATETC;
  129. }
  130. SIZE_T Size2 = GlobalSize(pStgMedium->hGlobal);
  131. ASSERT(Size == Size2);
  132. pStream->Release();
  133. return hr;
  134. } // end GetDataHere()
  135. //---------------------------------------------------------------------------
  136. //
  137. STDMETHODIMP CDataObject::GetData
  138. (
  139. LPFORMATETC pFormatEtc, // [in] Pointer to the FORMATETC structure
  140. LPSTGMEDIUM pStgMedium // [out] Pointer to the STGMEDIUM structure
  141. )
  142. {
  143. ASSERT(pFormatEtc && pStgMedium );
  144. if (!pFormatEtc || !pStgMedium)
  145. return E_UNEXPECTED;
  146. HRESULT hr = DV_E_FORMATETC; // Unknown format
  147. const CLIPFORMAT cf = pFormatEtc->cfFormat;
  148. pStgMedium->pUnkForRelease = NULL;
  149. _TCHAR szFormatName[246];
  150. if (!GetClipboardFormatName(cf, szFormatName, ARRAY_SIZE(szFormatName)))
  151. _tcscpy(szFormatName, _T("Unknown format") );
  152. // Make sure FORMATETC is something we can handle...
  153. if( (DVASPECT_CONTENT != pFormatEtc->dwAspect) || (TYMED_HGLOBAL != pFormatEtc->tymed) )
  154. {
  155. ATLTRACE( _T("CDataObject::GetData() called with ClipFormat 0x%X %s return 0x%X\n"), cf, szFormatName, hr );
  156. return hr;
  157. }
  158. if (cf == s_cfNodeID ||
  159. cf == s_cfNodeID2 ||
  160. cf == s_cfSnapinPreloads )
  161. {
  162. IStream *pStream = NULL;
  163. pStgMedium->tymed = TYMED_HGLOBAL;
  164. pStgMedium->hGlobal = NULL;
  165. // the stream gets bigger as needed, not a problem
  166. hr = CreateStreamOnHGlobal( NULL, FALSE, &pStream );
  167. if( SUCCEEDED(hr) )
  168. {
  169. hr = GetHGlobalFromStream(pStream, &(pStgMedium->hGlobal));
  170. ASSERT( SUCCEEDED(hr) );
  171. if ( SUCCEEDED(hr) )
  172. {
  173. if (cf == s_cfNodeID)
  174. hr = WriteNodeID( pStream, TRUE );
  175. else if (cf == s_cfNodeID2)
  176. hr = WriteNodeID( pStream );
  177. else if (cf == s_cfSnapinPreloads)
  178. hr = WriteSnapinPreloads(pStream);
  179. else
  180. {
  181. // a more expensive path to say no!
  182. ASSERT(FALSE); // we already checked for format ...function out of sync?
  183. GlobalFree(pStgMedium->hGlobal);
  184. pStgMedium->hGlobal = NULL;
  185. pStgMedium->tymed = TYMED_NULL;
  186. hr = DV_E_FORMATETC;
  187. }
  188. }
  189. pStream->Release();
  190. }
  191. }
  192. //ATLTRACE( _T("CDataObject::GetData() called with ClipFormat 0x%X %s return 0x%X\n"), cf, szFormatName, hr );
  193. return hr;
  194. } // end GetData()
  195. //---------------------------------------------------------------------------
  196. // SetData can be implemented if a data consumer needs to change the
  197. // properties of one of our nodes.
  198. //
  199. STDMETHODIMP CDataObject::SetData
  200. (
  201. LPFORMATETC pFormatEtc, //[in] FormatEtc to use
  202. LPSTGMEDIUM pStgMedium, //[in] StgMedium to use
  203. BOOL bRelease //[in] TRUE if we release the memory
  204. )
  205. {
  206. ASSERT( pFormatEtc && pStgMedium );
  207. if (!pFormatEtc || !pStgMedium)
  208. return E_UNEXPECTED;
  209. HRESULT hr = DV_E_FORMATETC;
  210. // Make sure FORMATETC is something we can handle.
  211. if( (DVASPECT_CONTENT & pFormatEtc->dwAspect) &&
  212. (TYMED_HGLOBAL & pFormatEtc->tymed ) )
  213. {
  214. //
  215. }
  216. if( bRelease )
  217. ReleaseStgMedium( pStgMedium );
  218. ATLTRACE( _T("CDataObject::SetData() returned 0x%X \n"), hr );
  219. return hr;
  220. } // end SetData()
  221. //---------------------------------------------------------------------------
  222. //
  223. STDMETHODIMP CDataObject::QueryGetData
  224. (
  225. LPFORMATETC pFormatEtc // [in] FormatEtc struct to test.
  226. )
  227. {
  228. ASSERT(pFormatEtc);
  229. if (!pFormatEtc)
  230. return E_UNEXPECTED;
  231. HRESULT hr = DV_E_FORMATETC;
  232. const CLIPFORMAT cf = pFormatEtc->cfFormat;
  233. // Make sure FORMATETC is something we can handle.
  234. if ( (DVASPECT_CONTENT != pFormatEtc->dwAspect) || (TYMED_HGLOBAL != pFormatEtc->tymed) )
  235. hr = DV_E_FORMATETC;
  236. else if (cf == s_cfNodeID || cf == s_cfNodeID2 || cf == s_cfSnapinPreloads)
  237. hr = S_OK;
  238. else
  239. hr = DV_E_FORMATETC;
  240. #ifdef _DEBUG
  241. _TCHAR szFormatName[246];
  242. if (!GetClipboardFormatName(cf, szFormatName, ARRAY_SIZE(szFormatName)))
  243. _tcscpy(szFormatName, _T("Unknown format") );
  244. //ATLTRACE( _T("CDataObject::QueryGetData() called with ClipFormat 0x%X %s return 0x%X\n"), cf, szFormatName, hr );
  245. #endif
  246. return hr;
  247. } // end QueryGetData()
  248. STDMETHODIMP CDataObject::EnumFormatEtc
  249. (
  250. DWORD dwDirection, //[in] Only DATADIR_GET supported
  251. LPENUMFORMATETC* ppEnumFormatEtc //[out] Points to our IEnumFormatEtc
  252. )
  253. {
  254. ATLTRACE( _T("CDataObject::EnumFormatEtc\n"));
  255. return E_NOTIMPL;
  256. } // end EnumFormatEtc()
  257. /////////////////////////////////////////////////////////////////////////////
  258. // Support methods
  259. //
  260. //---------------------------------------------------------------------------
  261. // Write the appropriate GUID to the stream
  262. //
  263. HRESULT
  264. CDataObject::WriteNodeTypeGUID
  265. (
  266. IStream* pStream // [in] Stream we are writing to
  267. )
  268. {
  269. if (!m_pFolderObj)
  270. {
  271. ASSERT( FALSE );
  272. return E_UNEXPECTED;
  273. }
  274. const GUID *pGuid = m_pFolderObj->GetGUIDptr();
  275. return pStream->Write( (PVOID)pGuid, sizeof(GUID), NULL );
  276. } // end WriteNodeTypeGUID()
  277. HRESULT
  278. CDataObject::WriteNodeTypeGUIDString
  279. (
  280. IStream* pStream // [in] Stream we are writing to
  281. )
  282. {
  283. if (!m_pFolderObj)
  284. {
  285. ASSERT( FALSE );
  286. return E_UNEXPECTED;
  287. }
  288. const TCHAR *szGuid = m_pFolderObj->GetGUIDsz();
  289. ULONG ulSizeofString = ( _tcslen(szGuid) + 1) * sizeof(TCHAR);
  290. return pStream->Write( szGuid, ulSizeofString, NULL );
  291. } // end WriteNodeTypeGUIDString()
  292. //---------------------------------------------------------------------------
  293. // Writes the display name to the stream, the node name
  294. //
  295. HRESULT
  296. CDataObject::WriteDisplayName
  297. (
  298. IStream* pStream // [in] Stream we are writing to
  299. )
  300. {
  301. ASSERT(m_pFolderObj);
  302. if (!m_pFolderObj)
  303. return E_UNEXPECTED;
  304. ULONG ulSizeofName = _tcslen(m_pFolderObj->GetNodeName());
  305. if (ulSizeofName) // Count null character if we have a string
  306. ulSizeofName++;
  307. ulSizeofName *= sizeof(TCHAR);
  308. return pStream->Write(m_pFolderObj->GetNodeName(), ulSizeofName, NULL);
  309. } // end WriteDisplayName()
  310. //---------------------------------------------------------------------------
  311. // Writes the Class ID to the stream
  312. //
  313. HRESULT
  314. CDataObject::WriteClsid
  315. (
  316. IStream* pStream // [in] Stream we are writing to
  317. )
  318. {
  319. return pStream->Write( &CLSID_ComponentData,
  320. sizeof(CLSID_ComponentData),
  321. NULL
  322. );
  323. } // end WriteClsid()
  324. //---------------------------------------------------------------------------
  325. // Writes a pointer to this data object to the stream
  326. //
  327. HRESULT
  328. CDataObject::WriteInternal
  329. (
  330. IStream* pStream // [in] Stream we are writing to
  331. )
  332. {
  333. ASSERT(m_pFolderObj);
  334. if (!m_pFolderObj)
  335. return E_UNEXPECTED;
  336. CDataObject *pThis = this;
  337. return pStream->Write( &pThis, sizeof(CDataObject*), NULL );
  338. } // end WriteInternal
  339. //---------------------------------------------------------------------------
  340. // Writes a CBaseNode pointer to the stream
  341. //
  342. HRESULT
  343. CDataObject::WriteBaseInternal
  344. (
  345. IStream* pStream // [in] Stream we are writing to
  346. )
  347. {
  348. ASSERT(m_pFolderObj);
  349. if (!m_pFolderObj)
  350. return E_UNEXPECTED;
  351. return pStream->Write( &m_pFolderObj, sizeof(CBaseNode *), NULL );
  352. } // end WriteInternal
  353. HRESULT
  354. CDataObject::WriteNodeID
  355. (
  356. IStream* pStream, // [in] Stream we are writing to
  357. BOOL bCCF_NODEID /* = FALSE */ // [in] reply with older CCF_NODEID format rather than CCF_NODEID2
  358. )
  359. {
  360. if (!m_pFolderObj)
  361. {
  362. ASSERT( FALSE );
  363. return E_UNEXPECTED;
  364. }
  365. HRESULT hr;
  366. DWORD dwFlags = 0;
  367. BOOL bPersisted = m_pFolderObj->IsPersisted();
  368. const TCHAR *szGuid = m_pFolderObj->GetGUIDsz();
  369. DWORD cBytes = (_tcslen(szGuid) + 1) * sizeof(TCHAR);
  370. if (bCCF_NODEID) // CCF_NODEID (originial or older format)
  371. {
  372. // CCF_NODEID cBytes = 0 implies don't persist this node's selection
  373. if (!bPersisted)
  374. cBytes = 0;
  375. hr = pStream->Write(&cBytes, sizeof(cBytes), NULL);
  376. if (hr == S_OK) hr = pStream->Write(szGuid, cBytes, NULL);
  377. }
  378. else // CCF_NODEID2 (newer format)
  379. {
  380. // CCF_NODEID2 doesn't permit writing cBytes = 0, Node GUID string is always written
  381. if (!bPersisted)
  382. dwFlags |= MMC_NODEID_SLOW_RETRIEVAL;
  383. hr = pStream->Write(&dwFlags, sizeof(dwFlags), NULL);
  384. if (hr == S_OK) hr = pStream->Write(&cBytes, sizeof(cBytes), NULL);
  385. if (hr == S_OK) hr = pStream->Write(szGuid, cBytes, NULL);
  386. }
  387. return hr;
  388. } // WriteNodeID()
  389. HRESULT
  390. CDataObject::WriteSnapinPreloads
  391. (
  392. IStream* pStream // [in] Stream we are writing to
  393. )
  394. {
  395. if (!m_pFolderObj)
  396. {
  397. ASSERT( FALSE );
  398. return E_UNEXPECTED;
  399. }
  400. BOOL bPreload = m_pFolderObj->GetPreload();
  401. return pStream->Write( &bPreload, sizeof(bPreload), NULL );
  402. } // end WriteSnapinPreloads()
  403. //---------------------------------------------------------------------------
  404. // Writes the display name to the stream, the node name
  405. //
  406. HRESULT
  407. CDataObject::WriteWindowTitle
  408. (
  409. IStream* pStream // [in] Stream we are writing to
  410. )
  411. {
  412. ASSERT(m_pFolderObj);
  413. if (!m_pFolderObj)
  414. return E_UNEXPECTED;
  415. ULONG ulSizeofName = _tcslen(m_pFolderObj->GetWindowTitle());
  416. if (ulSizeofName) // Count null character if we have a string
  417. ulSizeofName++;
  418. ulSizeofName *= sizeof(TCHAR);
  419. return pStream->Write(m_pFolderObj->GetWindowTitle(), ulSizeofName, NULL);
  420. } // end WriteWindowTitle()
  421. //---------------------------------------------------------------------------
  422. //
  423. VOID
  424. CDataObject::SetDataObject
  425. (
  426. DATA_OBJECT_TYPES Context, // [in] Context of the caller
  427. CBaseNode *pFolder
  428. )
  429. {
  430. m_Context = Context;
  431. m_pFolderObj = pFolder;
  432. } // end SetDataObject()
  433. //---------------------------------------------------------------------------
  434. //
  435. VOID
  436. CDataObject::SetDataObject
  437. (
  438. DATA_OBJECT_TYPES Context, // [in] Context of the caller
  439. CBaseNode *pFolder,
  440. MMC_COOKIE Cookie // [in] Unique indentifier
  441. )
  442. {
  443. m_Context = Context;
  444. m_pFolderObj = pFolder;
  445. m_Cookie = Cookie;
  446. m_bResultItem = TRUE;
  447. } // end SetDataObject()