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.

509 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: dataobj_.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. ///////////////////////////////////////////////////////////////////////////////
  11. // Sample code to show how to Create DataObjects
  12. // Minimal error checking for clarity
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // Snap-in NodeType in both GUID format and string format
  15. // Note - Typically there is a node type for each different object, sample
  16. // only uses one node type.
  17. const wchar_t* CCF_DNS_SNAPIN_INTERNAL = L"DNS_SNAPIN_INTERNAL";
  18. CLIPFORMAT CDataObject::m_cfNodeType = (CLIPFORMAT)RegisterClipboardFormat(CCF_NODETYPE);
  19. CLIPFORMAT CDataObject::m_cfNodeTypeString = (CLIPFORMAT)RegisterClipboardFormat(CCF_SZNODETYPE);
  20. CLIPFORMAT CDataObject::m_cfDisplayName = (CLIPFORMAT)RegisterClipboardFormat(CCF_DISPLAY_NAME);
  21. CLIPFORMAT CDataObject::m_cfCoClass = (CLIPFORMAT)RegisterClipboardFormat(CCF_SNAPIN_CLASSID);
  22. CLIPFORMAT CDataObject::m_cfColumnID = (CLIPFORMAT)RegisterClipboardFormat(CCF_COLUMN_SET_ID);
  23. CLIPFORMAT CDataObject::m_cfInternal = (CLIPFORMAT)RegisterClipboardFormat(CCF_DNS_SNAPIN_INTERNAL);
  24. CLIPFORMAT CDataObject::m_cfMultiSel = (CLIPFORMAT)RegisterClipboardFormat(CCF_MULTI_SELECT_SNAPINS);
  25. CLIPFORMAT CDataObject::m_cfMultiObjTypes = (CLIPFORMAT)RegisterClipboardFormat(CCF_OBJECT_TYPES_IN_MULTI_SELECT);
  26. #ifdef _DEBUG_REFCOUNT
  27. unsigned int CDataObject::m_nOustandingObjects = 0;
  28. #endif // _DEBUG_REFCOUNT
  29. /////////////////////////////////////////////////////////////////////////////
  30. // CInternalFormatCracker
  31. HRESULT CInternalFormatCracker::Extract(LPDATAOBJECT lpDataObject)
  32. {
  33. if (DOBJ_CUSTOMOCX == lpDataObject ||
  34. DOBJ_CUSTOMWEB == lpDataObject ||
  35. DOBJ_NULL == lpDataObject)
  36. {
  37. return DV_E_CLIPFORMAT;
  38. }
  39. if (m_pInternal != NULL)
  40. _Free();
  41. SMMCDataObjects * pDO = NULL;
  42. STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
  43. FORMATETC formatetc = { CDataObject::m_cfInternal, NULL,
  44. DVASPECT_CONTENT, -1, TYMED_HGLOBAL
  45. };
  46. FORMATETC formatetc2 = { CDataObject::m_cfMultiSel, NULL,
  47. DVASPECT_CONTENT, -1, TYMED_HGLOBAL
  48. };
  49. HRESULT hr = lpDataObject->GetData(&formatetc2, &stgmedium);
  50. if (FAILED(hr))
  51. {
  52. hr = lpDataObject->GetDataHere(&formatetc, &stgmedium);
  53. if (FAILED(hr))
  54. return hr;
  55. m_pInternal = reinterpret_cast<INTERNAL*>(stgmedium.hGlobal);
  56. }
  57. else
  58. {
  59. pDO = reinterpret_cast<SMMCDataObjects*>(stgmedium.hGlobal);
  60. for (UINT i = 0; i < pDO->count; i++)
  61. {
  62. hr = pDO->lpDataObject[i]->GetDataHere(&formatetc, &stgmedium);
  63. if (FAILED(hr))
  64. break;
  65. m_pInternal = reinterpret_cast<INTERNAL*>(stgmedium.hGlobal);
  66. if (m_pInternal != NULL)
  67. break;
  68. }
  69. }
  70. return hr;
  71. }
  72. void CInternalFormatCracker::GetCookieList(CNodeList& list)
  73. {
  74. for (DWORD dwCount = 0; dwCount < m_pInternal->m_cookie_count; dwCount++)
  75. {
  76. list.AddTail(m_pInternal->m_p_cookies[dwCount]);
  77. }
  78. }
  79. /////////////////////////////////////////////////////////////////////////////
  80. // CDataObject implementations
  81. STDMETHODIMP CDataObject::GetDataHere(LPFORMATETC lpFormatetc, LPSTGMEDIUM lpMedium)
  82. {
  83. HRESULT hr = DV_E_CLIPFORMAT;
  84. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  85. // Based on the CLIPFORMAT write data to the stream
  86. const CLIPFORMAT cf = lpFormatetc->cfFormat;
  87. if(cf == m_cfNodeType)
  88. {
  89. hr = CreateNodeTypeData(lpMedium);
  90. }
  91. else if(cf == m_cfNodeTypeString)
  92. {
  93. hr = CreateNodeTypeStringData(lpMedium);
  94. }
  95. else if (cf == m_cfDisplayName)
  96. {
  97. hr = CreateDisplayName(lpMedium);
  98. }
  99. else if (cf == m_cfCoClass)
  100. {
  101. hr = CreateCoClassID(lpMedium);
  102. }
  103. else if (cf == m_cfInternal)
  104. {
  105. hr = CreateInternal(lpMedium);
  106. }
  107. else if (cf == m_cfMultiObjTypes)
  108. {
  109. hr = CreateMultiSelectObject(lpMedium);
  110. }
  111. else
  112. {
  113. // if not successful, maybe there is a node specific clipboard format,
  114. // so ask the node itself to provide
  115. CTreeNode* pNode = GetTreeNodeFromCookie();
  116. ASSERT(pNode != NULL);
  117. if (pNode != NULL)
  118. {
  119. hr = pNode->GetDataHere(cf, lpMedium, this);
  120. }
  121. }
  122. return hr;
  123. }
  124. // Note - Sample does not implement these
  125. STDMETHODIMP CDataObject::GetData(LPFORMATETC lpFormatetcIn, LPSTGMEDIUM lpMedium)
  126. {
  127. HRESULT hr = DV_E_CLIPFORMAT;
  128. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  129. // Based on the CLIPFORMAT write data to the stream
  130. const CLIPFORMAT cf = lpFormatetcIn->cfFormat;
  131. if (cf == m_cfColumnID)
  132. {
  133. hr = CreateColumnID(lpMedium);
  134. }
  135. else if (cf == m_cfMultiObjTypes)
  136. {
  137. hr = CreateMultiSelectObject(lpMedium);
  138. }
  139. else
  140. {
  141. // if not successful, maybe there is a node specific clipboard format,
  142. // so ask the node itself to provide
  143. CTreeNode* pNode = GetTreeNodeFromCookie();
  144. if (pNode != NULL)
  145. {
  146. hr = pNode->GetData(cf, lpMedium, this);
  147. }
  148. }
  149. return hr;
  150. }
  151. STDMETHODIMP CDataObject::EnumFormatEtc(DWORD, LPENUMFORMATETC*)
  152. {
  153. return E_NOTIMPL;
  154. }
  155. /////////////////////////////////////////////////////////////////////////////
  156. // CDataObject creation members
  157. HRESULT CDataObject::Create(const void* pBuffer, size_t len, LPSTGMEDIUM lpMedium)
  158. {
  159. HRESULT hr = DV_E_TYMED;
  160. // Do some simple validation
  161. if (pBuffer == NULL || lpMedium == NULL)
  162. return E_POINTER;
  163. // Make sure the type medium is HGLOBAL
  164. if (lpMedium->tymed == TYMED_HGLOBAL)
  165. {
  166. // Create the stream on the hGlobal passed in
  167. LPSTREAM lpStream;
  168. hr = CreateStreamOnHGlobal(lpMedium->hGlobal, FALSE, &lpStream);
  169. if (SUCCEEDED(hr))
  170. {
  171. // Write to the stream the number of bytes
  172. unsigned long written;
  173. hr = lpStream->Write(pBuffer, static_cast<ULONG>(len), &written);
  174. // Because we told CreateStreamOnHGlobal with 'FALSE',
  175. // only the stream is released here.
  176. // Note - the caller (i.e. snap-in, object) will free the HGLOBAL
  177. // at the correct time. This is according to the IDataObject specification.
  178. lpStream->Release();
  179. }
  180. }
  181. return hr;
  182. }
  183. HRESULT CDataObject::CreateColumnID(LPSTGMEDIUM lpMedium)
  184. {
  185. CTreeNode* pTreeNode = GetTreeNodeFromCookie();
  186. if (pTreeNode == NULL)
  187. {
  188. return E_FAIL;
  189. }
  190. ASSERT(pTreeNode->IsContainer());
  191. CContainerNode* pContainerNode = (CContainerNode*)pTreeNode;
  192. // build the column id
  193. LPCWSTR lpszColumnID = pContainerNode->GetColumnID();
  194. size_t iLen = wcslen(lpszColumnID);
  195. // allocate enough memory for the struct and the string for the column id
  196. SColumnSetID* pColumnID = (SColumnSetID*)malloc(sizeof(SColumnSetID) + (iLen * sizeof(WCHAR)));
  197. if (pColumnID != NULL)
  198. {
  199. memset(pColumnID, 0, sizeof(SColumnSetID) + (iLen * sizeof(WCHAR)));
  200. pColumnID->cBytes = static_cast<DWORD>(iLen * sizeof(WCHAR));
  201. wcscpy((LPWSTR)pColumnID->id, lpszColumnID);
  202. // copy the column id to global memory
  203. size_t cb = sizeof(SColumnSetID) + (iLen * sizeof(WCHAR));
  204. lpMedium->tymed = TYMED_HGLOBAL;
  205. lpMedium->hGlobal = ::GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, cb);
  206. if (lpMedium->hGlobal == NULL)
  207. return STG_E_MEDIUMFULL;
  208. BYTE* pb = reinterpret_cast<BYTE*>(::GlobalLock(lpMedium->hGlobal));
  209. memcpy(pb, pColumnID, cb);
  210. ::GlobalUnlock(lpMedium->hGlobal);
  211. free(pColumnID);
  212. }
  213. return S_OK;
  214. }
  215. HRESULT CDataObject::CreateNodeTypeData(LPSTGMEDIUM lpMedium)
  216. {
  217. // Create the node type object in GUID format
  218. // First ask the related node, if failed, get the default GUID
  219. // from the root node
  220. CTreeNode* pNode = GetTreeNodeFromCookie();
  221. if (pNode == NULL)
  222. {
  223. return E_FAIL;
  224. }
  225. const GUID* pNodeType = pNode->GetNodeType();
  226. if (pNodeType == NULL)
  227. {
  228. pNodeType = GetDataFromComponentDataObject()->GetNodeType();
  229. }
  230. HRESULT hr = Create(pNodeType, sizeof(GUID), lpMedium);
  231. return hr;
  232. }
  233. HRESULT CDataObject::CreateNodeTypeStringData(LPSTGMEDIUM lpMedium)
  234. {
  235. // Create the node type object in GUID string format
  236. OLECHAR szNodeType[128] = {0};
  237. // First ask the related node, if failed, get the default GUID
  238. // from the root node
  239. CTreeNode* pNode = GetTreeNodeFromCookie();
  240. if (pNode == NULL)
  241. {
  242. return E_FAIL;
  243. }
  244. const GUID* pNodeType = pNode->GetNodeType();
  245. if (pNodeType == NULL)
  246. {
  247. pNodeType = GetDataFromComponentDataObject()->GetNodeType();
  248. }
  249. ::StringFromGUID2(*pNodeType,szNodeType,128);
  250. return Create(szNodeType, BYTE_MEM_LEN_W(szNodeType), lpMedium);
  251. }
  252. HRESULT CDataObject::CreateDisplayName(LPSTGMEDIUM lpMedium)
  253. {
  254. // This is the display named used in the scope pane and snap-in manager
  255. // We get it from the root node.
  256. CString szDispName;
  257. szDispName = GetDataFromComponentDataObject()->GetDisplayName();
  258. return Create(szDispName, (szDispName.GetLength()+1) * sizeof(wchar_t), lpMedium);
  259. }
  260. HRESULT CDataObject::CreateCoClassID(LPSTGMEDIUM lpMedium)
  261. {
  262. // TODO
  263. ASSERT(m_pUnkComponentData != NULL);
  264. IPersistStream* pIPersistStream = NULL;
  265. HRESULT hr = m_pUnkComponentData->QueryInterface(IID_IPersistStream, (void**)&pIPersistStream);
  266. if (FAILED(hr))
  267. return hr;
  268. ASSERT(pIPersistStream != NULL);
  269. // Create the CoClass information
  270. CLSID clsid;
  271. VERIFY(SUCCEEDED(pIPersistStream->GetClassID(&clsid)));
  272. hr = Create(reinterpret_cast<const void*>(&clsid), sizeof(CLSID), lpMedium);
  273. ASSERT(SUCCEEDED(hr));
  274. pIPersistStream->Release();
  275. return hr;
  276. }
  277. HRESULT CDataObject::CreateInternal(LPSTGMEDIUM lpMedium)
  278. {
  279. HRESULT hr = S_OK;
  280. INTERNAL * pInt = NULL;
  281. void * pBuf = NULL;
  282. UINT size = sizeof(INTERNAL);
  283. size += sizeof(CTreeNode*) * (m_internal.m_cookie_count);
  284. pBuf = GlobalAlloc (GPTR, size);
  285. if (pBuf != NULL)
  286. {
  287. pInt = (INTERNAL *) pBuf;
  288. lpMedium->hGlobal = pBuf;
  289. // copy the data
  290. pInt->m_type = m_internal.m_type;
  291. pInt->m_cookie_count = m_internal.m_cookie_count;
  292. pInt->m_p_cookies = (CTreeNode**) ((BYTE *)pInt + sizeof(INTERNAL));
  293. memcpy (pInt->m_p_cookies, m_internal.m_p_cookies,
  294. sizeof(CTreeNode*) * (m_internal.m_cookie_count));
  295. hr = Create(pBuf, size, lpMedium);
  296. }
  297. else
  298. {
  299. hr = E_OUTOFMEMORY;
  300. }
  301. return hr;
  302. }
  303. //+----------------------------------------------------------------------------
  304. //
  305. // Method: CDSDataObject::CreateMultiSelectObject
  306. //
  307. // Synopsis: this is to create the list of types selected
  308. //
  309. //-----------------------------------------------------------------------------
  310. HRESULT CDataObject::CreateMultiSelectObject(LPSTGMEDIUM lpMedium)
  311. {
  312. CTreeNode** cookieArray = NULL;
  313. cookieArray = (CTreeNode**) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
  314. m_internal.m_cookie_count*sizeof(CTreeNode*));
  315. if (!cookieArray)
  316. {
  317. return E_OUTOFMEMORY;
  318. }
  319. for (UINT k=0; k<m_internal.m_cookie_count; k++)
  320. {
  321. cookieArray[k] = m_internal.m_p_cookies[k];
  322. }
  323. BOOL* bDuplicateArr = NULL;
  324. bDuplicateArr = (BOOL*)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
  325. m_internal.m_cookie_count*sizeof(BOOL));
  326. if (!bDuplicateArr)
  327. {
  328. if (cookieArray)
  329. {
  330. GlobalFree (cookieArray);
  331. }
  332. return E_OUTOFMEMORY;
  333. }
  334. //ZeroMemory(bDuplicateArr, m_internal.m_cookie_count*sizeof(BOOL));
  335. UINT cCount = 0;
  336. for (UINT index = 0; index < m_internal.m_cookie_count; index++)
  337. {
  338. for (UINT j = 0; j < index; j++)
  339. {
  340. GUID Guid1 = *(cookieArray[index]->GetNodeType());
  341. GUID Guid2 = *(cookieArray[j]->GetNodeType());
  342. if (IsEqualGUID (Guid1, Guid2))
  343. {
  344. bDuplicateArr[index] = TRUE;
  345. break; //repeated GUID
  346. }
  347. }
  348. if (!bDuplicateArr[index])
  349. {
  350. cCount++;
  351. }
  352. }
  353. UINT size = sizeof(SMMCObjectTypes) + (cCount) * sizeof(GUID);
  354. void * pTmp = ::GlobalAlloc(GPTR, size);
  355. if (!pTmp)
  356. {
  357. if (cookieArray)
  358. {
  359. GlobalFree (cookieArray);
  360. }
  361. if (bDuplicateArr)
  362. {
  363. GlobalFree (bDuplicateArr);
  364. }
  365. return E_OUTOFMEMORY;
  366. }
  367. SMMCObjectTypes* pdata = reinterpret_cast<SMMCObjectTypes*>(pTmp);
  368. pdata->count = cCount;
  369. UINT i = 0;
  370. for (index=0; index<m_internal.m_cookie_count; index++)
  371. {
  372. if (!bDuplicateArr[index])
  373. {
  374. pdata->guid[i++] = *(cookieArray[index]->GetNodeType());
  375. }
  376. }
  377. ASSERT(i == cCount);
  378. lpMedium->hGlobal = pTmp;
  379. GlobalFree (cookieArray);
  380. GlobalFree (bDuplicateArr);
  381. return S_OK;
  382. }
  383. CRootData* CDataObject::GetDataFromComponentDataObject()
  384. {
  385. CComponentDataObject* pObject =
  386. reinterpret_cast<CComponentDataObject*>(m_pUnkComponentData);
  387. CRootData* pRootData = pObject->GetRootData();
  388. ASSERT(pRootData != NULL);
  389. return pRootData;
  390. }
  391. CTreeNode* CDataObject::GetTreeNodeFromCookie()
  392. {
  393. CComponentDataObject* pObject =
  394. reinterpret_cast<CComponentDataObject*>(m_pUnkComponentData);
  395. CTreeNode* pNode = NULL;
  396. if (m_internal.m_cookie_count > 0)
  397. {
  398. pNode = m_internal.m_p_cookies[0];
  399. if (pNode == NULL)
  400. {
  401. return pObject->GetRootData();
  402. }
  403. }
  404. return pNode;
  405. }
  406. void CDataObject::AddCookie(CTreeNode* cookie)
  407. {
  408. const UINT MEM_CHUNK_SIZE = 10;
  409. void * pTMP = NULL;
  410. if ((m_internal.m_cookie_count) % MEM_CHUNK_SIZE == 0)
  411. {
  412. if (m_internal.m_p_cookies != NULL)
  413. {
  414. pTMP = realloc (m_internal.m_p_cookies,
  415. (m_internal.m_cookie_count +
  416. MEM_CHUNK_SIZE) * sizeof (CTreeNode*));
  417. }
  418. else
  419. {
  420. pTMP = malloc (MEM_CHUNK_SIZE * sizeof (CTreeNode*));
  421. }
  422. if (pTMP == NULL)
  423. {
  424. TRACE(_T("CDataObject::AddCookie - malloc/realloc failed.."));
  425. ASSERT (pTMP != NULL);
  426. }
  427. m_internal.m_p_cookies = (CTreeNode**)pTMP;
  428. }
  429. m_internal.m_p_cookies[m_internal.m_cookie_count] = cookie;
  430. m_internal.m_cookie_count++;
  431. }