Persist.h 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. #ifndef __Persist_h__
  2. #define __Persist_h__
  3. #pragma once
  4. /////////////////////////////////////////////////////////////////////////////
  5. // Description: Implementation of *IPersistStreamInit::Load*.
  6. //
  7. // Initializes an object from the stream where it was previously saved.
  8. //
  9. // Note: The *ATL::IPersistStreamInitImpl* class uses this method for its
  10. // implementation of *IPersistStreamInit::Load*.
  11. //
  12. // Parameters:
  13. // pStm - [in] *IStream* pointer to the stream from which the object should
  14. // be loaded.
  15. // pMap - [in] Pointer to the first element of an array of
  16. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  17. //
  18. // Return Value:
  19. //
  20. // S_OK - The object was successfully loaded.
  21. // E_OUTOFMEMORY - The object was not loaded due to a lack of memory.
  22. // E_FAIL - The object was not loaded due to some reason other than a lack
  23. // of memory.
  24. //
  25. // See Also: TCComPropertyClass, *ATL::IPersistStreamInitImpl* „
  26. HRESULT TCComPropertyClassRoot::TCPersistStreamInit_Load(LPSTREAM pStm,
  27. ATL_PROPMAP_ENTRY* pMap)
  28. {
  29. // Enter the Loading mode for this scope
  30. CLoadSaveScope loading(this);
  31. // Ensure that we get a pointer to the outer-most inheritance branch
  32. T* pT = static_cast<T*>(this);
  33. IUnknown* pUnk = pT->GetUnknown();
  34. assert(pMap != NULL);
  35. HRESULT hr = S_OK;
  36. DWORD dwVer;
  37. hr = pStm->Read(&dwVer, sizeof(DWORD), NULL);
  38. if (dwVer > _ATL_VER)
  39. return E_FAIL;
  40. if (FAILED(hr))
  41. return hr;
  42. CComPtr<IDispatch> pDispatch;
  43. const IID* piidOld = NULL;
  44. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  45. {
  46. if (pMap[i].szDesc == NULL)
  47. continue;
  48. // check if raw data entry
  49. if (pMap[i].dwSizeData != 0)
  50. {
  51. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  52. hr = pStm->Read(pData, pMap[i].dwSizeData, NULL);
  53. if (FAILED(hr))
  54. return hr;
  55. continue;
  56. }
  57. CComVariant var;
  58. // Handle safe arrays seperately from general VARTYPE's
  59. if (S_FALSE == (hr = TCReadSafeArrayFromStream(pStm, var)))
  60. hr = var.ReadFromStream(pStm);
  61. if (FAILED(hr))
  62. break;
  63. if(pMap[i].piidDispatch != piidOld)
  64. {
  65. pDispatch.Release();
  66. if(FAILED(ControlQueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  67. {
  68. _TRACE_BEGIN
  69. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  70. _TRACE_PART("IPersistStreamInit_Load(): Failed to get a dispatch ");
  71. _TRACE_PART("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
  72. _TRACE_END
  73. hr = E_FAIL;
  74. break;
  75. }
  76. piidOld = pMap[i].piidDispatch;
  77. }
  78. if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
  79. {
  80. _TRACE_BEGIN
  81. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  82. _TRACE_PART("IPersistStreamInit_Load(): Invoke failed on DISPID ");
  83. _TRACE_PART("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  84. _TRACE_END
  85. hr = E_FAIL;
  86. break;
  87. }
  88. }
  89. return hr;
  90. }
  91. /////////////////////////////////////////////////////////////////////////////
  92. // Description: Implementation of *IPersistStreamInit::Save*.
  93. //
  94. // Saves an object to the specified stream.
  95. //
  96. // Note: The *ATL::IPersistStreamInitImpl* class uses this method for its
  97. // implementation of *IPersistStreamInit::Save*.
  98. //
  99. // Parameters:
  100. // pStm - [in] *IStream* pointer to the stream into which the object should
  101. // be saved.
  102. // fClearDirty - [in] Indicates whether to clear the dirty flag after the
  103. // save is complete. If *TRUE*, the flag should be cleared. If *FALSE*, the
  104. // flag should be left unchanged.
  105. // pMap - [in] Pointer to the first element of an array of
  106. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  107. //
  108. // Return Value:
  109. //
  110. // S_OK - The object was successfully saved to the stream.
  111. // STG_E_CANTSAVE - The object could not save itself to the stream. This
  112. // error could indicate, for example, that the object contains another object
  113. // that is not serializable to a stream or that an
  114. // *ISequentialStream::Write* call returned *STG_E_CANTSAVE*.
  115. // STG_E_MEDIUMFULL - The object could not be saved because there is no
  116. // space left on the storage device.
  117. //
  118. // See Also: TCComPropertyClass, *ATL::IPersistStreamInitImpl* „
  119. HRESULT TCComPropertyClassRoot::TCPersistStreamInit_Save(LPSTREAM pStm,
  120. BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap)
  121. {
  122. // Enter the Saving mode for this scope
  123. CLoadSaveScope saving(this, false);
  124. // Ensure that we get a pointer to the outer-most inheritance branch
  125. T* pT = static_cast<T*>(this);
  126. IUnknown* pUnk = pT->GetUnknown();
  127. assert(pMap != NULL);
  128. DWORD dw = _ATL_VER;
  129. HRESULT hr = pStm->Write(&dw, sizeof(DWORD), NULL);
  130. if (FAILED(hr))
  131. return hr;
  132. CComPtr<IDispatch> pDispatch;
  133. const IID* piidOld = NULL;
  134. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  135. {
  136. if (pMap[i].szDesc == NULL)
  137. continue;
  138. // check if raw data entry
  139. if (pMap[i].dwSizeData != 0)
  140. {
  141. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  142. hr = pStm->Write(pData, pMap[i].dwSizeData, NULL);
  143. if (FAILED(hr))
  144. return hr;
  145. continue;
  146. }
  147. CComVariant var;
  148. if(pMap[i].piidDispatch != piidOld)
  149. {
  150. pDispatch.Release();
  151. if(FAILED(ControlQueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  152. {
  153. _TRACE_BEGIN
  154. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  155. _TRACE_PART("IPersistStreamInit_Save(): Failed to get a dispatch ");
  156. _TRACE_PART("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
  157. _TRACE_END
  158. hr = E_FAIL;
  159. break;
  160. }
  161. piidOld = pMap[i].piidDispatch;
  162. }
  163. if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  164. {
  165. _TRACE_BEGIN
  166. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  167. _TRACE_PART("IPersistStreamInit_Save(): Invoke failed on DISPID ");
  168. _TRACE_PART("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  169. _TRACE_END
  170. hr = E_FAIL;
  171. break;
  172. }
  173. // Handle safe arrays seperately from general VARTYPE's
  174. if (S_FALSE == (hr = TCWriteSafeArrayToStream(pStm, var)))
  175. hr = var.WriteToStream(pStm);
  176. if (FAILED(hr))
  177. break;
  178. }
  179. if (SUCCEEDED(hr) && fClearDirty)
  180. SetDirty(FALSE);
  181. return hr;
  182. }
  183. /////////////////////////////////////////////////////////////////////////////
  184. // Description: Implementation of *IPersistPropertyBag::Load*.
  185. //
  186. // This method instructs the object to initialize itself using the properties
  187. // available in the property bag, notifying the provided error log object
  188. // when errors occur. All property storage must take place within this method
  189. // call as the object cannot hold the IPropertyBag pointer.
  190. //
  191. // *E_NOTIMPL* is not a valid return code as any object implementing this
  192. // interface must support the entire functionality of the interface.
  193. //
  194. // Note: The *ATL::IPersistPropertyBagImpl* class uses this method for its
  195. // implementation of *IPersistPropertyBag::Load*.
  196. //
  197. // Parameters:
  198. // pPropBag - [in] Pointer to the caller's *IPropertyBag* interface bag
  199. // that the object uses to read its properties. Cannot be *NULL*.
  200. // pErrorLog - [in] Pointer to the caller's *IErrorLog* interface in which
  201. // the object stores any errors that occur during initialization. Can be
  202. // *NULL* in which case the caller is not interested in errors.
  203. // pMap - [in] Pointer to the first element of an array of
  204. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  205. //
  206. // Return Value:
  207. //
  208. // S_OK - The object successfully initialized itself.
  209. // E_UNEXPECTED - This method was called after
  210. // *IPersistPropertyBag::InitNew* has already been called. The two
  211. // initialization methods are mutually exclusive.
  212. // E_OUTOFMEMORY - The properties were not loaded due to a lack of memory.
  213. // E_POINTER - The address in /pPropBag/ is not valid (such as *NULL*) and
  214. // therefore the object cannot initialize itself.
  215. // E_FAIL - The object was unable to retrieve a critical property that is
  216. // necessary for the object's successful operation. The object was therefore
  217. // unable to initialize itself completely.
  218. //
  219. // See Also: TCComPropertyClass, *ATL::IPersistPropertyBagImpl* „
  220. HRESULT TCComPropertyClassRoot::TCPersistPropertyBag_Load(
  221. LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap)
  222. {
  223. // Enter the Loading mode for this scope
  224. CLoadSaveScope loading(this);
  225. // Ensure that we get a pointer to the outer-most inheritance branch
  226. T* pT = static_cast<T*>(this);
  227. IUnknown* pUnk = pT->GetUnknown();
  228. USES_CONVERSION;
  229. CComPtr<IDispatch> pDispatch;
  230. const IID* piidOld = NULL;
  231. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  232. {
  233. if (pMap[i].szDesc == NULL)
  234. continue;
  235. CComVariant var;
  236. // If raw entry, handle specially
  237. if (pMap[i].dwSizeData != 0)
  238. {
  239. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  240. HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
  241. if (SUCCEEDED(hr))
  242. {
  243. // check the type - we only deal with limited set
  244. switch (pMap[i].vt)
  245. {
  246. case VT_UI1:
  247. case VT_I1:
  248. *((BYTE*)pData) = var.bVal;
  249. break;
  250. case VT_BOOL:
  251. *((VARIANT_BOOL*)pData) = var.boolVal;
  252. break;
  253. case VT_I2: // Added by TC
  254. case VT_UI2:
  255. *((short*)pData) = var.iVal;
  256. break;
  257. case VT_I4: // Added by TC
  258. case VT_UI4:
  259. case VT_INT:
  260. case VT_UINT:
  261. *((long*)pData) = var.lVal;
  262. break;
  263. /////////////////////////////////////////////////////////////////////
  264. // The following all added by TC //
  265. case VT_R4: //
  266. *((float*)pData) = var.fltVal; //
  267. break; //
  268. case VT_R8: //
  269. *((double*)pData) = var.dblVal; //
  270. break; //
  271. case VT_CY: //
  272. *((CY*)pData) = var.cyVal; //
  273. break; //
  274. case VT_DATE: //
  275. *((DATE*)pData) = var.date; //
  276. break; //
  277. case VT_ERROR: //
  278. *((SCODE*)pData) = var.scode; //
  279. break; //
  280. case VT_DECIMAL: //
  281. *((DECIMAL*)pData) = *var.pdecVal; //
  282. break; //
  283. /////////////////////////////////////////////////////////////////////
  284. // TODO: Implement the following VARIANT types //
  285. case VT_BSTR: // Tricky: different ways to store a BSTR //
  286. break; //
  287. case VT_UNKNOWN: // Tricky: different ways to store a IUnknown* //
  288. case VT_DISPATCH: // Tricky: different ways to store a IDispatch*//
  289. continue; //
  290. case VT_VARIANT: // Tricky: different ways to store a VARIANT //
  291. continue; //
  292. case VT_RECORD: // Tricky: how possible? //
  293. continue; //
  294. case VT_ARRAY: // Very tricky: Also, caution: OR flag //
  295. continue; //
  296. case VT_BYREF: // Shouldn't be TOO tricky. Caution: OR flag //
  297. continue; //
  298. /////////////////////////////////////////////////////////////////////
  299. }
  300. }
  301. continue;
  302. }
  303. if(pMap[i].piidDispatch != piidOld)
  304. {
  305. pDispatch.Release();
  306. if(FAILED(ControlQueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  307. {
  308. _TRACE_BEGIN
  309. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  310. _TRACE_PART("IPersistPropertyBag_Load(): Failed to get a dispatch ");
  311. _TRACE_PART("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
  312. _TRACE_END
  313. return E_FAIL;
  314. }
  315. piidOld = pMap[i].piidDispatch;
  316. }
  317. if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  318. {
  319. _TRACE_BEGIN
  320. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  321. _TRACE_PART("IPersistPropertyBag_Load(): Invoke failed on DISPID ");
  322. _TRACE_PART("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  323. _TRACE_END
  324. return E_FAIL;
  325. }
  326. if (VT_DISPATCH == V_VT(&var))
  327. var.Clear();
  328. HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
  329. if (FAILED(hr))
  330. {
  331. if (hr == E_INVALIDARG)
  332. {
  333. _TRACE_BEGIN
  334. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  335. _TRACE_PART("IPersistPropertyBag_Load(): ");
  336. _TRACE_PART("Property %ls not in Bag\n", pMap[i].szDesc);
  337. _TRACE_END
  338. }
  339. else
  340. {
  341. // Many containers return different ERROR values for Member not found
  342. _TRACE_BEGIN
  343. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  344. _TRACE_PART("IPersistPropertyBag_Load(): Error attempting to read ");
  345. _TRACE_PART("Property %ls from PropertyBag\n", pMap[i].szDesc);
  346. _TRACE_END
  347. }
  348. continue;
  349. }
  350. if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
  351. {
  352. _TRACE_BEGIN
  353. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  354. _TRACE_PART("IPersistPropertyBag_Load(): Invoke failed on DISPID ");
  355. _TRACE_PART("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  356. _TRACE_END
  357. return E_FAIL;
  358. }
  359. }
  360. return S_OK;
  361. }
  362. /////////////////////////////////////////////////////////////////////////////
  363. // Description: Implementation of *IPersistPropertyBag::Save*.
  364. //
  365. // This method instructs the object to save its properties to the specified
  366. // property bag, optionally clearing the object's dirty flag. The caller can
  367. // request that the object save all properties or that the object save only
  368. // those that are known to have changed.
  369. //
  370. // *E_NOTIMPL* is not a valid return code as any object implementing this
  371. // interface must support the entire functionality of the interface.
  372. //
  373. // Note: The *ATL::IPersistPropertyBagImpl* class uses this method for its
  374. // implementation of *IPersistPropertyBag::Save*.
  375. //
  376. // Parameters:
  377. // pPropBag - [in] Pointer to the caller's *IPropertyBag* interface bag
  378. // that the object uses to write its properties. Cannot be *NULL*.
  379. // fClearDirty - [in] A flag indicating whether the object should clear its
  380. // dirty flag when saving is complete. *TRUE* means clear the flag, *FALSE* „
  381. // means leave the flag unaffected. *FALSE* is used when the caller wishes to
  382. // do a /Save/ /Copy/ /As/ type of operation.
  383. // fSaveAllProperties - [in] A flag indicating whether the object should
  384. // save all its properties (TRUE) or only those that have changed since the
  385. // last save or initialization (FALSE).
  386. // pMap - [in] Pointer to the first element of an array of
  387. // *ATL_PROPMAP_ENTRY* structures, as defined by the ATL property map macros.
  388. //
  389. // Return Value:
  390. //
  391. // S_OK - The object successfully saved the requested properties itself.
  392. // E_FAIL - There was a problem saving one of the properties. The object can
  393. // choose to fail only if a necessary property could not be saved, meaning
  394. // that the object can assume default property values if a given property is
  395. // not seen through *IPersistPropertyBag::Load* at some later time.
  396. // E_POINTER - The address in /pPropBag/ is not valid (such as *NULL*) and
  397. // therefore the object cannot save itself.
  398. // STG_E_MEDIUMFULL - The object was not saved because of a lack of space on
  399. // the disk.
  400. //
  401. // See Also: TCComPropertyClass, *ATL::IPersistPropertyBagImpl* „
  402. HRESULT TCComPropertyClassRoot::TCPersistPropertyBag_Save(
  403. LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties,
  404. ATL_PROPMAP_ENTRY* pMap)
  405. {
  406. // Do nothing if saving only the dirty properties and there are none
  407. if (!fSaveAllProperties && !GetDirty())
  408. return S_OK;
  409. if (pPropBag == NULL)
  410. {
  411. _TRACE_BEGIN
  412. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  413. _TRACE_PART("IPersistPropertyBag_Save(): ");
  414. _TRACE_PART("PropBag pointer passed in was invalid\n");
  415. _TRACE_END
  416. return E_POINTER;
  417. }
  418. // Enter the Saving mode for this scope
  419. CLoadSaveScope saving(this, false);
  420. // Ensure that we get a pointer to the outer-most inheritance branch
  421. T* pT = static_cast<T*>(this);
  422. IUnknown* pUnk = pT->GetUnknown();
  423. CComPtr<IDispatch> pDispatch;
  424. const IID* piidOld = NULL;
  425. for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  426. {
  427. if (pMap[i].szDesc == NULL)
  428. continue;
  429. CComVariant var;
  430. // If raw entry skip it - we don't handle it for property bags just yet
  431. if (pMap[i].dwSizeData != 0)
  432. {
  433. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  434. // check the type - we only deal with limited set
  435. bool bTypeOK = false;
  436. switch (pMap[i].vt)
  437. {
  438. case VT_UI1:
  439. case VT_I1:
  440. var.bVal = *((BYTE*)pData);
  441. bTypeOK = true;
  442. break;
  443. case VT_BOOL:
  444. var.boolVal = *((VARIANT_BOOL*)pData);
  445. bTypeOK = true;
  446. break;
  447. case VT_I2: // Added by TC
  448. case VT_UI2:
  449. var.iVal = *((short*)pData);
  450. bTypeOK = true;
  451. break;
  452. case VT_I4: // Added by TC
  453. case VT_UI4:
  454. case VT_INT:
  455. case VT_UINT:
  456. var.lVal = *((long*)pData);
  457. bTypeOK = true;
  458. break;
  459. /////////////////////////////////////////////////////////////////////
  460. // The following all added by TC //
  461. case VT_R4: //
  462. var.fltVal = *((float*)pData); //
  463. bTypeOK = true; //
  464. break; //
  465. case VT_R8: //
  466. var.dblVal = *((double*)pData); //
  467. bTypeOK = true; //
  468. break; //
  469. case VT_CY: //
  470. var.cyVal = *((CY*)pData); //
  471. bTypeOK = true; //
  472. break; //
  473. case VT_DATE: //
  474. var.date = *((DATE*)pData); //
  475. bTypeOK = true; //
  476. break; //
  477. case VT_ERROR: //
  478. var.scode = *((SCODE*)pData); //
  479. bTypeOK = true; //
  480. break; //
  481. case VT_DECIMAL: //
  482. var.pdecVal = ((DECIMAL*)pData); //
  483. bTypeOK = true; //
  484. break; //
  485. /////////////////////////////////////////////////////////////////////
  486. // TODO: Implement the following VARIANT types //
  487. case VT_BSTR: // Tricky: different ways to store a BSTR //
  488. break; //
  489. case VT_UNKNOWN: // Tricky: different ways to store a IUnknown* //
  490. case VT_DISPATCH: // Tricky: different ways to store a IDispatch*//
  491. continue; //
  492. case VT_VARIANT: // Tricky: different ways to store a VARIANT //
  493. continue; //
  494. case VT_RECORD: // Tricky: how possible? //
  495. continue; //
  496. case VT_ARRAY: // Very tricky: Also, caution: OR flag //
  497. continue; //
  498. case VT_BYREF: // Shouldn't be TOO tricky. Caution: OR flag //
  499. continue; //
  500. /////////////////////////////////////////////////////////////////////
  501. }
  502. if (bTypeOK)
  503. {
  504. var.vt = pMap[i].vt;
  505. HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
  506. if (FAILED(hr))
  507. return hr;
  508. }
  509. continue;
  510. }
  511. if(pMap[i].piidDispatch != piidOld)
  512. {
  513. pDispatch.Release();
  514. if(FAILED(ControlQueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  515. {
  516. _TRACE_BEGIN
  517. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  518. _TRACE_PART("IPersistPropertyBag_Save(): Failed to get a dispatch ");
  519. _TRACE_PART("pointer for property #%i, \"%ls\"\n", i, pMap[i].szDesc);
  520. _TRACE_END
  521. return E_FAIL;
  522. }
  523. piidOld = pMap[i].piidDispatch;
  524. }
  525. if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  526. {
  527. _TRACE_BEGIN
  528. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  529. _TRACE_PART("IPersistPropertyBag_Save(): Invoke failed on DISPID ");
  530. _TRACE_PART("0x%x, \"%ls\"\n", pMap[i].dispid, pMap[i].szDesc);
  531. _TRACE_END
  532. return E_FAIL;
  533. }
  534. if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH)
  535. {
  536. if (var.pUnkVal == NULL)
  537. {
  538. _TRACE_BEGIN
  539. _TRACE_PART("TCComPropertyClass<%hs>::", m_pszType);
  540. _TRACE_PART("IPersistPropertyBag_Save(): ");
  541. _TRACE_PART("Warning skipping empty IUnknown in Save\n");
  542. _TRACE_END
  543. continue;
  544. }
  545. }
  546. HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
  547. if (FAILED(hr))
  548. return hr;
  549. }
  550. if (fClearDirty)
  551. SetDirty(FALSE);
  552. return S_OK;
  553. }
  554. /////////////////////////////////////////////////////////////////////////////
  555. // TCPersistStreamInitImpl extends ATL's IPersistStreamInitImpl class to
  556. // provide an implementation of the *IPersistStreamInit::GetSizeMax* „
  557. // interface method.
  558. //
  559. // Parameters:
  560. // T - The class derived from TCPersistStreamInitImpl.
  561. //
  562. template <class T>
  563. class ATL_NO_VTABLE TCPersistStreamInitImpl :
  564. public IPersistStreamInit
  565. {
  566. // Group=Types
  567. public:
  568. // Declares a type definition to allow derived classes an easier way to
  569. // refer to the base class.
  570. typedef TCPersistStreamInitImpl<T> TCPersistStreamInitImplBase;
  571. // Group=IPersist Interface Methods
  572. public:
  573. STDMETHODIMP GetClassID(CLSID *pClassID);
  574. // Group=IPersistStream Interface Methods
  575. public:
  576. STDMETHODIMP IsDirty();
  577. STDMETHODIMP Load(IStream* pStm);
  578. STDMETHODIMP Save(IStream* pStm, BOOL fClearDirty);
  579. STDMETHODIMP GetSizeMax(ULARGE_INTEGER* pcbSize);
  580. // Group=IPersistStreamInit Interface Methods
  581. public:
  582. STDMETHODIMP InitNew();
  583. // Group=Implementation
  584. public:
  585. HRESULT IPersistStreamInit_Load(IStream* pStm, ATL_PROPMAP_ENTRY* pMap);
  586. HRESULT IPersistStreamInit_Save(IStream* pStm, BOOL fClearDirty,
  587. ATL_PROPMAP_ENTRY* pMap);
  588. };
  589. /////////////////////////////////////////////////////////////////////////////
  590. // Group=IPersist Interface Methods
  591. template <class T>
  592. STDMETHODIMP TCPersistStreamInitImpl::GetClassID(CLSID *pClassID)
  593. {
  594. _TRACE0("TCPersistStreamInitImpl::GetClassID\n");
  595. *pClassID = T::GetObjectCLSID();
  596. return S_OK;
  597. }
  598. /////////////////////////////////////////////////////////////////////////////
  599. // Group=IPersistStream Interface Methods
  600. template <class T>
  601. STDMETHODIMP TCPersistStreamInitImpl::IsDirty()
  602. {
  603. _TRACE0("TCPersistStreamInitImpl::IsDirty\n");
  604. T* pT = static_cast<T*>(this);
  605. return (pT->m_bRequiresSave) ? S_OK : S_FALSE;
  606. }
  607. template <class T>
  608. STDMETHODIMP TCPersistStreamInitImpl::Load(IStream* pStm)
  609. {
  610. _TRACE0("TCPersistStreamInitImpl::Load\n");
  611. T* pT = static_cast<T*>(this);
  612. return pT->IPersistStreamInit_Load(pStm, T::GetPropertyMap());
  613. }
  614. template <class T>
  615. STDMETHODIMP TCPersistStreamInitImpl::Save(IStream* pStm, BOOL fClearDirty)
  616. {
  617. T* pT = static_cast<T*>(this);
  618. _TRACE0("TCPersistStreamInitImpl::Save\n");
  619. return pT->IPersistStreamInit_Save(pStm, fClearDirty, T::GetPropertyMap());
  620. }
  621. /////////////////////////////////////////////////////////////////////////////
  622. // Description: Returns the size, in bytes, of the stream needed to save the
  623. // object.
  624. //
  625. // This function implements the *IPersistStreamInit::GetSizeMax* interface
  626. // method by calling the TCGetPersistStreamSize global function.
  627. //
  628. // Parameters:
  629. // pCbSize - [out] Points to a 64-bit unsigned integer value indicating the
  630. // size in bytes of the stream needed to save this object.
  631. //
  632. // Return Value: *S_OK* indicates that the size was successfully returned.
  633. //
  634. // See Also: TCNullStream, CTCNullStream
  635. template <class T>
  636. STDMETHODIMP TCPersistStreamInitImpl<T>::GetSizeMax(ULARGE_INTEGER* pcbSize)
  637. {
  638. // Get the derived class pointer
  639. T* pThis = static_cast<T*>(this);
  640. // Determine the max size by writing to a null stream
  641. HRESULT hr = TCGetPersistStreamSize(pThis->GetUnknown(), pcbSize);
  642. // Display trace information under _DEBUG builds
  643. _TRACE_BEGIN
  644. _TRACE_PART("TCPersistStreamInitImpl<%hs>::GetSizeMax():", TCTypeName(T));
  645. if (SUCCEEDED(hr))
  646. _TRACE_PART("%s Counted 0x%08X (%d) bytes\n", szMsg, pcbSize->LowPart,
  647. pcbSize->LowPart);
  648. else
  649. _TRACE_PART("%s Failed, hr = 0x%08X\n", szMsg, hr);
  650. _TRACE_END
  651. // Return the last HRESULT
  652. return hr;
  653. }
  654. /////////////////////////////////////////////////////////////////////////////
  655. // Group=IPersistStreamInit Interface Methods
  656. template <class T>
  657. STDMETHODIMP TCPersistStreamInitImpl::InitNew()
  658. {
  659. _TRACE0("TCPersistStreamInitImpl::InitNew\n");
  660. return S_OK;
  661. }
  662. /////////////////////////////////////////////////////////////////////////////
  663. // Group=Implementation
  664. template <class T>
  665. HRESULT TCPersistStreamInitImpl::IPersistStreamInit_Load(IStream* pStm,
  666. ATL_PROPMAP_ENTRY* pMap)
  667. {
  668. T* pT = static_cast<T*>(this);
  669. HRESULT hr = pT->TCPersistStreamInit_Load(pStm, pMap);
  670. if (SUCCEEDED(hr))
  671. pT->m_bRequiresSave = FALSE;
  672. return hr;
  673. }
  674. template <class T>
  675. HRESULT TCPersistStreamInitImpl::IPersistStreamInit_Save(IStream* pStm,
  676. BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap)
  677. {
  678. T* pT = static_cast<T*>(this);
  679. return pT->TCPersistStreamInit_Save(pStm, fClearDirty, pMap);
  680. }
  681. /////////////////////////////////////////////////////////////////////////////
  682. // TCPersistPropertyBagImpl
  683. //
  684. //
  685. // Parameters:
  686. // T - The class derived from TCPersistPropertyBagImpl
  687. //
  688. template <class T>
  689. class ATL_NO_VTABLE TCPersistPropertyBagImpl :
  690. public IPersistPropertyBag
  691. {
  692. // IPersist Interface Methods
  693. public:
  694. STDMETHODIMP GetClassID(CLSID *pClassID)
  695. // IPersistPropertyBag Interface Methods
  696. public:
  697. STDMETHODIMP InitNew();
  698. STDMETHODIMP Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog);
  699. STDMETHODIMP Save(IPropertyBag* pPropBag, BOOL fClearDirty,
  700. BOOL fSaveAllProperties);
  701. // Implementation
  702. public:
  703. HRESULT IPersistPropertyBag_Load(IPropertyBag* pPropBag,
  704. IErrorLog* pErrorLog, ATL_PROPMAP_ENTRY* pMap);
  705. HRESULT IPersistPropertyBag_Save(IPropertyBag* pPropBag, BOOL fClearDirty,
  706. BOOL fSaveAllProperties, ATL_PROPMAP_ENTRY* pMap);
  707. };
  708. /////////////////////////////////////////////////////////////////////////////
  709. // IPersist Interface Methods
  710. STDMETHODIMP TCPersistPropertyBagImpl::GetClassID(CLSID *pClassID)
  711. {
  712. _TRACE0("IPersistPropertyBagImpl::GetClassID\n");
  713. *pClassID = T::GetObjectCLSID();
  714. return S_OK;
  715. }
  716. /////////////////////////////////////////////////////////////////////////////
  717. // IPersistPropertyBag Interface Methods
  718. STDMETHODIMP TCPersistPropertyBagImpl::InitNew()
  719. {
  720. _TRACE0("IPersistPropertyBagImpl::InitNew\n");
  721. return S_OK;
  722. }
  723. STDMETHODIMP TCPersistPropertyBagImpl::Load(IPropertyBag* pPropBag,
  724. IErrorLog* pErrorLog)
  725. {
  726. _TRACE0("IPersistPropertyBagImpl::Load\n");
  727. T* pT = static_cast<T*>(this);
  728. ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  729. ATLASSERT(pMap != NULL);
  730. return pT->IPersistPropertyBag_Load(pPropBag, pErrorLog, pMap);
  731. }
  732. STDMETHODIMP TCPersistPropertyBagImpl::Save(IPropertyBag* pPropBag,
  733. BOOL fClearDirty, BOOL fSaveAllProperties)
  734. {
  735. _TRACE0("IPersistPropertyBagImpl::Save\n");
  736. T* pT = static_cast<T*>(this);
  737. ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  738. ATLASSERT(pMap != NULL);
  739. return pT->IPersistPropertyBag_Save(pPropBag, fClearDirty,
  740. fSaveAllProperties, pMap);
  741. }
  742. /////////////////////////////////////////////////////////////////////////////
  743. // Implementation
  744. HRESULT TCPersistPropertyBagImpl::IPersistPropertyBag_Load(
  745. IPropertyBag* pPropBag, IErrorLog* pErrorLog, ATL_PROPMAP_ENTRY* pMap)
  746. {
  747. T* pT = static_cast<T*>(this);
  748. HRESULT hr = pT->TCPersistPropertyBag_Load(pPropBag, pErrorLog, pMap);
  749. if (SUCCEEDED(hr))
  750. pT->m_bRequiresSave = FALSE;
  751. return hr;
  752. }
  753. HRESULT TCPersistPropertyBagImpl::IPersistPropertyBag_Save(
  754. IPropertyBag* pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties,
  755. ATL_PROPMAP_ENTRY* pMap)
  756. {
  757. T* pT = static_cast<T*>(this);
  758. return pT->TCPersistPropertyBag_Save(pPropBag, fClearDirty,
  759. fSaveAllProperties, pMap);
  760. }
  761. /////////////////////////////////////////////////////////////////////////////
  762. #endif // !__Persist_h__