Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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