PropertyClass.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  1. #ifndef __PropertyClass_cpp__
  2. #define __PropertyClass_cpp__
  3. /////////////////////////////////////////////////////////////////////////////
  4. // PropertyClass.cpp | Implementation of the TCComPropertyClassRoot class.
  5. //
  6. #include "PropertyClass.h"
  7. /////////////////////////////////////////////////////////////////////////////
  8. // TCComPropertyClassRoot
  9. /////////////////////////////////////////////////////////////////////////////
  10. // Construction
  11. #ifdef _DEBUG
  12. ///////////////////////////////////////////////////////////////////////////
  13. // {group:Construction}
  14. // Parameters:
  15. // pszType - The class name of the most-derived class, used only for
  16. // diagnostic purposes. This parameter only exists under _DEBUG builds
  17. TCComPropertyClassRoot::TCComPropertyClassRoot(LPCSTR pszType)
  18. : m_nLoadingRefs(0), m_nSavingRefs(0), m_bRequiresSave(FALSE),
  19. m_pszType(pszType)
  20. {
  21. }
  22. #endif // _DEBUG
  23. #ifndef _DEBUG
  24. TCComPropertyClassRoot::TCComPropertyClassRoot()
  25. : m_nLoadingRefs(0), m_nSavingRefs(0), m_bRequiresSave(FALSE)
  26. {
  27. }
  28. #endif // !_DEBUG
  29. /////////////////////////////////////////////////////////////////////////////
  30. // Group=Attributes
  31. /////////////////////////////////////////////////////////////////////////////
  32. // Description: Sets or clears the object's dirty flag.
  33. //
  34. // Sets or clears the object's dirty flag.
  35. //
  36. // Parameters:
  37. // bDirty - *TRUE* to set the object's dirty flag, *FALSE* to clear it.
  38. //
  39. // See Also: TCComPropertyClassRoot::GetDirty,
  40. // TCComPropertyClassRoot::m_bRequiresSave
  41. void TCComPropertyClassRoot::SetDirty(BOOL bDirty)
  42. {
  43. m_bRequiresSave = 0 != bDirty;
  44. }
  45. /////////////////////////////////////////////////////////////////////////////
  46. // Description: Gets the current state of the object's dirty flag.
  47. //
  48. // Gets the current state of the object's dirty flag.
  49. //
  50. // Return Value: *TRUE* if the object needs to be saved, otherwise *FALSE*.
  51. //
  52. // See Also: TCComPropertyClassRoot::SetDirty,
  53. // TCComPropertyClassRoot::m_bRequiresSave
  54. BOOL TCComPropertyClassRoot::GetDirty() const
  55. {
  56. return m_bRequiresSave ? TRUE : FALSE;
  57. }
  58. /////////////////////////////////////////////////////////////////////////////
  59. // Description: Returns the object's current persistence load state.
  60. //
  61. // Determines if the object is currently being loaded from a persistence
  62. // mechanism.
  63. //
  64. // Return Value: *true* if the object is being loaded from a persistence
  65. // mechanism, otherwise *false*.
  66. //
  67. // See Also: TCComPropertyClassRoot::SetLoading,
  68. // TCComPropertyClassRoot::IsSaving, TCComPropertyClassRoot::CLoadSaveScope
  69. bool TCComPropertyClassRoot::IsLoading()
  70. {
  71. return m_nLoadingRefs != 0;
  72. }
  73. /////////////////////////////////////////////////////////////////////////////
  74. // Description: Sets or clears the object's current persistence load state.
  75. //
  76. // Sets or clears the object's current persistence state. Actually, since
  77. // loading from a persistence mechanism may be nested into several levels,
  78. // this method only increments or decrements a reference count of load
  79. // operations. Typically, this method is only used internally by the
  80. // TCComPropertyClassRoot::CLoadSaveScope class. Usually, there is no reason
  81. // to call it directly.
  82. //
  83. // Parameters:
  84. // bLoading - *true* specifies that a persistence load operation is about
  85. // to be entered; *false* indicates that such an operation is finished.
  86. //
  87. // See Also: TCComPropertyClassRoot::IsLoading,
  88. // TCComPropertyClassRoot::SetSaving, TCComPropertyClassRoot::CLoadSaveScope
  89. void TCComPropertyClassRoot::SetLoading(bool bLoading)
  90. {
  91. if (bLoading)
  92. InterlockedIncrement(&m_nLoadingRefs);
  93. else
  94. InterlockedDecrement(&m_nLoadingRefs);
  95. }
  96. /////////////////////////////////////////////////////////////////////////////
  97. // Description: Returns the object's current persistence save state.
  98. //
  99. // Determines if the object is currently being saved to a persistence
  100. // mechanism.
  101. //
  102. // Return Value: *true* if the object is being saved to a persistence
  103. // mechanism, otherwise *false*.
  104. //
  105. // See Also: TCComPropertyClassRoot::SetSaving,
  106. // TCComPropertyClassRoot::IsLoading, TCComPropertyClassRoot::CLoadSaveScope
  107. bool TCComPropertyClassRoot::IsSaving()
  108. {
  109. return m_nSavingRefs != 0;
  110. }
  111. /////////////////////////////////////////////////////////////////////////////
  112. // Description: Sets or clears the object's current persistence save state.
  113. //
  114. // Sets or clears the object's current persistence state. Actually, since
  115. // saving to a persistence mechanism may be nested into several levels,
  116. // this method only increments or decrements a reference count of save
  117. // operations. Typically, this method is only used internally by the
  118. // TCComPropertyClassRoot::CLoadSaveScope class. Usually, there is no reason
  119. // to call it directly.
  120. //
  121. // Parameters:
  122. // bSaving - *true* specifies that a persistence save operation is about to
  123. // be entered; *false* indicates that such an operation is finished.
  124. //
  125. // See Also: TCComPropertyClassRoot::IsSaving,
  126. // TCComPropertyClassRoot::SetLoading, TCComPropertyClassRoot::CLoadSaveScope
  127. void TCComPropertyClassRoot::SetSaving(bool bSaving)
  128. {
  129. if (bSaving)
  130. InterlockedIncrement(&m_nSavingRefs);
  131. else
  132. InterlockedDecrement(&m_nSavingRefs);
  133. }
  134. /////////////////////////////////////////////////////////////////////////////
  135. // Group=Implementation
  136. /////////////////////////////////////////////////////////////////////////////
  137. // Description: Implementation of *IPersistStreamInit::Load*.
  138. //
  139. // Initializes an object from the stream where it was previously saved.
  140. //
  141. // Note: The *ATL::IPersistStreamInitImpl* class uses this method for its
  142. // implementation of *IPersistStreamInit::Load*.
  143. //
  144. // Parameters:
  145. // pStm - [in] *IStream* pointer to the stream from which the object should
  146. // be loaded.
  147. // pMap - [in] Pointer to the first element of an array of
  148. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  149. //
  150. // Return Value:
  151. //
  152. // S_OK - The object was successfully loaded.
  153. // E_OUTOFMEMORY - The object was not loaded due to a lack of memory.
  154. // E_FAIL - The object was not loaded due to some reason other than a lack
  155. // of memory.
  156. //
  157. // See Also: TCComPropertyClass, *ATL::IPersistStreamInitImpl* „
  158. HRESULT TCComPropertyClassRoot::TCPersistStreamInit_Load(LPSTREAM pStm,
  159. ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  160. {
  161. // Enter the Loading mode for this scope
  162. CLoadSaveScope loading(this);
  163. assert(pMap != NULL);
  164. HRESULT hr = S_OK;
  165. DWORD dwVer;
  166. hr = pStm->Read(&dwVer, sizeof(DWORD), NULL);
  167. if (dwVer > _ATL_VER)
  168. return E_FAIL;
  169. if (FAILED(hr))
  170. return hr;
  171. CComPtr<IDispatch> pDispatch;
  172. const IID* piidOld = NULL;
  173. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  174. {
  175. if (pMap[i].szDesc == NULL)
  176. continue;
  177. // check if raw data entry
  178. if (pMap[i].dwSizeData != 0)
  179. {
  180. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  181. hr = pStm->Read(pData, pMap[i].dwSizeData, NULL);
  182. if (FAILED(hr))
  183. return hr;
  184. continue;
  185. }
  186. CComVariant var;
  187. // Handle safe arrays seperately from general VARTYPE's
  188. if (S_FALSE == (hr = TCReadSafeArrayFromStream(pStm, var)))
  189. hr = var.ReadFromStream(pStm);
  190. if (FAILED(hr))
  191. break;
  192. if(pMap[i].piidDispatch != piidOld)
  193. {
  194. pDispatch.Release();
  195. if(FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  196. {
  197. _TRACE_BEGIN
  198. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  199. _TRACE_PART0("IPersistStreamInit_Load(): Failed to get a dispatch ");
  200. _TRACE_PART2("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
  201. _TRACE_END
  202. hr = E_FAIL;
  203. break;
  204. }
  205. piidOld = pMap[i].piidDispatch;
  206. }
  207. if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
  208. {
  209. _TRACE_BEGIN
  210. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  211. _TRACE_PART0("IPersistStreamInit_Load(): Invoke failed on DISPID ");
  212. _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  213. _TRACE_END
  214. hr = E_FAIL;
  215. break;
  216. }
  217. }
  218. return hr;
  219. }
  220. /////////////////////////////////////////////////////////////////////////////
  221. // Description: Implementation of *IPersistStreamInit::Save*.
  222. //
  223. // Saves an object to the specified stream.
  224. //
  225. // Note: The *ATL::IPersistStreamInitImpl* class uses this method for its
  226. // implementation of *IPersistStreamInit::Save*.
  227. //
  228. // Parameters:
  229. // pStm - [in] *IStream* pointer to the stream into which the object should
  230. // be saved.
  231. // fClearDirty - [in] Indicates whether to clear the dirty flag after the
  232. // save is complete. If *TRUE*, the flag should be cleared. If *FALSE*, the
  233. // flag should be left unchanged.
  234. // pMap - [in] Pointer to the first element of an array of
  235. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  236. //
  237. // Return Value:
  238. //
  239. // S_OK - The object was successfully saved to the stream.
  240. // STG_E_CANTSAVE - The object could not save itself to the stream. This
  241. // error could indicate, for example, that the object contains another object
  242. // that is not serializable to a stream or that an
  243. // *ISequentialStream::Write* call returned *STG_E_CANTSAVE*.
  244. // STG_E_MEDIUMFULL - The object could not be saved because there is no
  245. // space left on the storage device.
  246. //
  247. // See Also: TCComPropertyClass, *ATL::IPersistStreamInitImpl* „
  248. HRESULT TCComPropertyClassRoot::TCPersistStreamInit_Save(LPSTREAM pStm,
  249. BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  250. {
  251. // Enter the Saving mode for this scope
  252. CLoadSaveScope saving(this, false);
  253. assert(pMap != NULL);
  254. DWORD dw = _ATL_VER;
  255. HRESULT hr = pStm->Write(&dw, sizeof(DWORD), NULL);
  256. if (FAILED(hr))
  257. return hr;
  258. CComPtr<IDispatch> pDispatch;
  259. const IID* piidOld = NULL;
  260. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  261. {
  262. if (pMap[i].szDesc == NULL)
  263. continue;
  264. // check if raw data entry
  265. if (pMap[i].dwSizeData != 0)
  266. {
  267. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  268. hr = pStm->Write(pData, pMap[i].dwSizeData, NULL);
  269. if (FAILED(hr))
  270. return hr;
  271. continue;
  272. }
  273. CComVariant var;
  274. if(pMap[i].piidDispatch != piidOld)
  275. {
  276. pDispatch.Release();
  277. if(FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  278. {
  279. _TRACE_BEGIN
  280. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  281. _TRACE_PART0("IPersistStreamInit_Save(): Failed to get a dispatch ");
  282. _TRACE_PART2("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
  283. _TRACE_END
  284. hr = E_FAIL;
  285. break;
  286. }
  287. piidOld = pMap[i].piidDispatch;
  288. }
  289. if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  290. {
  291. _TRACE_BEGIN
  292. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  293. _TRACE_PART0("IPersistStreamInit_Save(): Invoke failed on DISPID ");
  294. _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  295. _TRACE_END
  296. hr = E_FAIL;
  297. break;
  298. }
  299. // Handle safe arrays seperately from general VARTYPE's
  300. if (S_FALSE == (hr = TCWriteSafeArrayToStream(pStm, var)))
  301. hr = var.WriteToStream(pStm);
  302. if (FAILED(hr))
  303. break;
  304. }
  305. if (SUCCEEDED(hr) && fClearDirty)
  306. SetDirty(FALSE);
  307. return hr;
  308. }
  309. /////////////////////////////////////////////////////////////////////////////
  310. // Description: Implementation of *IPersistPropertyBag::Load*.
  311. //
  312. // This method instructs the object to initialize itself using the properties
  313. // available in the property bag, notifying the provided error log object
  314. // when errors occur. All property storage must take place within this method
  315. // call as the object cannot hold the IPropertyBag pointer.
  316. //
  317. // *E_NOTIMPL* is not a valid return code as any object implementing this
  318. // interface must support the entire functionality of the interface.
  319. //
  320. // Note: The *ATL::IPersistPropertyBagImpl* class uses this method for its
  321. // implementation of *IPersistPropertyBag::Load*.
  322. //
  323. // Parameters:
  324. // pPropBag - [in] Pointer to the caller's *IPropertyBag* interface bag
  325. // that the object uses to read its properties. Cannot be *NULL*.
  326. // pErrorLog - [in] Pointer to the caller's *IErrorLog* interface in which
  327. // the object stores any errors that occur during initialization. Can be
  328. // *NULL* in which case the caller is not interested in errors.
  329. // pMap - [in] Pointer to the first element of an array of
  330. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  331. //
  332. // Return Value:
  333. //
  334. // S_OK - The object successfully initialized itself.
  335. // E_UNEXPECTED - This method was called after
  336. // *IPersistPropertyBag::InitNew* has already been called. The two
  337. // initialization methods are mutually exclusive.
  338. // E_OUTOFMEMORY - The properties were not loaded due to a lack of memory.
  339. // E_POINTER - The address in /pPropBag/ is not valid (such as *NULL*) and
  340. // therefore the object cannot initialize itself.
  341. // E_FAIL - The object was unable to retrieve a critical property that is
  342. // necessary for the object's successful operation. The object was therefore
  343. // unable to initialize itself completely.
  344. //
  345. // See Also: TCComPropertyClass, *ATL::IPersistPropertyBagImpl* „
  346. HRESULT TCComPropertyClassRoot::TCPersistPropertyBag_Load(
  347. LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap,
  348. void* pThis, IUnknown* pUnk)
  349. {
  350. // Enter the Loading mode for this scope
  351. CLoadSaveScope loading(this);
  352. USES_CONVERSION;
  353. CComPtr<IDispatch> pDispatch;
  354. const IID* piidOld = NULL;
  355. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  356. {
  357. if (pMap[i].szDesc == NULL)
  358. continue;
  359. CComVariant var;
  360. // If raw entry, handle specially
  361. if (pMap[i].dwSizeData != 0)
  362. {
  363. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  364. HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
  365. if (SUCCEEDED(hr))
  366. {
  367. // check the type - we only deal with limited set
  368. switch (pMap[i].vt)
  369. {
  370. case VT_UI1:
  371. case VT_I1:
  372. *((BYTE*)pData) = var.bVal;
  373. break;
  374. case VT_BOOL:
  375. *((VARIANT_BOOL*)pData) = var.boolVal;
  376. break;
  377. case VT_I2: // Added by TC
  378. case VT_UI2:
  379. *((short*)pData) = var.iVal;
  380. break;
  381. case VT_I4: // Added by TC
  382. case VT_UI4:
  383. case VT_INT:
  384. case VT_UINT:
  385. *((long*)pData) = var.lVal;
  386. break;
  387. /////////////////////////////////////////////////////////////////////
  388. // The following all added by TC //
  389. case VT_R4: //
  390. *((float*)pData) = var.fltVal; //
  391. break; //
  392. case VT_R8: //
  393. *((double*)pData) = var.dblVal; //
  394. break; //
  395. case VT_CY: //
  396. *((CY*)pData) = var.cyVal; //
  397. break; //
  398. case VT_DATE: //
  399. *((DATE*)pData) = var.date; //
  400. break; //
  401. case VT_ERROR: //
  402. *((SCODE*)pData) = var.scode; //
  403. break; //
  404. case VT_DECIMAL: //
  405. *((DECIMAL*)pData) = *var.pdecVal; //
  406. break; //
  407. /////////////////////////////////////////////////////////////////////
  408. // TODO: Implement the following VARIANT types //
  409. case VT_BSTR: // Tricky: different ways to store a BSTR //
  410. break; //
  411. case VT_UNKNOWN: // Tricky: different ways to store a IUnknown* //
  412. case VT_DISPATCH: // Tricky: different ways to store a IDispatch*//
  413. continue; //
  414. case VT_VARIANT: // Tricky: different ways to store a VARIANT //
  415. continue; //
  416. case VT_RECORD: // Tricky: how possible? //
  417. continue; //
  418. case VT_ARRAY: // Very tricky: Also, caution: OR flag //
  419. continue; //
  420. case VT_BYREF: // Shouldn't be TOO tricky. Caution: OR flag //
  421. continue; //
  422. /////////////////////////////////////////////////////////////////////
  423. }
  424. }
  425. continue;
  426. }
  427. if(pMap[i].piidDispatch != piidOld)
  428. {
  429. pDispatch.Release();
  430. if(FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  431. {
  432. _TRACE_BEGIN
  433. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  434. _TRACE_PART0("IPersistPropertyBag_Load(): Failed to get a dispatch ");
  435. _TRACE_PART2("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
  436. _TRACE_END
  437. return E_FAIL;
  438. }
  439. piidOld = pMap[i].piidDispatch;
  440. }
  441. if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  442. {
  443. _TRACE_BEGIN
  444. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  445. _TRACE_PART0("IPersistPropertyBag_Load(): Invoke failed on DISPID ");
  446. _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  447. _TRACE_END
  448. return E_FAIL;
  449. }
  450. if (VT_DISPATCH == V_VT(&var))
  451. var.Clear();
  452. HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
  453. if (FAILED(hr))
  454. {
  455. if (hr == E_INVALIDARG)
  456. {
  457. _TRACE_BEGIN
  458. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  459. _TRACE_PART0("IPersistPropertyBag_Load(): ");
  460. _TRACE_PART1("Property %ls not in Bag\n", pMap[i].szDesc);
  461. _TRACE_END
  462. }
  463. else
  464. {
  465. // Many containers return different ERROR values for Member not found
  466. _TRACE_BEGIN
  467. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  468. _TRACE_PART0("IPersistPropertyBag_Load(): Error attempting to read ");
  469. _TRACE_PART1("Property %ls from PropertyBag\n", pMap[i].szDesc);
  470. _TRACE_END
  471. }
  472. continue;
  473. }
  474. if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
  475. {
  476. _TRACE_BEGIN
  477. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  478. _TRACE_PART0("IPersistPropertyBag_Load(): Invoke failed on DISPID ");
  479. _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  480. _TRACE_END
  481. return E_FAIL;
  482. }
  483. }
  484. return S_OK;
  485. }
  486. /////////////////////////////////////////////////////////////////////////////
  487. // Description: Implementation of *IPersistPropertyBag::Save*.
  488. //
  489. // This method instructs the object to save its properties to the specified
  490. // property bag, optionally clearing the object's dirty flag. The caller can
  491. // request that the object save all properties or that the object save only
  492. // those that are known to have changed.
  493. //
  494. // *E_NOTIMPL* is not a valid return code as any object implementing this
  495. // interface must support the entire functionality of the interface.
  496. //
  497. // Note: The *ATL::IPersistPropertyBagImpl* class uses this method for its
  498. // implementation of *IPersistPropertyBag::Save*.
  499. //
  500. // Parameters:
  501. // pPropBag - [in] Pointer to the caller's *IPropertyBag* interface bag
  502. // that the object uses to write its properties. Cannot be *NULL*.
  503. // fClearDirty - [in] A flag indicating whether the object should clear its
  504. // dirty flag when saving is complete. *TRUE* means clear the flag, *FALSE* „
  505. // means leave the flag unaffected. *FALSE* is used when the caller wishes to
  506. // do a /Save/ /Copy/ /As/ type of operation.
  507. // fSaveAllProperties - [in] A flag indicating whether the object should
  508. // save all its properties (TRUE) or only those that have changed since the
  509. // last save or initialization (FALSE).
  510. // pMap - [in] Pointer to the first element of an array of
  511. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  512. //
  513. // Return Value:
  514. //
  515. // S_OK - The object successfully saved the requested properties itself.
  516. // E_FAIL - There was a problem saving one of the properties. The object can
  517. // choose to fail only if a necessary property could not be saved, meaning
  518. // that the object can assume default property values if a given property is
  519. // not seen through *IPersistPropertyBag::Load* at some later time.
  520. // E_POINTER - The address in /pPropBag/ is not valid (such as *NULL*) and
  521. // therefore the object cannot save itself.
  522. // STG_E_MEDIUMFULL - The object was not saved because of a lack of space on
  523. // the disk.
  524. //
  525. // See Also: TCComPropertyClass, *ATL::IPersistPropertyBagImpl* „
  526. HRESULT TCComPropertyClassRoot::TCPersistPropertyBag_Save(
  527. LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties,
  528. ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  529. {
  530. // Do nothing if saving only the dirty properties and there are none
  531. if (!fSaveAllProperties && !GetDirty())
  532. return S_OK;
  533. if (pPropBag == NULL)
  534. {
  535. _TRACE_BEGIN
  536. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  537. _TRACE_PART0("IPersistPropertyBag_Save(): ");
  538. _TRACE_PART0("PropBag pointer passed in was invalid\n");
  539. _TRACE_END
  540. return E_POINTER;
  541. }
  542. // Enter the Saving mode for this scope
  543. CLoadSaveScope saving(this, false);
  544. CComPtr<IDispatch> pDispatch;
  545. const IID* piidOld = NULL;
  546. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  547. {
  548. if (pMap[i].szDesc == NULL)
  549. continue;
  550. CComVariant var;
  551. // If raw entry skip it - we don't handle it for property bags just yet
  552. if (pMap[i].dwSizeData != 0)
  553. {
  554. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  555. // check the type - we only deal with limited set
  556. bool bTypeOK = false;
  557. switch (pMap[i].vt)
  558. {
  559. case VT_UI1:
  560. case VT_I1:
  561. var.bVal = *((BYTE*)pData);
  562. bTypeOK = true;
  563. break;
  564. case VT_BOOL:
  565. var.boolVal = *((VARIANT_BOOL*)pData);
  566. bTypeOK = true;
  567. break;
  568. case VT_I2: // Added by TC
  569. case VT_UI2:
  570. var.iVal = *((short*)pData);
  571. bTypeOK = true;
  572. break;
  573. case VT_I4: // Added by TC
  574. case VT_UI4:
  575. case VT_INT:
  576. case VT_UINT:
  577. var.lVal = *((long*)pData);
  578. bTypeOK = true;
  579. break;
  580. /////////////////////////////////////////////////////////////////////
  581. // The following all added by TC //
  582. case VT_R4: //
  583. var.fltVal = *((float*)pData); //
  584. bTypeOK = true; //
  585. break; //
  586. case VT_R8: //
  587. var.dblVal = *((double*)pData); //
  588. bTypeOK = true; //
  589. break; //
  590. case VT_CY: //
  591. var.cyVal = *((CY*)pData); //
  592. bTypeOK = true; //
  593. break; //
  594. case VT_DATE: //
  595. var.date = *((DATE*)pData); //
  596. bTypeOK = true; //
  597. break; //
  598. case VT_ERROR: //
  599. var.scode = *((SCODE*)pData); //
  600. bTypeOK = true; //
  601. break; //
  602. case VT_DECIMAL: //
  603. var.pdecVal = ((DECIMAL*)pData); //
  604. bTypeOK = true; //
  605. break; //
  606. /////////////////////////////////////////////////////////////////////
  607. // TODO: Implement the following VARIANT types //
  608. case VT_BSTR: // Tricky: different ways to store a BSTR //
  609. break; //
  610. case VT_UNKNOWN: // Tricky: different ways to store a IUnknown* //
  611. case VT_DISPATCH: // Tricky: different ways to store a IDispatch*//
  612. continue; //
  613. case VT_VARIANT: // Tricky: different ways to store a VARIANT //
  614. continue; //
  615. case VT_RECORD: // Tricky: how possible? //
  616. continue; //
  617. case VT_ARRAY: // Very tricky: Also, caution: OR flag //
  618. continue; //
  619. case VT_BYREF: // Shouldn't be TOO tricky. Caution: OR flag //
  620. continue; //
  621. /////////////////////////////////////////////////////////////////////
  622. }
  623. if (bTypeOK)
  624. {
  625. var.vt = pMap[i].vt;
  626. HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
  627. if (FAILED(hr))
  628. return hr;
  629. }
  630. continue;
  631. }
  632. if(pMap[i].piidDispatch != piidOld)
  633. {
  634. pDispatch.Release();
  635. if(FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  636. {
  637. _TRACE_BEGIN
  638. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  639. _TRACE_PART0("IPersistPropertyBag_Save(): Failed to get a dispatch ");
  640. _TRACE_PART2("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
  641. _TRACE_END
  642. return E_FAIL;
  643. }
  644. piidOld = pMap[i].piidDispatch;
  645. }
  646. if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  647. {
  648. _TRACE_BEGIN
  649. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  650. _TRACE_PART0("IPersistPropertyBag_Save(): Invoke failed on DISPID ");
  651. _TRACE_PART2("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  652. _TRACE_END
  653. return E_FAIL;
  654. }
  655. if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH)
  656. {
  657. if (var.ppunkVal == NULL)
  658. {
  659. _TRACE_BEGIN
  660. _TRACE_PART1("TCComPropertyClass<%hs>::", m_pszType);
  661. _TRACE_PART0("IPersistPropertyBag_Save(): ");
  662. _TRACE_PART0("Warning skipping empty IUnknown in Save\n");
  663. _TRACE_END
  664. continue;
  665. }
  666. }
  667. HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
  668. if (FAILED(hr))
  669. return hr;
  670. }
  671. if (fClearDirty)
  672. SetDirty(FALSE);
  673. return S_OK;
  674. }
  675. /////////////////////////////////////////////////////////////////////////////
  676. // Description: Implementation of *ISpecifyPropertyPages::GetPages*.
  677. //
  678. // Fills a counted array of GUID values where each GUID specifies the CLSID
  679. // of each property page that can be displayed in the property sheet for this
  680. // object.
  681. //
  682. // Note: The *ATL::ISpecifyPropertyPagesImpl* class uses this method for its
  683. // implementation of *ISpecifyPropertyPages::GetPages*.
  684. //
  685. // Parameters:
  686. // pPages - [out] Pointer to a caller-allocated *CAUUID* structure that must
  687. // be initialized and filled before returning. The /pElems/ field in the
  688. // *CAUUID* structure is allocated by the callee with *CoTaskMemAlloc* and
  689. // freed by the caller with *CoTaskMemFree*.
  690. // pMap - [in] Pointer to the first element of an array of
  691. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  692. //
  693. // Return Value: This method supports the standard return values
  694. // *E_OUTOFMEMORY* and *E_UNEXPECTED*, as well as the following:
  695. //
  696. // S_OK - The array was filled successfully.
  697. // E_POINTER - The address in /pPages/ is not valid. For example, it may be
  698. // *NULL*.
  699. //
  700. // See Also: TCComPropertyClass, *ATL::ISpecifyPropertyPagesImpl* „
  701. HRESULT TCComPropertyClassRoot::ISpecifyPropertyPages_GetPages(
  702. CAUUID* pPages, ATL_PROPMAP_ENTRY* pMap)
  703. {
  704. assert(pMap != NULL);
  705. int nCnt = 0;
  706. // Get count of unique pages
  707. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  708. {
  709. if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
  710. nCnt++;
  711. }
  712. pPages->pElems = NULL;
  713. pPages->pElems = (GUID*) CoTaskMemAlloc(sizeof(CLSID)*nCnt);
  714. if (pPages->pElems == NULL)
  715. return E_OUTOFMEMORY;
  716. nCnt = 0;
  717. for(i = 0; pMap[i].pclsidPropPage != NULL; i++)
  718. {
  719. if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
  720. {
  721. BOOL bMatch = FALSE;
  722. for (int j=0;j<nCnt;j++)
  723. {
  724. if (InlineIsEqualGUID(*(pMap[i].pclsidPropPage), pPages->pElems[j]))
  725. {
  726. bMatch = TRUE;
  727. break;
  728. }
  729. }
  730. if (!bMatch)
  731. pPages->pElems[nCnt++] = *pMap[i].pclsidPropPage;
  732. }
  733. }
  734. pPages->cElems = nCnt;
  735. return S_OK;
  736. }
  737. /////////////////////////////////////////////////////////////////////////////
  738. // Group=
  739. /////////////////////////////////////////////////////////////////////////////
  740. // Global Implementation
  741. #ifdef _ATL
  742. ///////////////////////////////////////////////////////////////////////////
  743. // Description: Compares a *CComVariant* to a *VARIANT*.
  744. //
  745. // Since CComVariant::operator== does not compare arrays of *BSTR*'s, this
  746. // function was developed to first check for the variant type
  747. // *VT_ARRAY*|*VT_BSTR*. If both parameters are of that variant type,
  748. // the elements of the first dimension of the string array are compared.
  749. // Otherwise, processing is delegated to CComVariant::operator==.
  750. //
  751. // Parameters:
  752. // dest - A reference to the *CComVariant* on the left-hand side of the
  753. // comparison.
  754. // src - A reference to the *VARIANT* on the right-hand side of the
  755. // comparison.
  756. //
  757. // Return Value: *true* if the arguments are equal, otherwise *false*.
  758. //
  759. // See Also: TCComPropertyCompare, TCComPropertyPut
  760. bool TCComVariantCompare(CComVariant& dest, VARIANT& src)
  761. {
  762. // Check for (some) types that CComVariant::operator== doesnt' handle
  763. VARTYPE vtDest = V_VT(&dest);
  764. VARTYPE vtSrc = V_VT(&src);
  765. // Array of ...
  766. if ((VT_ARRAY & vtDest) && (VT_ARRAY & vtSrc))
  767. {
  768. // Check equal element size
  769. SAFEARRAY* psaDest = V_ARRAY(&dest);
  770. SAFEARRAY* psaSrc = V_ARRAY(&src);
  771. if (psaDest->cbElements != psaSrc->cbElements)
  772. return false;
  773. // Strip off array flag and check to see if BSTR's
  774. vtDest &= ~VT_ARRAY;
  775. vtSrc &= ~VT_ARRAY;
  776. if (VT_BSTR == vtDest && VT_BSTR == vtSrc)
  777. {
  778. // Check array bounds for match
  779. LONG lLBoundDest, lUBoundDest;
  780. LONG lLBoundSrc, lUBoundSrc;
  781. // Upper, most likely to be different
  782. if (FAILED(SafeArrayGetUBound(psaDest, 1, &lUBoundDest)))
  783. return false;
  784. if (FAILED(SafeArrayGetUBound(psaSrc, 1, &lUBoundSrc)))
  785. return false;
  786. if (lUBoundDest != lUBoundSrc)
  787. return false;
  788. // Check the lower too
  789. if (FAILED(SafeArrayGetLBound(psaDest, 1, &lLBoundDest)))
  790. return false;
  791. if (FAILED(SafeArrayGetLBound(psaSrc, 1, &lLBoundSrc)))
  792. return false;
  793. if (lLBoundDest != lLBoundSrc)
  794. return false;
  795. // Compute the elements size, equal if no elements
  796. LONG cElements = lUBoundDest - lLBoundDest + 1;
  797. if (!cElements)
  798. return true;
  799. // Get pointers to the elements of the arrays
  800. BSTR *pbstrDest,*pbstrSrc;
  801. if (FAILED(SafeArrayAccessData(psaDest, (void**)&pbstrDest)))
  802. return false;
  803. if (FAILED(SafeArrayAccessData(psaSrc, (void**)&pbstrSrc)))
  804. {
  805. _VERIFYE(SUCCEEDED(SafeArrayUnaccessData(psaDest)));
  806. return false;
  807. }
  808. // Loop through all elements and check for difference
  809. bool bSame = true;
  810. __try
  811. {
  812. // See if the strings are the same
  813. for (int i = 0; i < cElements && bSame; i++)
  814. {
  815. // Check for NULL pointers
  816. if (!pbstrDest[i] || !pbstrSrc[i])
  817. {
  818. bSame = pbstrDest[i] == pbstrSrc[i];
  819. continue;
  820. }
  821. // Get string lengths
  822. UINT nLenDest = SysStringLen(pbstrDest[i]);
  823. UINT nLenSrc = SysStringLen(pbstrSrc[i]);
  824. // Compare lengths and contents
  825. if (nLenDest != nLenSrc || wcscmp(pbstrDest[i], pbstrSrc[i]))
  826. bSame = false;
  827. }
  828. }
  829. __except(1)
  830. {
  831. _TRACE_BEGIN
  832. _TRACE_PART0("TCComPropertyCompare(): Caught an unknown exception ");
  833. _TRACE_PART0("(probably an invalid pointer was specified)");
  834. _TRACE_END
  835. bSame = false;
  836. }
  837. // Release access to the array elements
  838. _VERIFYE(SUCCEEDED(SafeArrayUnaccessData(psaDest)));
  839. _VERIFYE(SUCCEEDED(SafeArrayUnaccessData(psaSrc)));
  840. return bSame;
  841. }
  842. }
  843. // Default to CComVariant::operator==
  844. return dest == src;
  845. }
  846. #endif // _ATL
  847. /////////////////////////////////////////////////////////////////////////////
  848. #endif // !__PropertyClass_cpp__