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.

499 lines
13 KiB

  1. //=--------------------------------------------------------------------------=
  2. // multisel.cpp
  3. //=--------------------------------------------------------------------------=
  4. // Copyright (c) 1999, Microsoft Corp.
  5. // All Rights Reserved
  6. // Information Contained Herein Is Proprietary and Confidential.
  7. //=--------------------------------------------------------------------------=
  8. //
  9. // CMultiSelDataObject class implementation
  10. //
  11. // This class simulates a multi-select data object craeted by MMC. It is
  12. // used by the stub when it receives a remote call with multiple data objects.
  13. //=--------------------------------------------------------------------------=
  14. #include "mmc.h"
  15. static HRESULT ANSIFromWideStr(WCHAR *pwszWideStr, char **ppszAnsi);
  16. extern "C" HRESULT GetClipboardFormat(WCHAR *pwszFormatName,
  17. CLIPFORMAT *pcfFormat);
  18. class CMultiSelDataObject : public IDataObject
  19. {
  20. public:
  21. CMultiSelDataObject();
  22. ~CMultiSelDataObject();
  23. HRESULT SetDataObjects(IDataObject **ppiDataObjects, long cDataObjects);
  24. private:
  25. // IUnknown
  26. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObjOut);
  27. STDMETHOD_(ULONG, AddRef)(void);
  28. STDMETHOD_(ULONG, Release)(void);
  29. // IDataObject
  30. STDMETHOD(GetData)(FORMATETC *pFormatEtcIn, STGMEDIUM *pmedium);
  31. STDMETHOD(GetDataHere)(FORMATETC *pFormatEtc, STGMEDIUM *pmedium);
  32. STDMETHOD(QueryGetData)(FORMATETC *pFormatEtc);
  33. STDMETHOD(GetCanonicalFormatEtc)(FORMATETC *pFormatEtcIn,
  34. FORMATETC *pFormatEtcOut);
  35. STDMETHOD(SetData)(FORMATETC *pFormatEtc,
  36. STGMEDIUM *pmedium,
  37. BOOL fRelease);
  38. STDMETHOD(EnumFormatEtc)(DWORD dwDirection,
  39. IEnumFORMATETC **ppenumFormatEtc);
  40. STDMETHOD(DAdvise)(FORMATETC *pFormatEtc,
  41. DWORD advf,
  42. IAdviseSink *pAdvSink,
  43. DWORD *pdwConnection);
  44. STDMETHOD(DUnadvise)(DWORD dwConnection);
  45. STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise);
  46. void InitMemberVariables();
  47. void ReleaseDataObjects();
  48. SMMCDataObjects *m_pDataObjects;
  49. CLIPFORMAT m_cfMultiSelectSnapIns;
  50. CLIPFORMAT m_cfMultiSelectDataObject;
  51. ULONG m_cRefs;
  52. };
  53. CMultiSelDataObject::CMultiSelDataObject()
  54. {
  55. InitMemberVariables();
  56. m_cRefs = 1L;
  57. }
  58. CMultiSelDataObject::~CMultiSelDataObject()
  59. {
  60. ReleaseDataObjects();
  61. InitMemberVariables();
  62. }
  63. void CMultiSelDataObject::ReleaseDataObjects()
  64. {
  65. DWORD i = 0;
  66. if (NULL != m_pDataObjects)
  67. {
  68. while (i < m_pDataObjects->count)
  69. {
  70. if (NULL != m_pDataObjects->lpDataObject[i])
  71. {
  72. m_pDataObjects->lpDataObject[i]->Release();
  73. }
  74. i++;
  75. }
  76. (void)::GlobalFree((HGLOBAL)m_pDataObjects);
  77. m_pDataObjects = NULL;
  78. }
  79. }
  80. void CMultiSelDataObject::InitMemberVariables()
  81. {
  82. m_pDataObjects = NULL;
  83. m_cfMultiSelectSnapIns = 0;
  84. m_cfMultiSelectDataObject = 0;
  85. m_cRefs = 0;
  86. }
  87. HRESULT CMultiSelDataObject::SetDataObjects
  88. (
  89. IDataObject **ppiDataObjects,
  90. long cDataObjects
  91. )
  92. {
  93. HRESULT hr = S_OK;
  94. long i = 0;
  95. ReleaseDataObjects();
  96. hr = ::GetClipboardFormat(CCF_MULTI_SELECT_SNAPINS,
  97. &m_cfMultiSelectSnapIns);
  98. if (FAILED(hr))
  99. {
  100. goto Cleanup;
  101. }
  102. hr = ::GetClipboardFormat(CCF_MMC_MULTISELECT_DATAOBJECT,
  103. &m_cfMultiSelectDataObject);
  104. if (FAILED(hr))
  105. {
  106. goto Cleanup;
  107. }
  108. m_pDataObjects = (SMMCDataObjects *)::GlobalAlloc(GPTR,
  109. sizeof(SMMCDataObjects) + ((cDataObjects - 1) * sizeof(IDataObject *)));
  110. if (NULL == m_pDataObjects)
  111. {
  112. hr = E_OUTOFMEMORY;
  113. goto Cleanup;
  114. }
  115. m_pDataObjects->count = cDataObjects;
  116. for (i = 0; i < cDataObjects; i++)
  117. {
  118. ppiDataObjects[i]->AddRef();
  119. m_pDataObjects->lpDataObject[i] = ppiDataObjects[i];
  120. }
  121. Cleanup:
  122. return hr;
  123. }
  124. //=--------------------------------------------------------------------------=
  125. //
  126. // IUnknown Methods
  127. //
  128. //=--------------------------------------------------------------------------=
  129. STDMETHODIMP CMultiSelDataObject::QueryInterface(REFIID riid, void **ppvObjOut)
  130. {
  131. HRESULT hr = S_OK;
  132. if (IID_IUnknown == riid)
  133. {
  134. AddRef();
  135. *ppvObjOut = (IUnknown *)this;
  136. }
  137. else if (IID_IDataObject == riid)
  138. {
  139. AddRef();
  140. *ppvObjOut = (IDataObject *)this;
  141. }
  142. else
  143. {
  144. hr = E_NOINTERFACE;
  145. }
  146. return hr;
  147. }
  148. STDMETHODIMP_(ULONG) CMultiSelDataObject::AddRef(void)
  149. {
  150. m_cRefs++;
  151. return m_cRefs;
  152. }
  153. STDMETHODIMP_(ULONG) CMultiSelDataObject::Release(void)
  154. {
  155. ULONG cRefs = --m_cRefs;
  156. if (0 == cRefs)
  157. {
  158. delete this;
  159. }
  160. return cRefs;
  161. }
  162. //=--------------------------------------------------------------------------=
  163. //
  164. // IDataObject Methods
  165. //
  166. //=--------------------------------------------------------------------------=
  167. STDMETHODIMP CMultiSelDataObject::GetData
  168. (
  169. FORMATETC *pFmtEtc,
  170. STGMEDIUM *pStgMed
  171. )
  172. {
  173. SMMCDataObjects *pMMCDataObjects = NULL;
  174. DWORD *pdw = NULL;
  175. DWORD i = 0;
  176. HRESULT hr = S_OK;
  177. if (TYMED_HGLOBAL != pFmtEtc->tymed)
  178. {
  179. hr = DV_E_TYMED;
  180. goto Cleanup;
  181. }
  182. if (m_cfMultiSelectSnapIns == pFmtEtc->cfFormat)
  183. {
  184. if (NULL == m_pDataObjects)
  185. {
  186. hr = DV_E_FORMATETC;
  187. goto Cleanup;
  188. }
  189. pStgMed->hGlobal = ::GlobalAlloc(GPTR,
  190. sizeof(SMMCDataObjects) +
  191. ((m_pDataObjects->count - 1) * sizeof(IDataObject *)));
  192. if (NULL == pStgMed->hGlobal)
  193. {
  194. hr = E_OUTOFMEMORY;
  195. goto Cleanup;
  196. }
  197. pStgMed->tymed = TYMED_HGLOBAL;
  198. pMMCDataObjects = (SMMCDataObjects *)pStgMed->hGlobal;
  199. pMMCDataObjects->count = m_pDataObjects->count;
  200. for (i = 0; i < pMMCDataObjects->count; i++)
  201. {
  202. // Note: According to the rules of COM the returned IDataObject
  203. // pointers should be AddRef()ed. That is not done here in order
  204. // to emulate the way MMC does it.
  205. pMMCDataObjects->lpDataObject[i] = m_pDataObjects->lpDataObject[i];
  206. }
  207. }
  208. else if (m_cfMultiSelectDataObject == pFmtEtc->cfFormat)
  209. {
  210. pStgMed->hGlobal = ::GlobalAlloc(GPTR, sizeof(DWORD));
  211. if (NULL == pStgMed->hGlobal)
  212. {
  213. hr = E_OUTOFMEMORY;
  214. goto Cleanup;
  215. }
  216. pStgMed->tymed = TYMED_HGLOBAL;
  217. pdw = (DWORD *)pStgMed->hGlobal;
  218. *pdw = (DWORD)1;
  219. }
  220. else
  221. {
  222. hr = DV_E_FORMATETC;
  223. goto Cleanup;
  224. }
  225. Cleanup:
  226. return hr;
  227. }
  228. STDMETHODIMP CMultiSelDataObject::GetDataHere
  229. (
  230. FORMATETC *pFormatEtc,
  231. STGMEDIUM *pmedium
  232. )
  233. {
  234. return E_NOTIMPL;
  235. }
  236. STDMETHODIMP CMultiSelDataObject::QueryGetData(FORMATETC *pFmtEtc)
  237. {
  238. HRESULT hr = S_OK;
  239. if (TYMED_HGLOBAL != pFmtEtc->tymed)
  240. {
  241. hr = DV_E_TYMED;
  242. }
  243. else if ( (m_cfMultiSelectSnapIns != pFmtEtc->cfFormat) &&
  244. (m_cfMultiSelectDataObject != pFmtEtc->cfFormat) )
  245. {
  246. hr = DV_E_FORMATETC;
  247. }
  248. return hr;
  249. }
  250. STDMETHODIMP CMultiSelDataObject::GetCanonicalFormatEtc
  251. (
  252. FORMATETC *pFormatEtcIn,
  253. FORMATETC *pFormatEtcOut
  254. )
  255. {
  256. return E_NOTIMPL;
  257. }
  258. STDMETHODIMP CMultiSelDataObject::SetData
  259. (
  260. FORMATETC *pFormatEtc,
  261. STGMEDIUM *pmedium,
  262. BOOL fRelease
  263. )
  264. {
  265. return E_NOTIMPL;
  266. }
  267. STDMETHODIMP CMultiSelDataObject::EnumFormatEtc
  268. (
  269. DWORD dwDirection,
  270. IEnumFORMATETC **ppenumFormatEtc
  271. )
  272. {
  273. return E_NOTIMPL;
  274. }
  275. STDMETHODIMP CMultiSelDataObject::DAdvise
  276. (
  277. FORMATETC *pFormatEtc,
  278. DWORD advf,
  279. IAdviseSink *pAdvSink,
  280. DWORD *pdwConnection
  281. )
  282. {
  283. return E_NOTIMPL;
  284. }
  285. STDMETHODIMP CMultiSelDataObject::DUnadvise(DWORD dwConnection)
  286. {
  287. return E_NOTIMPL;
  288. }
  289. STDMETHODIMP CMultiSelDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
  290. {
  291. return E_NOTIMPL;
  292. }
  293. extern "C" HRESULT CreateMultiSelDataObject
  294. (
  295. IDataObject **ppiDataObjects,
  296. long cDataObjects,
  297. IDataObject **ppiMultiSelDataObject
  298. )
  299. {
  300. HRESULT hr = S_OK;
  301. CMultiSelDataObject *pMultiSelDataObject = new CMultiSelDataObject;
  302. *ppiMultiSelDataObject = NULL;
  303. if (NULL == pMultiSelDataObject)
  304. {
  305. hr = E_OUTOFMEMORY;
  306. goto Cleanup;
  307. }
  308. hr = pMultiSelDataObject->SetDataObjects(ppiDataObjects, cDataObjects);
  309. if (FAILED(hr))
  310. {
  311. goto Cleanup;
  312. }
  313. *ppiMultiSelDataObject = pMultiSelDataObject;
  314. Cleanup:
  315. if ( FAILED(hr) && (NULL != pMultiSelDataObject) )
  316. {
  317. delete pMultiSelDataObject;
  318. }
  319. return hr;
  320. }
  321. extern "C" HRESULT GetClipboardFormat
  322. (
  323. WCHAR *pwszFormatName,
  324. CLIPFORMAT *pcfFormat
  325. )
  326. {
  327. HRESULT hr = S_OK;
  328. BOOL fAnsi = TRUE;
  329. char *pszFormatName = NULL;
  330. OSVERSIONINFO VerInfo;
  331. ::ZeroMemory(&VerInfo, sizeof(VerInfo));
  332. // Determine whether we are on NT or Win9x so that we know whether to
  333. // register clipboard format strings as UNICODE or ANSI.
  334. VerInfo.dwOSVersionInfoSize = sizeof(VerInfo);
  335. if (!::GetVersionEx(&VerInfo))
  336. {
  337. hr = HRESULT_FROM_WIN32(::GetLastError());
  338. goto Cleanup;
  339. }
  340. if (VER_PLATFORM_WIN32_NT == VerInfo.dwPlatformId)
  341. {
  342. fAnsi = FALSE;
  343. }
  344. if (fAnsi)
  345. {
  346. hr = ::ANSIFromWideStr(pwszFormatName, &pszFormatName);
  347. if (FAILED(hr))
  348. {
  349. goto Cleanup;
  350. }
  351. *pcfFormat = static_cast<CLIPFORMAT>(::RegisterClipboardFormatA(pszFormatName));
  352. }
  353. else
  354. {
  355. *pcfFormat = static_cast<CLIPFORMAT>(::RegisterClipboardFormatW(pwszFormatName));
  356. }
  357. if (0 == *pcfFormat)
  358. {
  359. hr = HRESULT_FROM_WIN32(::GetLastError());
  360. }
  361. Cleanup:
  362. if (NULL != pszFormatName)
  363. {
  364. (void)::GlobalFree(pszFormatName);
  365. }
  366. return hr;
  367. }
  368. static HRESULT ANSIFromWideStr(WCHAR *pwszWideStr, char **ppszAnsi)
  369. {
  370. HRESULT hr = S_OK;
  371. int cchWideStr = (int)::wcslen(pwszWideStr);
  372. int cchConverted = 0;
  373. *ppszAnsi = NULL;
  374. // get required buffer length
  375. int cchAnsi = ::WideCharToMultiByte(CP_ACP, // code page - ANSI code page
  376. 0, // performance and mapping flags
  377. pwszWideStr, // address of wide-character string
  378. cchWideStr, // number of characters in string
  379. NULL, // address of buffer for new string
  380. 0, // size of buffer
  381. NULL, // address of default for unmappable characters
  382. NULL // address of flag set when default char. used
  383. );
  384. if (cchAnsi == 0)
  385. {
  386. hr = HRESULT_FROM_WIN32(::GetLastError());
  387. goto Cleanup;
  388. }
  389. // allocate a buffer for the ANSI string
  390. *ppszAnsi = static_cast<char *>(::GlobalAlloc(GPTR, cchAnsi + 1));
  391. if (*ppszAnsi == NULL)
  392. {
  393. hr = E_OUTOFMEMORY;
  394. goto Cleanup;
  395. }
  396. // now convert the string and copy it to the buffer
  397. cchConverted = ::WideCharToMultiByte(CP_ACP, // code page - ANSI code page
  398. 0, // performance and mapping flags
  399. pwszWideStr, // address of wide-character string
  400. cchWideStr, // number of characters in string
  401. *ppszAnsi, // address of buffer for new string
  402. cchAnsi, // size of buffer
  403. NULL, // address of default for unmappable characters
  404. NULL // address of flag set when default char. used
  405. );
  406. if (cchConverted != cchAnsi)
  407. {
  408. hr = HRESULT_FROM_WIN32(::GetLastError());
  409. goto Cleanup;
  410. }
  411. // add terminating null byte
  412. *((*ppszAnsi) + cchAnsi) = '\0';
  413. Cleanup:
  414. if (FAILED(hr))
  415. {
  416. if (NULL != *ppszAnsi)
  417. {
  418. (void)::GlobalFree(*ppszAnsi);
  419. *ppszAnsi = NULL;
  420. }
  421. }
  422. return hr;
  423. }