Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

447 lines
11 KiB

  1. /*++
  2. Copyright (C) 1993-1999 Microsoft Corporation
  3. Module Name:
  4. iperstor.cpp
  5. Abstract:
  6. Implementation of the IPersistStorage interface exposed on the
  7. Polyline object.
  8. --*/
  9. #include "polyline.h"
  10. #include "unkhlpr.h"
  11. #include "unihelpr.h"
  12. #include "utils.h"
  13. /*
  14. * CImpIPersistStorage interface implementation
  15. */
  16. CImpIPersistStorage::CImpIPersistStorage(PCPolyline pObj
  17. , LPUNKNOWN pUnkOuter)
  18. {
  19. m_cRef=0;
  20. m_pObj=pObj;
  21. m_pUnkOuter=pUnkOuter;
  22. m_psState=PSSTATE_UNINIT;
  23. return;
  24. }
  25. CImpIPersistStorage::~CImpIPersistStorage(void)
  26. {
  27. return;
  28. }
  29. IMPLEMENT_CONTAINED_IUNKNOWN(CImpIPersistStorage)
  30. /*
  31. * CImpIPersistStorage::GetClassID
  32. *
  33. * Purpose:
  34. * Returns the CLSID of the object represented by this interface.
  35. *
  36. * Parameters:
  37. * pClsID LPCLSID in which to store our CLSID.
  38. *
  39. * Return Value:
  40. * HRESULT NOERROR on success, error code otherwise.
  41. */
  42. STDMETHODIMP CImpIPersistStorage::GetClassID(LPCLSID pClsID)
  43. {
  44. //----------------------------------------------------------------
  45. // THE OLECONT.EXE test container call this in the UNINIT state!
  46. // Go ahead and return the ClsID.
  47. //-----------------------------------------------------------------
  48. // if (PSSTATE_UNINIT==m_psState)
  49. // return ResultFromScode(E_UNEXPECTED);
  50. *pClsID=m_pObj->m_clsID;
  51. return NOERROR;
  52. }
  53. /*
  54. * CImpIPersistStorage::IsDirty
  55. *
  56. * Purpose:
  57. * Tells the caller if we have made changes to this object since
  58. * it was loaded or initialized new.
  59. *
  60. * Parameters:
  61. * None
  62. *
  63. * Return Value:
  64. * HRESULT Contains S_OK if we ARE dirty, S_FALSE if
  65. * NOT dirty.
  66. *
  67. */
  68. STDMETHODIMP CImpIPersistStorage::IsDirty(void)
  69. {
  70. if (PSSTATE_UNINIT==m_psState)
  71. return ResultFromScode(E_UNEXPECTED);
  72. return ResultFromScode(m_pObj->m_fDirty ? S_OK : S_FALSE);
  73. }
  74. /*
  75. * CImpIPersistStorage::InitNew
  76. *
  77. * Purpose:
  78. * Provides the object with the IStorage to hold on to while the
  79. * object is running. Here we initialize the structure of the
  80. * storage and AddRef it for incremental access. This function will
  81. * only be called once in the object's lifetime in lieu of Load.
  82. *
  83. * Parameters:
  84. * pIStorage LPSTORAGE for the object.
  85. *
  86. * Return Value:
  87. * HRESULT NOERROR or a general error value.
  88. */
  89. STDMETHODIMP CImpIPersistStorage::InitNew(LPSTORAGE pIStorage)
  90. {
  91. HRESULT hr;
  92. USES_CONVERSION
  93. if (PSSTATE_UNINIT!=m_psState)
  94. return ResultFromScode(E_UNEXPECTED);
  95. if (NULL==pIStorage)
  96. return ResultFromScode(E_POINTER);
  97. /*
  98. * The rules of IPersistStorage mean we hold onto the IStorage
  99. * and pre-create anything we'd need in Save(...,TRUE) for
  100. * low-memory situations. For us this means creating our
  101. * "CONTENTS" stream and holding onto that IStream as
  102. * well as the IStorage here (requiring an AddRef call).
  103. */
  104. hr=pIStorage->CreateStream(SZSTREAM, STGM_DIRECT
  105. | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  106. , 0, 0, &m_pObj->m_pIStream);
  107. if (FAILED(hr))
  108. return hr;
  109. //We expect that the client has called WriteClassStg
  110. WriteFmtUserTypeStg(pIStorage, m_pObj->m_cf, T2W(ResourceString(IDS_USERTYPE)));
  111. m_pObj->m_pIStorage=pIStorage;
  112. pIStorage->AddRef();
  113. m_psState=PSSTATE_SCRIBBLE;
  114. //Initialize the cache as needed.
  115. m_pObj->m_pDefIPersistStorage->InitNew(pIStorage);
  116. return NOERROR;
  117. }
  118. /*
  119. * CImpIPersistStorage::Load
  120. *
  121. * Purpose:
  122. * Instructs the object to load itself from a previously saved
  123. * IStorage that was handled by Save in another object lifetime.
  124. * This function will only be called once in the object's lifetime
  125. * in lieu of InitNew. The object should hold on to pIStorage here
  126. * for incremental access and low-memory saves in Save.
  127. *
  128. * Parameters:
  129. * pIStorage LPSTORAGE from which to load.
  130. *
  131. * Return Value:
  132. * HRESULT NOERROR or a general error value.
  133. */
  134. STDMETHODIMP CImpIPersistStorage::Load(LPSTORAGE pIStorage)
  135. {
  136. LPSTREAM pIStream;
  137. HRESULT hr;
  138. if (PSSTATE_UNINIT!=m_psState)
  139. return ResultFromScode(E_UNEXPECTED);
  140. if (NULL==pIStorage)
  141. return ResultFromScode(E_POINTER);
  142. //We don't check CLSID to remain compatible with other chapters.
  143. hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT
  144. | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  145. if (FAILED(hr))
  146. return ResultFromScode(STG_E_READFAULT);
  147. // Load graph data from stream
  148. hr = m_pObj->m_pCtrl->LoadFromStream(pIStream);
  149. if (FAILED(hr))
  150. {
  151. pIStream->Release();
  152. return hr;
  153. }
  154. /*
  155. * We don't call pIStream->Release here because we may need
  156. * it for a low-memory save in Save. We also need to
  157. * hold onto a copy of pIStorage, meaning AddRef.
  158. */
  159. m_pObj->m_pIStream = pIStream;
  160. m_pObj->m_pIStorage = pIStorage;
  161. pIStorage->AddRef();
  162. m_psState=PSSTATE_SCRIBBLE;
  163. //We also need to tell the cache to load cached graphics
  164. m_pObj->m_pDefIPersistStorage->Load(pIStorage);
  165. return NOERROR;
  166. }
  167. /*
  168. * CImpIPersistStorage::Save
  169. *
  170. * Purpose:
  171. * Saves the data for this object to an IStorage which may
  172. * or may not be the same as the one previously passed to
  173. * Load, indicated with fSameAsLoad. After this call we may
  174. * not write into the storage again until SaveCompleted is
  175. * called, although we may still read.
  176. *
  177. * Parameters:
  178. * pIStorage LPSTORAGE in which to save our data.
  179. * fSameAsLoad BOOL indicating if this is the same pIStorage
  180. * that was passed to Load. If TRUE, then the
  181. * object should write whatever it has *without
  182. * *using any extra memory* as this may be a low
  183. * memory save attempt. That means that you must
  184. * not try to open or create streams. If FALSE
  185. * you need to regenerate your whole storage
  186. * structure, being sure to also release any
  187. * pointers held from InitNew and Load.
  188. *
  189. * Return Value:
  190. * HRESULT NOERROR or a general error value.
  191. */
  192. STDMETHODIMP CImpIPersistStorage::Save(LPSTORAGE pIStorage
  193. , BOOL fSameAsLoad)
  194. {
  195. LPSTREAM pIStream;
  196. HRESULT hr;
  197. USES_CONVERSION
  198. // Permit call in UNINIT state, if not SameAsLoad
  199. if (PSSTATE_UNINIT == m_psState && fSameAsLoad)
  200. return ResultFromScode(E_POINTER);
  201. //Must have an IStorage if we're not in SameAsLoad
  202. if (NULL==pIStorage && !fSameAsLoad)
  203. return ResultFromScode(E_POINTER);
  204. /*
  205. * If we're saving to a new storage, create a new stream.
  206. * If fSameAsLoad it TRUE, then we write to the
  207. * stream we already allocated. We should NOT depends on
  208. * pIStorage with fSameAsLoad is TRUE.
  209. */
  210. if (fSameAsLoad)
  211. {
  212. LARGE_INTEGER li;
  213. /*
  214. * Use pre-allocated streams to avoid failures due
  215. * to low-memory conditions. Be sure to reset the
  216. * stream pointer if you used this stream before!!
  217. */
  218. pIStream=m_pObj->m_pIStream;
  219. LISet32(li, 0);
  220. pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  221. //This matches the Release below.
  222. pIStream->AddRef();
  223. }
  224. else
  225. {
  226. hr=pIStorage->CreateStream(SZSTREAM, STGM_DIRECT
  227. | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE
  228. , 0, 0, &pIStream);
  229. if (FAILED(hr))
  230. return hr;
  231. //Only do this with new storages.
  232. WriteFmtUserTypeStg(pIStorage, m_pObj->m_cf, T2W(ResourceString(IDS_USERTYPE)));
  233. }
  234. // Write graph info to stream
  235. hr = m_pObj->m_pCtrl->SaveToStream(pIStream);
  236. pIStream->Release();
  237. if (FAILED(hr))
  238. return hr;
  239. m_psState=PSSTATE_ZOMBIE;
  240. // Clear the dirty flag if storage is the same.
  241. if (fSameAsLoad)
  242. m_pObj->m_fDirty = FALSE;
  243. //We also need to tell the cache to save cached graphics
  244. m_pObj->m_pDefIPersistStorage->Save(pIStorage, fSameAsLoad);
  245. return NOERROR;
  246. }
  247. /*
  248. * CImpIPersistStorage::SaveCompleted
  249. *
  250. * Purpose:
  251. * Notifies the object that the storage in pIStorage has been
  252. * completely saved now. This is called when the user of this
  253. * object wants to save us in a completely new storage, and if
  254. * we normally hang on to the storage we have to reinitialize
  255. * ourselves here for this new one that is now complete.
  256. *
  257. * Parameters:
  258. * pIStorage LPSTORAGE of the new storage in which we live.
  259. *
  260. * Return Value:
  261. * HRESULT NOERROR or a general error value.
  262. */
  263. STDMETHODIMP CImpIPersistStorage::SaveCompleted(LPSTORAGE pIStorage)
  264. {
  265. HRESULT hr;
  266. LPSTREAM pIStream;
  267. //Must be called in no-scribble or hands-off state
  268. if (!(PSSTATE_ZOMBIE==m_psState || PSSTATE_HANDSOFF==m_psState))
  269. return ResultFromScode(E_UNEXPECTED);
  270. //If we're coming from Hands-Off, we'd better get a storage
  271. if (NULL==pIStorage && PSSTATE_HANDSOFF==m_psState)
  272. return ResultFromScode(E_UNEXPECTED);
  273. /*
  274. * If pIStorage is NULL, then we don't need to do anything
  275. * since we already have all the pointers we need for Save.
  276. * Otherwise we have to release any held pointers and
  277. * reinitialize them from pIStorage.
  278. */
  279. if (NULL!=pIStorage)
  280. {
  281. hr=pIStorage->OpenStream(SZSTREAM, 0, STGM_DIRECT
  282. | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0
  283. , &pIStream);
  284. if (FAILED(hr))
  285. return hr;
  286. if (NULL!=m_pObj->m_pIStream)
  287. m_pObj->m_pIStream->Release();
  288. m_pObj->m_pIStream=pIStream;
  289. if (NULL!=m_pObj->m_pIStorage)
  290. m_pObj->m_pIStorage->Release();
  291. m_pObj->m_pIStorage=pIStorage;
  292. m_pObj->m_pIStorage->AddRef();
  293. }
  294. //Change state back to scribble.
  295. m_psState=PSSTATE_SCRIBBLE;
  296. m_pObj->m_pDefIPersistStorage->SaveCompleted(pIStorage);
  297. return NOERROR;
  298. }
  299. /*
  300. * CImpIPersistStorage::HandsOffStorage
  301. *
  302. * Purpose:
  303. * Instructs the object that another agent is interested in having
  304. * total access to the storage we might be hanging on to from
  305. * InitNew or SaveCompleted. In this case we must release our hold
  306. * and await another call to SaveCompleted before we have a hold
  307. * again. Therefore we cannot read or write after this call until
  308. * SaveCompleted.
  309. *
  310. * Situations where this might happen arise in compound document
  311. * scenarios where this object might be in-place active but the
  312. * application wants to rename and commit the root storage.
  313. * Therefore we are asked to close our hold, let the container
  314. * party on the storage, then call us again later to tell us the
  315. * new storage we can hold.
  316. *
  317. * Parameters:
  318. * None
  319. *
  320. * Return Value:
  321. * HRESULT NOERROR or a general error value.
  322. */
  323. STDMETHODIMP CImpIPersistStorage::HandsOffStorage(void)
  324. {
  325. /*
  326. * Must come from scribble or no-scribble. A repeated call
  327. * to HandsOffStorage is an unexpected error (bug in client).
  328. */
  329. if (PSSTATE_UNINIT==m_psState || PSSTATE_HANDSOFF==m_psState)
  330. return ResultFromScode(E_UNEXPECTED);
  331. //Release held pointers
  332. if (NULL!=m_pObj->m_pIStream)
  333. {
  334. m_pObj->m_pIStream->Release();
  335. m_pObj->m_pIStream=NULL;
  336. }
  337. if (NULL!=m_pObj->m_pIStorage)
  338. {
  339. m_pObj->m_pIStorage->Release();
  340. m_pObj->m_pIStorage=NULL;
  341. }
  342. m_psState=PSSTATE_HANDSOFF;
  343. m_pObj->m_pDefIPersistStorage->HandsOffStorage();
  344. return NOERROR;
  345. }