PropertyClass.h 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. #ifndef __PropertyClass_h__
  2. #define __PropertyClass_h__
  3. /////////////////////////////////////////////////////////////////////////////
  4. // PropertyClass.h | Declaration of the TCComPropertyClass template class.
  5. //
  6. #include <..\TCLib\ObjectLock.h>
  7. /////////////////////////////////////////////////////////////////////////////
  8. // TCComPropertyClassRoot
  9. /////////////////////////////////////////////////////////////////////////////
  10. // Description: Provides basic property persistence support.
  11. //
  12. // TCComPropertyClassRoot serves as the base class of TCComPropertyClass.
  13. // Since that class is a template, the portions of functionality that are not
  14. // affected by the template paramters are implemented in this class to avoid
  15. // duplicated code. See TCComPropertyClass for more information.
  16. //
  17. // See Also: TCComPropertyClass, TCComPropertyClass::CLoadSaveScope,
  18. // TCComPropertyPut, TCComPropertyGet
  19. class ATL_NO_VTABLE TCComPropertyClassRoot
  20. {
  21. // Construction
  22. public:
  23. #ifdef _DEBUG
  24. TCComPropertyClassRoot(LPCSTR pszType);
  25. #else // _DEBUG
  26. TCComPropertyClassRoot();
  27. #endif // _DEBUG
  28. // Attributes
  29. public:
  30. void SetDirty(BOOL bDirty);
  31. BOOL GetDirty() const;
  32. bool IsLoading();
  33. void SetLoading(bool bLoading);
  34. bool IsSaving();
  35. void SetSaving(bool bSaving);
  36. // Implementation
  37. public:
  38. HRESULT TCPersistStreamInit_Load(IStream* pStm, ATL_PROPMAP_ENTRY* pMap,
  39. void* pT, IUnknown* pUnk);
  40. HRESULT TCPersistStreamInit_Save(IStream* pStm, BOOL /* fClearDirty */,
  41. ATL_PROPMAP_ENTRY* pMap, void* pT, IUnknown* pUnk);
  42. HRESULT TCPersistPropertyBag_Load(IPropertyBag* pPropBag,
  43. LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap, void* pT, IUnknown* pUnk);
  44. HRESULT TCPersistPropertyBag_Save(IPropertyBag* pPropBag,
  45. BOOL fClearDirty, BOOL fSaveAllProperties, ATL_PROPMAP_ENTRY* pMap,
  46. void* pT, IUnknown* pUnk);
  47. HRESULT ISpecifyPropertyPages_GetPages(CAUUID* pPages,
  48. ATL_PROPMAP_ENTRY* pMap);
  49. // Group=Types
  50. protected:
  51. ///////////////////////////////////////////////////////////////////////////
  52. // Description: Nested class used to symetrically increment and decrement
  53. // an indicator of the object's save or load state.
  54. //
  55. // This class is used to symetrically increment and decrement an indicator
  56. // of an object's save or load state.
  57. //
  58. // See Also: TCComPropertyClassRoot
  59. class CLoadSaveScope
  60. {
  61. // Construction / Destruction
  62. public:
  63. CLoadSaveScope(TCComPropertyClassRoot* pObject, bool bLoading = true);
  64. ~CLoadSaveScope();
  65. // Group=Data Members
  66. protected:
  67. // The outer class instance on which this scoping object operates.
  68. TCComPropertyClassRoot* m_pObject;
  69. // Indicates whether this object is being used to enclose a load
  70. // operation, *true*, or a save operation, *false*.
  71. bool m_bLoading;
  72. };
  73. // Group=Data Members
  74. public:
  75. bool m_bRequiresSave:1; // The object's dirty flag.
  76. protected:
  77. #pragma pack(push, 4)
  78. long m_nLoadingRefs; // The number of nested load operations in progress.
  79. long m_nSavingRefs; // The number of nested save operations in progress.
  80. #pragma pack(pop)
  81. ///////////////////////////////////////////////////////////////////////////
  82. // Description: A COM interface pointer of type *IDataAdviseHolder*.
  83. //
  84. // Provides a standard means to hold advisory connections between data
  85. // objects and advise sinks. (A data object is an object that can transfer
  86. // data and that implements *IDataObject*, whose methods specify the format
  87. // and transfer medium of the data.)
  88. //
  89. // The interface m_spDataAdviseHolder implements the
  90. // *IDataObject::DAdvise* and *IDataObject::DUnadvise* methods to establish
  91. // and delete advisory connections to the object client. The object's
  92. // client must implement an advise sink by supporting the *IAdviseSink* „
  93. // interface.
  94. //
  95. // This data member is used by *ATL::IDataObjectImpl* to manage data
  96. // advisory connections.
  97. //
  98. // TODO: This is a carry-over from the *ATL::CComControl* code that was
  99. // copied when creating this class. To fully support the
  100. // *ATL::IDataObjectImpl* class, this class (or a derived class) would need
  101. // to implement an *IDataObject_GetData* method, which is called by the ATL
  102. // implementation of *IDataObject::GetData*.
  103. //
  104. // See Also: TCComPropertyClass::SendOnDataChange
  105. CComPtr<IDataAdviseHolder> m_spDataAdviseHolder;
  106. #ifdef _DEBUG
  107. // This is used under _DEBUG builds to point to the name of the
  108. // most-derived class, used for diagnostic purposes.
  109. LPCSTR m_pszType;
  110. #endif // _DEBUG
  111. };
  112. /////////////////////////////////////////////////////////////////////////////
  113. // Group=Construction / Destruction
  114. /////////////////////////////////////////////////////////////////////////////
  115. // Parameters:
  116. // pObject - The outer object on which this scoping object operates.
  117. // bLoading - Indicates whether this object is being used to enclose a load
  118. // operation, *true*, or a save operation, *false*.
  119. //
  120. // Remarks: Calls either the TCComPropertyClassRoot::SetLoading or the
  121. // TCComPropertyClassRoot::SetSaving method with a parameter of *true*,
  122. // which increments the reference count of /pObject/'s load or save
  123. // operations, repectively.
  124. //
  125. // See Also: TCComPropertyClassRoot::CLoadSaveScope::destructor,
  126. // TCComPropertyClassRoot, TCComPropertyClassRoot::SetLoading,
  127. // TCComPropertyClassRoot::SetSaving,
  128. inline TCComPropertyClassRoot::CLoadSaveScope::CLoadSaveScope(
  129. TCComPropertyClassRoot* pObject, bool bLoading) :
  130. m_pObject(pObject), m_bLoading(bLoading)
  131. {
  132. if (m_pObject)
  133. {
  134. if (m_bLoading)
  135. m_pObject->SetLoading(true);
  136. else
  137. m_pObject->SetSaving(true);
  138. }
  139. }
  140. /////////////////////////////////////////////////////////////////////////////
  141. // Calls either the TCComPropertyClassRoot::SetLoading or the
  142. // TCComPropertyClassRoot::SetSaving method with a parameter of *false*,
  143. // which decrements the reference count of /pObject/'s load or save
  144. // operations, repectively.
  145. //
  146. // See Also: TCComPropertyClassRoot::CLoadSaveScope::constructor,
  147. // TCComPropertyClassRoot, TCComPropertyClassRoot::SetLoading,
  148. // TCComPropertyClassRoot::SetSaving,
  149. inline TCComPropertyClassRoot::CLoadSaveScope::~CLoadSaveScope()
  150. {
  151. if (m_pObject)
  152. {
  153. if (m_bLoading)
  154. m_pObject->SetLoading(false);
  155. else
  156. m_pObject->SetSaving(false);
  157. }
  158. }
  159. /////////////////////////////////////////////////////////////////////////////
  160. // Group=
  161. /////////////////////////////////////////////////////////////////////////////
  162. // TCComFakeNotifySink declares a class that /looks/ like a connection point
  163. // class for the *IPropertyNotifySink* interface, in that it declares the
  164. // Fire_OnChanged and Fire_OnRequestEdit methods. However, these methods do
  165. // nothing.
  166. //
  167. // This class is used just so that a derived class can call the
  168. // *Fire_* methods, even when the class does not currently support the
  169. // *IPropertyNotifySink* connection point. Primarily, this class is specified
  170. // as the default /PNSCP/ template parameter of the TCComPropertyClass
  171. // template class. A class derived from TCComPropertyClass should specify
  172. // TCComPropertyNotifySinkCP for that parameter if it supports the
  173. // *IPropertyNotifySink* connection point.
  174. //
  175. // See Also: TCComPropertyClass, TCComPropertyNotifySink
  176. class TCComFakeNotifySink
  177. {
  178. public:
  179. void Fire_OnChanged(DISPID dispID) {UNUSED(dispID);} // {secret}
  180. void Fire_OnRequestEdit(DISPID dispID) {UNUSED(dispID);} // {secret}
  181. };
  182. /////////////////////////////////////////////////////////////////////////////
  183. // TCComPropertyClass
  184. /////////////////////////////////////////////////////////////////////////////
  185. // Description: Provides basic property persistence support.
  186. //
  187. // The ATL framework defines a class, CComControl, that provides support for
  188. // an object to have persistent properties through the ATL property map
  189. // macros and the *IPersist* interfaces. However, to get this support,
  190. // deriving from CComControl brings along a lot of overhead unnecessary for
  191. // many simple component objects that are not full ActiveX controls. To
  192. // alleviate this problem, the TCComPropertyClass provides the equivalent
  193. // support for property persistence, but without the unnecessary overhead of
  194. // CComControl.
  195. //
  196. // Include this class as a base class of component objects that use any of
  197. // the ATL persistence implementations, including *IPersistStreamInitImpl*,
  198. // *IPersistStorageImpl*, and *IPersistPropertyBagImpl*.
  199. //
  200. // Parameters:
  201. // T - Your class, derived from TCComPropertyClass.
  202. // PNSCP - The connection point class that is used to fire property change
  203. // notifications. By default, this is TCComFakeNotifySink, which implements
  204. // *Fire_OnChanged* and *Fire_OnRequestEdit* to do nothing. If a component
  205. // object supports the *IPropertyNotifySink* connection point, this parameter
  206. // should be TCComPropertyNotifySinkCP. The class specified by this parameter
  207. // is used as a base class of TCComPropertyClass, and is therefore also
  208. // inherited by /T/.
  209. //
  210. // See Also: TCPersistStreamInitImpl, TCComPropertyClassRoot,
  211. // TCComPropertyPut, TCComPropertyGet, TCComFakeNotifySink,
  212. // TCComPropertyNotifySinkCP
  213. template <class T, class PNSCP = TCComFakeNotifySink>
  214. class ATL_NO_VTABLE TCComPropertyClass :
  215. public TCComPropertyClassRoot,
  216. public PNSCP
  217. {
  218. // Construction / Destruction
  219. public:
  220. TCComPropertyClass();
  221. // Operations
  222. public:
  223. HRESULT FireOnChanged(DISPID dispID);
  224. HRESULT FireOnRequestEdit(DISPID dispID);
  225. HRESULT SendOnDataChange(DWORD advf = 0);
  226. // Overrides
  227. public:
  228. virtual HRESULT ControlQueryInterface(const IID& iid, void** ppv);
  229. // Group=Types
  230. public:
  231. // Declares a type definition to allow derived classes an easier way to
  232. // refer to the base class.
  233. typedef TCComPropertyClass<T, PNSCP> TCComPropertyClassBase;
  234. protected:
  235. // Declares an auto-scoping object used internally for thread
  236. // synchronization.
  237. typedef TCObjectLock<T> CLock;
  238. };
  239. /////////////////////////////////////////////////////////////////////////////
  240. // TCComPropertyClass Construction
  241. #ifdef _DEBUG
  242. ///////////////////////////////////////////////////////////////////////////
  243. // {group:Construction}
  244. // Constructs an instance of the class.
  245. template <class T, class PNSCP>
  246. inline TCComPropertyClass<T, PNSCP>::TCComPropertyClass()
  247. : TCComPropertyClassRoot(TCTypeName(T))
  248. {
  249. }
  250. #else
  251. template <class T, class PNSCP>
  252. inline TCComPropertyClass<T, PNSCP>::TCComPropertyClass()
  253. {
  254. }
  255. #endif // _DEBUG
  256. /////////////////////////////////////////////////////////////////////////////
  257. // Group=Operations
  258. /////////////////////////////////////////////////////////////////////////////
  259. // Description: Fires a property change notification to connected objects.
  260. //
  261. // This method calls the *Fire_OnChanged* method of the class specified by
  262. // the /PNSCP/ template parameter.
  263. //
  264. // This method is provided for compatibility with the ATL CComControl class
  265. // from which portions of this class were copied. It is used by the
  266. // TCComPropertyPut function template when a property has changed.
  267. //
  268. // Parameters:
  269. // dispid - [in] Dispatch identifier of the property that changed, or
  270. // *DISPID_UNKNOWN* if multiple properties have changed.
  271. //
  272. // Return Value: Currently, *S_OK* is always returned.
  273. //
  274. // See Also: TCComPropertyPut, TCComFakeNotifySink, TCComPropertyNotifySinkCP
  275. template <class T, class PNSCP>
  276. inline HRESULT TCComPropertyClass<T, PNSCP>::FireOnChanged(DISPID dispID)
  277. {
  278. // Delegate to the derived-class function
  279. static_cast<PNSCP*>(this)->Fire_OnChanged(dispID);
  280. return S_OK;
  281. }
  282. /////////////////////////////////////////////////////////////////////////////
  283. // Description: Fires a property change request to connected objects.
  284. //
  285. // This method calls the *Fire_OnRequestEdit* method of the class specified
  286. // by the /PNSCP/ template parameter.
  287. //
  288. // This method is provided for compatibility with the ATL CComControl class
  289. // from which portions of this class were copied. It is intended to be used
  290. // by the TCComPropertyPut function template when a property is about to be
  291. // changed. However, that function does not currently call this method, since
  292. // it currently always returns *S_OK*.
  293. //
  294. // Parameters:
  295. // dispid - [in] Dispatch identifier of the property that is about to
  296. // change or *DISPID_UNKNOWN* if multiple properties are about to change.
  297. //
  298. // Return Value: Currently, *S_OK* is always returned.
  299. //
  300. // See Also: TCComPropertyPut, TCComFakeNotifySink, TCComPropertyNotifySinkCP
  301. template <class T, class PNSCP>
  302. inline HRESULT TCComPropertyClass<T, PNSCP>::FireOnRequestEdit(DISPID dispID)
  303. {
  304. // Delegate to the derived-class function
  305. static_cast<PNSCP*>(this)->Fire_OnRequestEdit(dispID);
  306. return S_OK;
  307. }
  308. /////////////////////////////////////////////////////////////////////////////
  309. // Description: Called by the object to notify the connected advise sinks
  310. // that data in the object has changed.
  311. //
  312. // Notifies all advisory sinks registered with the advise holder that the
  313. // object data has changed.
  314. //
  315. // TODO: This is a carry-over from the *ATL::CComControl* code that was
  316. // copied when creating this class. To fully support the
  317. // *ATL::IDataObjectImpl* class, this class (or a derived class) would need
  318. // to implement an *IDataObject_GetData* method, which is called by the ATL
  319. // implementation of *IDataObject::GetData*.
  320. //
  321. // Parameters:
  322. // advf - [in] Advise flags that specify how the call to
  323. // *IAdviseSink::OnDataChange* is made. Values are from the
  324. // *ADVF* enumeration.
  325. //
  326. // See Also: TCComPropertyClassRoot::m_spDataAdviseHolder
  327. template <class T, class PNSCP>
  328. HRESULT TCComPropertyClass<T, PNSCP>::SendOnDataChange(DWORD advf)
  329. {
  330. HRESULT hRes = S_OK;
  331. if (m_spDataAdviseHolder)
  332. {
  333. CComPtr<IDataObject> pdo;
  334. if (SUCCEEDED(ControlQueryInterface(IID_IDataObject, (void**)&pdo)))
  335. hRes = m_spDataAdviseHolder->SendOnDataChange(pdo, 0, advf);
  336. }
  337. return hRes;
  338. }
  339. /////////////////////////////////////////////////////////////////////////////
  340. // Group=Overrides
  341. /////////////////////////////////////////////////////////////////////////////
  342. // TCComPropertyClass implements this by calling the _InternalQueryInterface
  343. // method of the derived class, /T/.
  344. template <class T, class PNSCP>
  345. HRESULT TCComPropertyClass<T, PNSCP>::ControlQueryInterface(const IID& iid,
  346. void** ppv)
  347. {
  348. T* pT = static_cast<T*>(this);
  349. return pT->_InternalQueryInterface(iid, ppv);
  350. }
  351. /////////////////////////////////////////////////////////////////////////////
  352. // Group=
  353. /////////////////////////////////////////////////////////////////////////////
  354. // TCPersistStreamInitImpl extends ATL's IPersistStreamInitImpl class to
  355. // provide an implementation of the *IPersistStreamInit::GetSizeMax* „
  356. // interface method.
  357. //
  358. // Parameters:
  359. // T - The class derived from TCPersistStreamInitImpl.
  360. //
  361. template <class T>
  362. class ATL_NO_VTABLE TCPersistStreamInitImpl :
  363. public IPersistStreamInit
  364. {
  365. // Group=Types
  366. public:
  367. // Declares a type definition to allow derived classes an easier way to
  368. // refer to the base class.
  369. typedef TCPersistStreamInitImpl<T> TCPersistStreamInitImplBase;
  370. // Group=IPersist Interface Methods
  371. public:
  372. STDMETHODIMP GetClassID(CLSID *pClassID);
  373. // Group=IPersistStream Interface Methods
  374. public:
  375. STDMETHODIMP IsDirty();
  376. STDMETHODIMP Load(IStream* pStm);
  377. STDMETHODIMP Save(IStream* pStm, BOOL fClearDirty);
  378. STDMETHODIMP GetSizeMax(ULARGE_INTEGER* pcbSize);
  379. // Group=IPersistStreamInit Interface Methods
  380. public:
  381. STDMETHODIMP InitNew();
  382. };
  383. /////////////////////////////////////////////////////////////////////////////
  384. // Group=IPersist Interface Methods
  385. template <class T>
  386. STDMETHODIMP TCPersistStreamInitImpl<T>::GetClassID(CLSID *pClassID)
  387. {
  388. _TRACE0("TCPersistStreamInitImpl<T>::GetClassID\n");
  389. *pClassID = T::GetObjectCLSID();
  390. return S_OK;
  391. }
  392. /////////////////////////////////////////////////////////////////////////////
  393. // Group=IPersistStream Interface Methods
  394. template <class T>
  395. STDMETHODIMP TCPersistStreamInitImpl<T>::IsDirty()
  396. {
  397. _TRACE0("TCPersistStreamInitImpl<T>::IsDirty\n");
  398. T* pT = static_cast<T*>(this);
  399. return (pT->m_bRequiresSave) ? S_OK : S_FALSE;
  400. }
  401. template <class T>
  402. STDMETHODIMP TCPersistStreamInitImpl<T>::Load(IStream* pStm)
  403. {
  404. _TRACE0("TCPersistStreamInitImpl<T>::Load\n");
  405. T* pT = static_cast<T*>(this);
  406. return pT->TCPersistStreamInit_Load(pStm, T::GetPropertyMap(), pT,
  407. pT->GetUnknown());
  408. }
  409. template <class T>
  410. STDMETHODIMP TCPersistStreamInitImpl<T>::Save(IStream* pStm, BOOL fClearDirty)
  411. {
  412. T* pT = static_cast<T*>(this);
  413. _TRACE0("TCPersistStreamInitImpl<T>::Save\n");
  414. return pT->TCPersistStreamInit_Save(pStm, fClearDirty, T::GetPropertyMap(),
  415. pT, pT->GetUnknown());
  416. }
  417. /////////////////////////////////////////////////////////////////////////////
  418. // Group=
  419. /////////////////////////////////////////////////////////////////////////////
  420. // Description: Returns the size, in bytes, of the stream needed to save the
  421. // object.
  422. //
  423. // This function implements the *IPersistStreamInit::GetSizeMax* interface
  424. // method by calling the TCGetPersistStreamSize global function.
  425. //
  426. // Parameters:
  427. // pCbSize - [out] Points to a 64-bit unsigned integer value indicating the
  428. // size in bytes of the stream needed to save this object.
  429. //
  430. // Return Value: *S_OK* indicates that the size was successfully returned.
  431. //
  432. // See Also: TCNullStream, CTCNullStream
  433. template <class T>
  434. STDMETHODIMP TCPersistStreamInitImpl<T>::GetSizeMax(ULARGE_INTEGER* pcbSize)
  435. {
  436. // Get the derived class pointer
  437. T* pThis = static_cast<T*>(this);
  438. // Determine the max size by writing to a null stream
  439. HRESULT hr = TCGetPersistStreamSize(pThis->GetUnknown(), pcbSize);
  440. // Display trace information under _DEBUG builds
  441. _TRACE_BEGIN
  442. _TRACE_PART1("TCPersistStreamInitImpl<%hs>::GetSizeMax():", TCTypeName(T));
  443. if (SUCCEEDED(hr))
  444. _TRACE_PART2("Counted 0x%08X (%d) bytes\n", pcbSize->LowPart, pcbSize->LowPart);
  445. else
  446. _TRACE_PART1("Failed, hr = 0x%08X\n", hr);
  447. _TRACE_END
  448. // Return the last HRESULT
  449. return hr;
  450. }
  451. /////////////////////////////////////////////////////////////////////////////
  452. // Group=IPersistStreamInit Interface Methods
  453. template <class T>
  454. STDMETHODIMP TCPersistStreamInitImpl<T>::InitNew()
  455. {
  456. _TRACE0("TCPersistStreamInitImpl<T>::InitNew\n");
  457. T* pT = static_cast<T*>(this);
  458. pT->SetDirty(false);
  459. return S_OK;
  460. }
  461. /////////////////////////////////////////////////////////////////////////////
  462. // Group=
  463. /////////////////////////////////////////////////////////////////////////////
  464. // TCPersistPropertyBagImpl
  465. //
  466. //
  467. // Parameters:
  468. // T - The class derived from TCPersistPropertyBagImpl
  469. //
  470. template <class T>
  471. class ATL_NO_VTABLE TCPersistPropertyBagImpl :
  472. public IPersistPropertyBag
  473. {
  474. // Group=IPersist Interface Methods
  475. public:
  476. STDMETHODIMP GetClassID(CLSID *pClassID);
  477. // Group=IPersistPropertyBag Interface Methods
  478. public:
  479. STDMETHODIMP InitNew();
  480. STDMETHODIMP Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog);
  481. STDMETHODIMP Save(IPropertyBag* pPropBag, BOOL fClearDirty,
  482. BOOL fSaveAllProperties);
  483. };
  484. /////////////////////////////////////////////////////////////////////////////
  485. // Group=IPersist Interface Methods
  486. template <class T>
  487. STDMETHODIMP TCPersistPropertyBagImpl<T>::GetClassID(CLSID *pClassID)
  488. {
  489. _TRACE0("IPersistPropertyBagImpl::GetClassID\n");
  490. *pClassID = T::GetObjectCLSID();
  491. return S_OK;
  492. }
  493. /////////////////////////////////////////////////////////////////////////////
  494. // Group=IPersistPropertyBag Interface Methods
  495. template <class T>
  496. STDMETHODIMP TCPersistPropertyBagImpl<T>::InitNew()
  497. {
  498. _TRACE0("IPersistPropertyBagImpl::InitNew\n");
  499. T* pT = static_cast<T*>(this);
  500. pT->SetDirty(false);
  501. return S_OK;
  502. }
  503. template <class T>
  504. STDMETHODIMP TCPersistPropertyBagImpl<T>::Load(IPropertyBag* pPropBag,
  505. IErrorLog* pErrorLog)
  506. {
  507. _TRACE0("IPersistPropertyBagImpl::Load\n");
  508. T* pT = static_cast<T*>(this);
  509. ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  510. ATLASSERT(pMap != NULL);
  511. return pT->TCPersistPropertyBag_Load(pPropBag, pErrorLog, pMap, pT,
  512. pT->GetUnknown());
  513. }
  514. template <class T>
  515. STDMETHODIMP TCPersistPropertyBagImpl<T>::Save(IPropertyBag* pPropBag,
  516. BOOL fClearDirty, BOOL fSaveAllProperties)
  517. {
  518. _TRACE0("IPersistPropertyBagImpl::Save\n");
  519. T* pT = static_cast<T*>(this);
  520. ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  521. ATLASSERT(pMap != NULL);
  522. return pT->TCPersistPropertyBag_Save(pPropBag, fClearDirty,
  523. fSaveAllProperties, pMap, pT, pT->GetUnknown());
  524. }
  525. /////////////////////////////////////////////////////////////////////////////
  526. // Group=
  527. /////////////////////////////////////////////////////////////////////////////
  528. // Property Exchange
  529. /////////////////////////////////////////////////////////////////////////////
  530. // Description: Compares two values.
  531. //
  532. // This template function is used by the TCComPropertyPut functions to
  533. // compare the two values, /dest/ and /src/. The default template function
  534. // uses the global operator== to perform the comparison. Template
  535. // specializations, however, are provided for the following type pairs:
  536. //
  537. // + *bool* to *VARIANT_BOOL* „
  538. // + *DATE* to *COleDateTime* (MFC Only)
  539. // + *CComVariant* to *VARIANT* „
  540. // + *CComBSTR* to *BSTR* „
  541. //
  542. // Parameters:
  543. // dest - A reference to the variable on the left-hand side of the
  544. // comparison.
  545. // src - A reference to the variable on the right-hand side of the
  546. // comparison.
  547. //
  548. // Return Value: *true* if the arguments are equal, otherwise *false*.
  549. //
  550. // See Also: TCComPropertyPut, TCComVariantCompare, TCComPropertyAssign,
  551. // TCComPropertyInit
  552. template <class Dest, class Src>
  553. inline bool TCComPropertyCompare(Dest& dest, Src& src)
  554. {
  555. return !!(dest == src);
  556. }
  557. /////////////////////////////////////////////////////////////////////////////
  558. // Description: Initializes a value.
  559. //
  560. // This template function is used by the TCComPropertyPut
  561. // and TCComPropertyGet functions to initialize a value to a known state. The
  562. // default template function simply initializes the specified value to zero,
  563. // type cast to the type of /dest./ A template specialization, however, is
  564. // provided for the following type:
  565. //
  566. // + *VARIANT* - Initialized with the Win32 *VariantInit* API.
  567. //
  568. // Parameters:
  569. // dest - A reference to the variable to be initialized.
  570. //
  571. // See Also: TCComPropertyPut, TCComPropertyGet, TCComPropertyAssign,
  572. // TCComPropertyCompare
  573. template <class Dest>
  574. inline void TCComPropertyInit(Dest& dest)
  575. {
  576. dest = (Dest)0;
  577. }
  578. /////////////////////////////////////////////////////////////////////////////
  579. // Description: Assigns the specified value to a variable.
  580. //
  581. // This template function is used by the TCComPropertyPut and
  582. // TCComPropertyGet functions to assign a value to a variable. The default
  583. // template function simply performs the assignment using the global
  584. // assignment operator=. Template specializations, however, are provided for
  585. // the following type pairs:
  586. //
  587. // + *bool* from *VARIANT_BOOL* „
  588. // + *VARIANT_BOOL* from *bool* „
  589. // + *VARIANT* from *VARIANT* - Uses the Win32 *VariantCopy* API.
  590. // + *SAFEARRAY* * from *SAFEARRAY* * - Uses the Win32 *SafeArrayCopy* API.
  591. // + *BSTR* from *BSTR* - Uses the Win32 *SysReAllocString* API.
  592. // + *BSTR* from *CComBSTR* „
  593. // + *VARIANT* from *COleVariant* (MFC only)
  594. // + *VARIANT* from *COleSafeArray* (MFC only)
  595. // + *VARIANT* from *CComVariant* „
  596. //
  597. // Parameters:
  598. // dest - A reference to the variable to be assigned the value of /src/.
  599. // src - A reference to the variable whose value will be assigned to
  600. // /dest/.
  601. //
  602. // Return Value:
  603. // *S_OK* if the function succeeded, otherwise an appropriated error code.
  604. //
  605. // See Also: TCComPropertyPut, TCComPropertyGet, TCComPropertyInit,
  606. // TCComPropertyCompare
  607. template <class Dest, class Src>
  608. inline HRESULT TCComPropertyAssign(Dest& dest, Src& src)
  609. {
  610. dest = src;
  611. return S_OK;
  612. }
  613. /////////////////////////////////////////////////////////////////////////////
  614. // Description: Provides a standard implementation for [propput] methods.
  615. //
  616. // Use this method when implementing the [propput] methods of a component
  617. // object interface.
  618. //
  619. // Properties are declared in a component object interface as methods with
  620. // the [propput] or [propget] IDL attributes. The resulting interface method
  621. // is named by prefixing *put_* or *get_*, respectively, to the property
  622. // name. Consider the following interface definition:
  623. //
  624. // // IMyInterface Interface
  625. // [
  626. // object, dual, pointer_default(unique),
  627. // uuid(E4DE3C70-21B7-11d2-97D4-00A0C932A52F),
  628. // helpstring("IMyInterface example interface with a property.")
  629. // ]
  630. // interface IMyInterface : IDispatch
  631. // {
  632. // [propput, helpstring("Sets/gets the Enabled property.")]
  633. // HRESULT Enabled([in] VARIANT_BOOL bEnabled);
  634. // …
  635. // [propget, id(DISPID_ENABLED)]
  636. // HRESULT Enabled([out, retval] VARIANT_BOOL* pbEnabled);
  637. // …
  638. // }; // End: interface IMyInterface : IDispatch
  639. //
  640. // In this example, the *IMyInterface* interface has one property, *Enabled*,
  641. // that can be set [propput] and queried [propget]. The declarations for this
  642. // property in a component object class that implements *IMyInterface* would
  643. // be similar to the following:
  644. //
  645. // // IMyInterface Interface Methods
  646. // public:
  647. // STDMETHODIMP put_Enabled(VARIANT_BOOL bEnabled);
  648. // STDMETHODIMP get_Enabled(VARIANT_BOOL* pbEnabled);
  649. //
  650. // In addition, the object would usually need to store the property as a data
  651. // member:
  652. //
  653. // // Data Members
  654. // protected:
  655. // bool m_bEnabled;
  656. //
  657. // Now, while implementing the *put_Enabled* and *get_Enabled* interface
  658. // methods is certainly not rocket science, several considerations come to
  659. // mind:
  660. //
  661. // + To synchronize access to the /m_bEnabled/ data member from multiple
  662. // threads, the object's *Lock* method should be called prior to accessing
  663. // the data member and the *Unlock* method called following.
  664. // + When the *put_Enabled* method changes the /m_bEnabled/ data member, a
  665. // property change notification should be fired, if the object supports the
  666. // *IPropertyNotifySink* connection point. This event should be fired
  667. // /after/ the object's *Unlock* method is called to avoid a possible
  668. // deadlock situation in free threaded component objects.
  669. // + If the /bEnabled/ parameter of *put_Enabled* specifies a value
  670. // equivalent to the value stored in the /m_bEnabled/ data member, the
  671. // object's dirty flag should not be set, nor should the object fire a
  672. // property change notification.
  673. // + While the *put_Enabled* and *get_Enabled* property methods have
  674. // parameters of type *VARIANT_BOOL* to match the IDL definition, the
  675. // /m_bEnabled/ data member is of type *bool*, which serves as a more natural
  676. // (and possibly compact) representation in C++.
  677. // + The /pbEnabled/ parameter of *get_Enabled* could be an invalid pointer.
  678. // Enclosing the code that accesses it in an exception handler would make the
  679. // object very robust since, instead of crashing, the method could return the
  680. // standard error value, *E_POINTER*.
  681. //
  682. // Since these same considerations apply for the implementation of almost
  683. // every interface property, the TCComPropertyPut and TCComPropertyGet
  684. // template functions were developed to encapsulate this coding pattern. All
  685. // of the considerations listed above are taken care of with the following
  686. // implementation of the property methods:
  687. //
  688. // // IMyInterface Interface Methods
  689. // …
  690. // STDMETHODIMP CMyClass::put_Enabled(VARIANT_BOOL bEnabled)
  691. // {
  692. // return TCComPropertyPut(this, m_bEnabled, bEnabled, DISPID_Enabled);
  693. // }
  694. // …
  695. // STDMETHODIMP CMyClass::get_Enabled(VARIANT_BOOL* pbEnabled)
  696. // {
  697. // return TCComPropertyGet(this, pbEnabled, m_bEnabled);
  698. // }
  699. //
  700. // The template functions rely heavily on the use of the TCComPropertyInit,
  701. // TCComPropertyAssign, and TCComPropertyCompare function templates. This
  702. // provides the flexibility to initialize, assign, and compare values of
  703. // varied types through function template specializations. Each of these
  704. // helper function templates have a default implementation that use either
  705. // the assignment operator or the equality operator, which may be overloaded
  706. // for a particular pair of types. Also, specializations are provided for
  707. // these function templates that perform the appropriate action based on
  708. // specific parameter types. For example, TCComPropertyAssign has the
  709. // following template specialization to allow the assignment of a *bool* data
  710. // member to a *VARIANT_BOOL* [out] parameter (as in the
  711. // *get_Enabled* example above):
  712. //
  713. // template <> inline
  714. // HRESULT TCComPropertyAssign<VARIANT_BOOL, bool>(VARIANT_BOOL& dest,
  715. // bool& src)
  716. // {
  717. // dest = (src ? VARIANT_TRUE : VARIANT_FALSE);
  718. // return S_OK;
  719. // }
  720. //
  721. // Parameters:
  722. // pThis - [in] A pointer to the object that owns the data member specified
  723. // by the /dest/ parameter. This object must provide the following
  724. // public methods: *Lock*, *Unlock*, and *SetDirty*. When the second form of
  725. // this function is used, this object must also provide the *FireOnChanged* „
  726. // public method. It is recommended that this class be derived from
  727. // TCComPropertyClass, since it provides all of these methods.
  728. // dest - [in, out] A reference to the data member (of the class referenced
  729. // by /pThis/) that is used to store the property value specified by /src/.
  730. // src - [in] A reference to the variable whose value is to be assigned to
  731. // the data member specified by the /dest/ parameter. Typically, the [in]
  732. // parameter of the [propput] method is specified here.
  733. // pbChanged - [out] A pointer to a *bool* variable that receives the
  734. // outcome of this function. *true* indicates that /dest/ was not equal to
  735. // /src/ so /dest/ was changed. *false* indicates that /dest/ was already
  736. // equal to /src/ so it did not change (and the *SetDirty* method of
  737. // /pThis/ was *not* called). This parameter can be *NULL*, indicating that
  738. // the outcome is not needed by the caller.
  739. //
  740. // See Also: TCComPropertyGet, TCComPropertyClass, TCObjectLock,
  741. // TCComPropertyCompare, TCComPropertyInit, TCComPropertyAssign
  742. template <class T, class Dest, class Src>
  743. HRESULT TCComPropertyPut(T* pThis, Dest& dest, Src& src,
  744. bool* pbChanged = NULL)
  745. {
  746. assert(NULL != pThis);
  747. bool bLocked = false;
  748. HRESULT hr = S_OK;
  749. __try
  750. {
  751. // Initialize the indicator, if specified
  752. if (NULL != pbChanged)
  753. *pbChanged = false;
  754. // lock the object
  755. pThis->Lock();
  756. bLocked = true;
  757. // Do nothing if new value is equal to the current value
  758. if (!TCComPropertyCompare(dest, src))
  759. {
  760. // Save the new value
  761. hr = TCComPropertyAssign(dest, src);
  762. if (SUCCEEDED(hr))
  763. {
  764. // Set the modified flag
  765. pThis->SetDirty(TRUE);
  766. // Indicate that the stored value changed
  767. if (NULL != pbChanged)
  768. *pbChanged = true;
  769. }
  770. }
  771. }
  772. __except(1)
  773. {
  774. _TRACE0("TCComPropertyPut(): Caught an unknown exception ");
  775. _TRACE0("(probably an invalid pointer was specified)");
  776. hr = E_POINTER;
  777. }
  778. // Unlock the object if we locked it
  779. if (bLocked)
  780. pThis->Unlock();
  781. // Return the last result
  782. return hr;
  783. }
  784. /////////////////////////////////////////////////////////////////////////////
  785. // Parameters:
  786. // dispid - Specifies the dispatch identifier to be used in a call to
  787. // *FireOnChanged*, which notifies objects connected to the
  788. // *IPropertyNotifySink* connection point of the property change.
  789. template <class T, class Dest, class Src>
  790. HRESULT TCComPropertyPut(T* pThis, Dest& dest, Src& src, DISPID dispid,
  791. bool* pbChanged = NULL)
  792. {
  793. __try
  794. {
  795. bool bChanged;
  796. HRESULT hr = TCComPropertyPut(pThis, dest, src, &bChanged);
  797. if (bChanged)
  798. pThis->FireOnChanged(dispid);
  799. if (pbChanged)
  800. *pbChanged = bChanged;
  801. return hr;
  802. }
  803. __except(1)
  804. {
  805. _TRACE0("TCComPropertyPut(): Caught an unknown exception\n");
  806. return E_UNEXPECTED;
  807. }
  808. }
  809. /////////////////////////////////////////////////////////////////////////////
  810. // Description: Provides a standard implementation for [propget] methods.
  811. //
  812. // Use this method when implementing the [propget] methods of a component
  813. // object interface.
  814. //
  815. // See TCComPropertyPut for information on how to use this function template.
  816. //
  817. // Parameters:
  818. // pThis - [in] A pointer to the object that owns the data member specified
  819. // by the /src/ parameter. This object must provide the following
  820. // public methods: *Lock* and *Unlock*. It is recommended that the class be
  821. // derived from TCComPropertyClass, since it provides those methods.
  822. // pDest - [out] A pointer to the variable to be assigned the value of the
  823. // data member specified by /src/. Typically, the [out, retval] parameter of
  824. // the [propget] method is specified here.
  825. // src - [in] A reference to the data member (of the class referenced by
  826. // /pThis/) whose value is assigned to the variable specified by /pDest/.
  827. // bLock - [in] Specifies if the assignment operation should be done while
  828. // the object is locked. The default, *true*, indicates that the *Lock* method
  829. // of the class referenced by /pThis/ will be called prior to the assignment,
  830. // and *Unlock* will be called afterward. If *false*, the object will not be
  831. // locked for the assignment.
  832. //
  833. // See Also: TCComPropertyPut, TCObjectLock, TCComPropertyInit,
  834. // TCComPropertyAssign
  835. template <class T, class Dest, class Src>
  836. HRESULT TCComPropertyGet(T* pThis, Dest* pDest, Src& src, bool bLock = true)
  837. {
  838. assert(NULL != pThis);
  839. bool bLocked = false;
  840. HRESULT hr = S_OK;
  841. __try
  842. {
  843. // Lock the object
  844. if (bLock)
  845. {
  846. pThis->Lock();
  847. bLocked = true;
  848. }
  849. // Initialize the [out] parameter
  850. TCComPropertyInit(*pDest);
  851. // Copy the value to the [out] parameter
  852. hr = TCComPropertyAssign(*pDest, src);
  853. }
  854. __except(1)
  855. {
  856. _TRACE_BEGIN
  857. _TRACE_PART0("TCComPropertyGet(): Caught an unknown exception ");
  858. _TRACE_PART0("(probably an invalid pointer was specified)");
  859. _TRACE_END
  860. hr = E_POINTER;
  861. }
  862. // Unlock the object if we locked it
  863. if (bLocked)
  864. pThis->Unlock();
  865. // Return the last result
  866. return hr;
  867. }
  868. /////////////////////////////////////////////////////////////////////////////
  869. // Special cases for conversion to/from bool and VARIANT_BOOL
  870. template <> inline
  871. bool TCComPropertyCompare<bool, VARIANT_BOOL>(bool& dest, VARIANT_BOOL& src)
  872. {
  873. return dest == !!src;
  874. }
  875. template <> inline
  876. HRESULT TCComPropertyAssign<bool, VARIANT_BOOL>(bool& dest, VARIANT_BOOL& src)
  877. {
  878. dest = !!src;
  879. return S_OK;
  880. }
  881. template <> inline
  882. HRESULT TCComPropertyAssign<VARIANT_BOOL, bool>(VARIANT_BOOL& dest, bool& src)
  883. {
  884. dest = (src ? VARIANT_TRUE : VARIANT_FALSE);
  885. return S_OK;
  886. }
  887. /////////////////////////////////////////////////////////////////////////////
  888. // Special cases for conversion to/from DATE types
  889. #ifdef _AFX
  890. template <> inline
  891. bool TCComPropertyCompare<DATE, COleDateTime>(DATE& dest, COleDateTime& src)
  892. {
  893. COleDateTime destDate(dest);
  894. return (destDate == src)?true:false;
  895. }
  896. #endif // _AFX
  897. /////////////////////////////////////////////////////////////////////////////
  898. // Special cases for conversion to/from VARIANT types
  899. template <>
  900. inline void TCComPropertyInit<VARIANT>(VARIANT& dest)
  901. {
  902. VariantInit(&dest);
  903. }
  904. template <> inline
  905. HRESULT TCComPropertyAssign<VARIANT, VARIANT>(VARIANT& dest, VARIANT& src)
  906. {
  907. RETURN_FAILED(VariantCopy(&dest, const_cast<VARIANT*>(&src)));
  908. if (NULL == V_ARRAY(&dest) && (VT_ARRAY & V_VT(&dest)))
  909. VariantClear(&dest);
  910. return S_OK;
  911. }
  912. #ifdef _ATL
  913. bool TCComVariantCompare(CComVariant& dest, VARIANT& src);
  914. template <>
  915. inline bool TCComPropertyCompare<CComVariant, VARIANT>(CComVariant& dest,
  916. VARIANT& src)
  917. {
  918. return TCComVariantCompare(dest, src);
  919. }
  920. #endif // _ATL
  921. /////////////////////////////////////////////////////////////////////////////
  922. // Special cases for conversion to/from SAFEARRAY types
  923. template <>
  924. inline HRESULT TCComPropertyAssign<SAFEARRAY*, SAFEARRAY*>(SAFEARRAY*& dest,
  925. SAFEARRAY*& src)
  926. {
  927. return SafeArrayCopy(const_cast<SAFEARRAY*>(src), &dest);
  928. }
  929. /////////////////////////////////////////////////////////////////////////////
  930. // Special cases for conversion to/from BSTR types
  931. template <>
  932. inline bool TCComPropertyCompare<CComBSTR, BSTR>(CComBSTR& dest, BSTR& src)
  933. {
  934. if (NULL == BSTR(dest))
  935. return NULL == src;
  936. else
  937. return (NULL == src) ? false : !wcscmp(dest, src);
  938. }
  939. template <>
  940. inline HRESULT TCComPropertyAssign<BSTR, BSTR>(BSTR& dest, BSTR& src)
  941. {
  942. return SysReAllocString(&dest, src);
  943. }
  944. template <>
  945. inline HRESULT TCComPropertyAssign<BSTR, CComBSTR>(BSTR& dest, CComBSTR& src)
  946. {
  947. dest = src.Copy();
  948. return S_OK;
  949. }
  950. /////////////////////////////////////////////////////////////////////////////
  951. // Special cases for conversion to/from MFC types
  952. #ifdef _AFX
  953. template <>
  954. inline HRESULT TCComPropertyAssign<VARIANT, COleVariant>(VARIANT& dest,
  955. COleVariant& src)
  956. {
  957. return TCComPropertyAssign(dest, VARIANT(src));
  958. }
  959. template <>
  960. inline HRESULT TCComPropertyAssign<VARIANT, COleSafeArray>(VARIANT& dest,
  961. COleSafeArray& src)
  962. {
  963. return TCComPropertyAssign(dest, VARIANT(src));
  964. }
  965. #endif // _AFX
  966. /////////////////////////////////////////////////////////////////////////////
  967. // Special cases for conversion to/from built-in types
  968. #ifdef _ATL
  969. template <>
  970. inline HRESULT TCComPropertyAssign<VARIANT, CComVariant>(VARIANT& dest,
  971. CComVariant& src)
  972. {
  973. return TCComPropertyAssign(dest, VARIANT(src));
  974. }
  975. #endif // _ATL
  976. /////////////////////////////////////////////////////////////////////////////
  977. #endif // __MMACAtl_h__