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.

610 lines
16 KiB

  1. /*****************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 2000
  4. *
  5. * TITLE: comutils.inl
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: LazarI
  10. *
  11. * DATE: 23-Dec-2000
  12. *
  13. * DESCRIPTION: COM templates & utilities (Impl.)
  14. *
  15. *****************************************************************************/
  16. ////////////////////////////////////////////////
  17. // template class CDataObj<MAX_FORMATS>
  18. //
  19. // implementation for an IDataObject which
  20. // supports SetData to different formats.
  21. //
  22. // construction/destruction
  23. template <int MAX_FORMATS>
  24. CDataObj<MAX_FORMATS>::CDataObj<MAX_FORMATS>()
  25. : m_cRefs(1)
  26. {
  27. memset(m_fmte, 0, sizeof(m_fmte));
  28. memset(m_medium, 0, sizeof(m_medium));
  29. }
  30. template <int MAX_FORMATS>
  31. CDataObj<MAX_FORMATS>::~CDataObj<MAX_FORMATS>()
  32. {
  33. // release the data we keep
  34. for( int i = 0; i < MAX_FORMATS; i++ )
  35. {
  36. if( m_medium[i].hGlobal )
  37. {
  38. ReleaseStgMedium(&m_medium[i]);
  39. }
  40. }
  41. }
  42. ///////////////////////////////
  43. // IUnknown impl. - standard
  44. //
  45. template <int MAX_FORMATS>
  46. STDMETHODIMP CDataObj<MAX_FORMATS>::QueryInterface(REFIID riid, void **ppv)
  47. {
  48. // standard implementation
  49. if( !ppv )
  50. {
  51. return E_INVALIDARG;
  52. }
  53. *ppv = NULL;
  54. if( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDataObject) )
  55. {
  56. *ppv = static_cast<IDataObject*>(this);
  57. }
  58. else
  59. {
  60. return E_NOINTERFACE;
  61. }
  62. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  63. return S_OK;
  64. }
  65. template <int MAX_FORMATS>
  66. STDMETHODIMP_(ULONG) CDataObj<MAX_FORMATS>::AddRef()
  67. {
  68. // standard implementation
  69. return InterlockedIncrement(&m_cRefs);
  70. }
  71. template <int MAX_FORMATS>
  72. STDMETHODIMP_(ULONG) CDataObj<MAX_FORMATS>::Release()
  73. {
  74. // standard implementation
  75. ULONG cRefs = InterlockedDecrement(&m_cRefs);
  76. if( 0 == cRefs )
  77. {
  78. delete this;
  79. }
  80. return cRefs;
  81. }
  82. //////////////////
  83. // IDataObject
  84. //
  85. template <int MAX_FORMATS>
  86. /* [local] */
  87. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::GetData(
  88. /* [unique][in] */ FORMATETC *pformatetcIn,
  89. /* [out] */ STGMEDIUM *pmedium)
  90. {
  91. HRESULT hr = E_INVALIDARG;
  92. pmedium->hGlobal = NULL;
  93. pmedium->pUnkForRelease = NULL;
  94. for( int i = 0; i < MAX_FORMATS; i++ )
  95. {
  96. if( (m_fmte[i].cfFormat == pformatetcIn->cfFormat) &&
  97. (m_fmte[i].tymed & pformatetcIn->tymed) &&
  98. (m_fmte[i].dwAspect == pformatetcIn->dwAspect) )
  99. {
  100. *pmedium = m_medium[i];
  101. if( pmedium->hGlobal )
  102. {
  103. // indicate that the caller should not release hmem.
  104. if( pmedium->tymed == TYMED_HGLOBAL )
  105. {
  106. pmedium->pUnkForRelease = static_cast<IDataObject*>(this);
  107. AddRef();
  108. return S_OK;
  109. }
  110. // if the type is stream then clone the stream.
  111. if( pmedium->tymed == TYMED_ISTREAM )
  112. {
  113. hr = CreateStreamOnHGlobal(NULL, TRUE, &pmedium->pstm);
  114. if( SUCCEEDED(hr) )
  115. {
  116. STATSTG stat;
  117. // Get the Current Stream size
  118. hr = m_medium[i].pstm->Stat(&stat, STATFLAG_NONAME);
  119. if( SUCCEEDED(hr) )
  120. {
  121. const LARGE_INTEGER g_li0 = {0};
  122. // Seek the source stream to the beginning.
  123. m_medium[i].pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  124. // Copy the entire source into the destination. Since the destination stream is created using
  125. // CreateStreamOnHGlobal, it seek pointer is at the beginning.
  126. hr = m_medium[i].pstm->CopyTo(pmedium->pstm, stat.cbSize, NULL,NULL );
  127. // Before returning Set the destination seek pointer back at the beginning.
  128. pmedium->pstm->Seek(g_li0, STREAM_SEEK_SET, NULL);
  129. // If this medium has a punk for release, make sure to add ref that...
  130. pmedium->pUnkForRelease = m_medium[i].pUnkForRelease;
  131. if( pmedium->pUnkForRelease )
  132. {
  133. pmedium->pUnkForRelease->AddRef();
  134. }
  135. }
  136. else
  137. {
  138. hr = E_OUTOFMEMORY;
  139. }
  140. }
  141. }
  142. }
  143. }
  144. }
  145. return hr;
  146. }
  147. template <int MAX_FORMATS>
  148. /* [local] */
  149. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::GetDataHere(
  150. /* [unique][in] */ FORMATETC *pformatetc,
  151. /* [out][in] */ STGMEDIUM *pmedium)
  152. {
  153. // we don't implement this.
  154. return E_NOTIMPL;
  155. }
  156. template <int MAX_FORMATS>
  157. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::QueryGetData(
  158. /* [unique][in] */ FORMATETC *pformatetc)
  159. {
  160. HRESULT hr = E_UNEXPECTED;
  161. for( int i = 0; i < MAX_FORMATS; i++ )
  162. {
  163. if( (m_fmte[i].cfFormat == pformatetc->cfFormat) &&
  164. (m_fmte[i].tymed & pformatetc->tymed) &&
  165. (m_fmte[i].dwAspect == pformatetc->dwAspect) )
  166. {
  167. hr = S_OK;
  168. }
  169. }
  170. return hr;
  171. }
  172. template <int MAX_FORMATS>
  173. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::GetCanonicalFormatEtc(
  174. /* [unique][in] */ FORMATETC *pformatectIn,
  175. /* [out] */ FORMATETC *pformatetcOut)
  176. {
  177. // always return the data in the same format
  178. return DATA_S_SAMEFORMATETC;
  179. }
  180. template <int MAX_FORMATS>
  181. /* [local] */
  182. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::SetData(
  183. /* [unique][in] */ FORMATETC *pformatetc,
  184. /* [unique][in] */ STGMEDIUM *pmedium,
  185. /* [in] */ BOOL fRelease)
  186. {
  187. HRESULT hr = E_INVALIDARG;
  188. ASSERT(pformatetc->tymed == pmedium->tymed);
  189. if( fRelease )
  190. {
  191. int i;
  192. // first add it if that format is already present
  193. // on a NULL medium (render on demand)
  194. for( i = 0; i < MAX_FORMATS; i++ )
  195. {
  196. if( (m_fmte[i].cfFormat == pformatetc->cfFormat) &&
  197. (m_fmte[i].tymed == pformatetc->tymed) &&
  198. (m_fmte[i].dwAspect == pformatetc->dwAspect) )
  199. {
  200. // we are simply adding a format, ignore.
  201. if( pmedium->hGlobal == NULL )
  202. {
  203. return S_OK;
  204. }
  205. // if we are set twice on the same object
  206. if( m_medium[i].hGlobal )
  207. {
  208. ReleaseStgMedium(&m_medium[i]);
  209. }
  210. m_medium[i] = *pmedium;
  211. return S_OK;
  212. }
  213. }
  214. // this is a new clipboard format. look for a free slot.
  215. for( i = 0; i < MAX_FORMATS; i++ )
  216. {
  217. if( m_fmte[i].cfFormat == 0 )
  218. {
  219. // found a free slot
  220. m_medium[i] = *pmedium;
  221. m_fmte[i] = *pformatetc;
  222. return S_OK;
  223. }
  224. }
  225. // overflow of our fixed size table
  226. hr = E_OUTOFMEMORY;
  227. }
  228. return hr;
  229. }
  230. template <int MAX_FORMATS>
  231. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::EnumFormatEtc(
  232. /* [in] */ DWORD dwDirection,
  233. /* [out] */ IEnumFORMATETC **ppenumFormatEtc)
  234. {
  235. // we don't implement this.
  236. return E_NOTIMPL;
  237. }
  238. template <int MAX_FORMATS>
  239. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::DAdvise(
  240. /* [in] */ FORMATETC *pformatetc,
  241. /* [in] */ DWORD advf,
  242. /* [unique][in] */ IAdviseSink *pAdvSink,
  243. /* [out] */ DWORD *pdwConnection)
  244. {
  245. // we don't implement this.
  246. return OLE_E_ADVISENOTSUPPORTED;
  247. }
  248. template <int MAX_FORMATS>
  249. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::DUnadvise(
  250. /* [in] */ DWORD dwConnection)
  251. {
  252. // we don't implement this.
  253. return OLE_E_ADVISENOTSUPPORTED;
  254. }
  255. template <int MAX_FORMATS>
  256. HRESULT STDMETHODCALLTYPE CDataObj<MAX_FORMATS>::EnumDAdvise(
  257. /* [out] */ IEnumSTATDATA **ppenumAdvise)
  258. {
  259. // we don't implement this.
  260. return OLE_E_ADVISENOTSUPPORTED;
  261. }
  262. ////////////////////////////////////////////////
  263. // template class CSimpleDataObjImpl<T>
  264. //
  265. // simple implementation for an IDataObject
  266. // and IDropSource which lives in memory.
  267. //
  268. // construction/destruction
  269. template <class T>
  270. CSimpleDataObjImpl<T>::CSimpleDataObjImpl<T>(const T &data, CLIPFORMAT cfDataType, IDataObject *pDataObj)
  271. : m_cRefs(1),
  272. m_cfDataType(cfDataType)
  273. {
  274. m_data = data;
  275. m_spDataObj.CopyFrom(pDataObj);
  276. }
  277. template <class T>
  278. CSimpleDataObjImpl<T>::~CSimpleDataObjImpl<T>()
  279. {
  280. // nothing special
  281. }
  282. ///////////////////////////////
  283. // IUnknown impl. - standard
  284. //
  285. template <class T>
  286. STDMETHODIMP CSimpleDataObjImpl<T>::QueryInterface(REFIID riid, void **ppv)
  287. {
  288. // standard implementation
  289. if( !ppv )
  290. {
  291. return E_INVALIDARG;
  292. }
  293. *ppv = NULL;
  294. if( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDataObject) )
  295. {
  296. *ppv = static_cast<IDataObject*>(this);
  297. }
  298. else if( IsEqualIID(riid, IID_IDropSource) )
  299. {
  300. *ppv = static_cast<IDropSource*>(this);
  301. }
  302. else
  303. {
  304. return E_NOINTERFACE;
  305. }
  306. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  307. return S_OK;
  308. }
  309. template <class T>
  310. STDMETHODIMP_(ULONG) CSimpleDataObjImpl<T>::AddRef()
  311. {
  312. // standard implementation
  313. return InterlockedIncrement(&m_cRefs);
  314. }
  315. template <class T>
  316. STDMETHODIMP_(ULONG) CSimpleDataObjImpl<T>::Release()
  317. {
  318. // standard implementation
  319. ULONG cRefs = InterlockedDecrement(&m_cRefs);
  320. if( 0 == cRefs )
  321. {
  322. delete this;
  323. }
  324. return cRefs;
  325. }
  326. //////////////////
  327. // IDataObject
  328. //
  329. template <class T>
  330. /* [local] */
  331. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::GetData(
  332. /* [unique][in] */ FORMATETC *pformatetcIn,
  333. /* [out] */ STGMEDIUM *pmedium)
  334. {
  335. HRESULT hr = E_INVALIDARG;
  336. // try our data obejct first
  337. if( m_spDataObj )
  338. {
  339. hr = m_spDataObj->GetData(pformatetcIn, pmedium);
  340. }
  341. if( FAILED(hr) )
  342. {
  343. pmedium->hGlobal = NULL;
  344. pmedium->pUnkForRelease = NULL;
  345. pmedium->tymed = TYMED_HGLOBAL;
  346. hr = QueryGetData(pformatetcIn);
  347. if( SUCCEEDED(hr) && FAILED(m_spDataObj->QueryGetData(pformatetcIn)) )
  348. {
  349. pmedium->hGlobal = GlobalAlloc(GPTR, sizeof(T));
  350. if( pmedium->hGlobal )
  351. {
  352. *((T *)pmedium->hGlobal) = m_data;
  353. hr = S_OK; // success
  354. }
  355. else
  356. {
  357. hr = E_OUTOFMEMORY;
  358. }
  359. }
  360. }
  361. return hr;
  362. }
  363. template <class T>
  364. /* [local] */
  365. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::GetDataHere(
  366. /* [unique][in] */ FORMATETC *pformatetc,
  367. /* [out][in] */ STGMEDIUM *pmedium)
  368. {
  369. // we don't implement this.
  370. return E_NOTIMPL;
  371. }
  372. template <class T>
  373. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::QueryGetData(
  374. /* [unique][in] */ FORMATETC *pformatetc)
  375. {
  376. HRESULT hr = E_UNEXPECTED;
  377. // try our data obejct first
  378. if( m_spDataObj )
  379. {
  380. hr = m_spDataObj->QueryGetData(pformatetc);
  381. }
  382. if( FAILED(hr) )
  383. {
  384. if( m_cfDataType == pformatetc->cfFormat )
  385. {
  386. if( TYMED_HGLOBAL & pformatetc->tymed )
  387. {
  388. // success
  389. hr = S_OK;
  390. }
  391. else
  392. {
  393. // invalid tymed
  394. hr = DV_E_TYMED;
  395. }
  396. }
  397. else
  398. {
  399. // invalid clipboard format
  400. hr = DV_E_CLIPFORMAT;
  401. }
  402. }
  403. return hr;
  404. }
  405. template <class T>
  406. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::GetCanonicalFormatEtc(
  407. /* [unique][in] */ FORMATETC *pformatectIn,
  408. /* [out] */ FORMATETC *pformatetcOut)
  409. {
  410. // always return the data in the same format
  411. return DATA_S_SAMEFORMATETC;
  412. }
  413. template <class T>
  414. /* [local] */
  415. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::SetData(
  416. /* [unique][in] */ FORMATETC *pformatetc,
  417. /* [unique][in] */ STGMEDIUM *pmedium,
  418. /* [in] */ BOOL fRelease)
  419. {
  420. HRESULT hr = E_INVALIDARG;
  421. // try our data obejct first
  422. if( m_spDataObj )
  423. {
  424. hr = m_spDataObj->SetData(pformatetc, pmedium, fRelease);
  425. }
  426. if( FAILED(hr) )
  427. {
  428. hr = QueryGetData(pformatetc);
  429. if( SUCCEEDED(hr) && FAILED(m_spDataObj->QueryGetData(pformatetc)) )
  430. {
  431. if( pmedium->hGlobal )
  432. {
  433. m_data = *((T *)pmedium->hGlobal);
  434. hr = S_OK; // success
  435. }
  436. else
  437. {
  438. hr = E_INVALIDARG;
  439. }
  440. }
  441. }
  442. return hr;
  443. }
  444. template <class T>
  445. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::EnumFormatEtc(
  446. /* [in] */ DWORD dwDirection,
  447. /* [out] */ IEnumFORMATETC **ppenumFormatEtc)
  448. {
  449. // we don't implement this.
  450. return E_NOTIMPL;
  451. }
  452. template <class T>
  453. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::DAdvise(
  454. /* [in] */ FORMATETC *pformatetc,
  455. /* [in] */ DWORD advf,
  456. /* [unique][in] */ IAdviseSink *pAdvSink,
  457. /* [out] */ DWORD *pdwConnection)
  458. {
  459. // we don't implement this.
  460. return OLE_E_ADVISENOTSUPPORTED;
  461. }
  462. template <class T>
  463. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::DUnadvise(
  464. /* [in] */ DWORD dwConnection)
  465. {
  466. // we don't implement this.
  467. return OLE_E_ADVISENOTSUPPORTED;
  468. }
  469. template <class T>
  470. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::EnumDAdvise(
  471. /* [out] */ IEnumSTATDATA **ppenumAdvise)
  472. {
  473. // we don't implement this.
  474. return OLE_E_ADVISENOTSUPPORTED;
  475. }
  476. //////////////////
  477. // IDropSource
  478. //
  479. template <class T>
  480. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::QueryContinueDrag(
  481. /* [in] */ BOOL fEscapePressed,
  482. /* [in] */ DWORD grfKeyState)
  483. {
  484. // standard implementation
  485. HRESULT hr = S_OK;
  486. if( fEscapePressed )
  487. {
  488. hr = DRAGDROP_S_CANCEL;
  489. }
  490. if( !(grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)) )
  491. {
  492. hr = DRAGDROP_S_DROP;
  493. }
  494. return hr;
  495. }
  496. template <class T>
  497. HRESULT STDMETHODCALLTYPE CSimpleDataObjImpl<T>::GiveFeedback(
  498. /* [in] */ DWORD dwEffect)
  499. {
  500. // standard implementation
  501. return DRAGDROP_S_USEDEFAULTCURSORS;
  502. }
  503. // this namespace is a placeholder to put COM related helpers here
  504. namespace comhelpers
  505. {
  506. inline
  507. BOOL AreObjectsIdentical(IUnknown *punk1, IUnknown *punk2)
  508. {
  509. BOOL bRet = FALSE;
  510. if (NULL == punk1 && NULL == punk2)
  511. {
  512. // if both are NULL then we assume they are identical
  513. bRet = TRUE;
  514. }
  515. else
  516. {
  517. // one of them isn't NULL - we compare using the COM identity rules
  518. if (punk1 && punk2)
  519. {
  520. CRefPtrCOM<IUnknown> spUnk1, spUnk2;
  521. if (SUCCEEDED(punk1->QueryInterface(IID_IUnknown, (void**)&spUnk1)) &&
  522. SUCCEEDED(punk2->QueryInterface(IID_IUnknown, (void**)&spUnk2)))
  523. {
  524. bRet = (spUnk1 == spUnk2);
  525. }
  526. }
  527. }
  528. return bRet;
  529. }
  530. }