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
14 KiB

  1. #include "privcpp.h"
  2. // Constructor
  3. CPackage_IPersistStorage::CPackage_IPersistStorage(CPackage *pPackage) :
  4. _pPackage(pPackage)
  5. {
  6. ASSERT(_cRef == 0);
  7. ASSERT(_psState == PSSTATE_UNINIT);
  8. }
  9. CPackage_IPersistStorage::~CPackage_IPersistStorage()
  10. {
  11. DebugMsg(DM_TRACE,"CPackage_IPersistStorage destroyed with ref count %d",_cRef);
  12. }
  13. //////////////////////////////////
  14. //
  15. // IUnknown Methods...
  16. //
  17. HRESULT CPackage_IPersistStorage::QueryInterface(REFIID iid, void ** ppv)
  18. {
  19. return _pPackage->QueryInterface(iid,ppv); // delegate to CPackage
  20. }
  21. ULONG CPackage_IPersistStorage::AddRef(void)
  22. {
  23. _cRef++; // interface ref count for debug
  24. return _pPackage->AddRef(); // delegate to CPackage
  25. }
  26. ULONG CPackage_IPersistStorage::Release(void)
  27. {
  28. _cRef--; // interface ref count for debug
  29. return _pPackage->Release(); // delegate to CPackage
  30. }
  31. //////////////////////////////////
  32. //
  33. // IPersistStorage Methods...
  34. //
  35. HRESULT CPackage_IPersistStorage::GetClassID(LPCLSID pClassID)
  36. {
  37. DebugMsg(DM_TRACE, "pack ps - GetClassID() called.");
  38. if (_psState == PSSTATE_UNINIT)
  39. return E_UNEXPECTED;
  40. if (pClassID == NULL)
  41. return E_INVALIDARG;
  42. *pClassID = CLSID_CPackage;
  43. return S_OK;
  44. }
  45. HRESULT CPackage_IPersistStorage::IsDirty(void)
  46. {
  47. DebugMsg(DM_TRACE,
  48. "pack ps - IsDirty() called. _fIsDirty==%d",
  49. (INT)_pPackage->_fIsDirty);
  50. if (_psState == PSSTATE_UNINIT)
  51. return E_UNEXPECTED;
  52. return (_pPackage->_fIsDirty ? S_OK : S_FALSE);
  53. }
  54. HRESULT CPackage_IPersistStorage::InitNew(IStorage *pstg)
  55. {
  56. HRESULT hr;
  57. DebugMsg(DM_TRACE, "pack ps - InitNew() called.");
  58. if (_psState != PSSTATE_UNINIT)
  59. return E_UNEXPECTED;
  60. if (!pstg)
  61. return E_POINTER;
  62. // Create a stream to save the package and cache the pointer. By doing
  63. // this now we ensure being able to save in low memory conditions.
  64. //
  65. hr = pstg->CreateStream(SZCONTENTS,STGM_DIRECT | STGM_CREATE |
  66. STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0,
  67. &_pPackage->_pstm);
  68. if (SUCCEEDED(hr))
  69. {
  70. hr = WriteFmtUserTypeStg(pstg, (CLIPFORMAT)_pPackage->_cf,SZUSERTYPE);
  71. if (SUCCEEDED(hr))
  72. {
  73. _pPackage->_fIsDirty = TRUE;
  74. _psState = PSSTATE_SCRIBBLE;
  75. _pPackage->_pIStorage = pstg; // cache the IStorage pointer
  76. _pPackage->_pIStorage->AddRef(); // but don't forget to addref it!
  77. DebugMsg(DM_TRACE, " leaving InitNew()");
  78. }
  79. else
  80. {
  81. _pPackage->_pstm->Release();
  82. _pPackage->_pstm = NULL;
  83. }
  84. }
  85. return hr;
  86. }
  87. HRESULT CPackage_IPersistStorage::Load(IStorage *pstg)
  88. {
  89. HRESULT hr;
  90. LPSTREAM pstm = NULL; // package contents
  91. CLSID clsid;
  92. DebugMsg(DM_TRACE, "pack ps - Load() called.");
  93. if (_psState != PSSTATE_UNINIT) {
  94. DebugMsg(DM_TRACE," wrong state!!");
  95. return E_UNEXPECTED;
  96. }
  97. if (!pstg) {
  98. DebugMsg(DM_TRACE," bad pointer!!");
  99. return E_POINTER;
  100. }
  101. // check to make sure this is one of our storages
  102. hr = ReadClassStg(pstg, &clsid);
  103. if (SUCCEEDED(hr) &&
  104. (clsid != CLSID_CPackage && clsid != CLSID_OldPackage) || FAILED(hr))
  105. {
  106. DebugMsg(DM_TRACE," bad storage type!!");
  107. return E_UNEXPECTED;
  108. }
  109. hr = pstg->OpenStream(SZCONTENTS,0, STGM_DIRECT | STGM_READWRITE |
  110. STGM_SHARE_EXCLUSIVE, 0, &pstm);
  111. if (FAILED(hr)) {
  112. DebugMsg(DM_TRACE," couldn't open contents stream!!");
  113. DebugMsg(DM_TRACE," hr==%Xh",hr);
  114. goto ErrRet;
  115. }
  116. hr = _pPackage->PackageReadFromStream(pstm);
  117. if (FAILED(hr))
  118. goto ErrRet;
  119. _pPackage->_pstm = pstm;
  120. _pPackage->_pIStorage = pstg;
  121. pstg->AddRef();
  122. _psState = PSSTATE_SCRIBBLE;
  123. _pPackage->_fIsDirty = FALSE;
  124. _pPackage->_fLoaded = TRUE;
  125. DebugMsg(DM_TRACE, " leaving Load()");
  126. return S_OK;
  127. ErrRet:
  128. if (pstm)
  129. pstm->Release();
  130. return hr;
  131. }
  132. HRESULT CPackage_IPersistStorage::Save(IStorage *pstg, BOOL fSameAsLoad)
  133. {
  134. HRESULT hr;
  135. LPSTREAM pstm=NULL;
  136. DebugMsg(DM_TRACE, "pack ps - Save() called.");
  137. // must come here from scribble state
  138. if ((_psState != PSSTATE_SCRIBBLE) && fSameAsLoad) {
  139. DebugMsg(DM_TRACE," bad state!!");
  140. return E_UNEXPECTED;
  141. }
  142. // must have an IStorage if not SameAsLoad
  143. if (!pstg && !fSameAsLoad) {
  144. DebugMsg(DM_TRACE," bad pointer!!");
  145. return E_POINTER;
  146. }
  147. // hopefully, the container calls WriteClassStg with our CLSID before
  148. // we get here, that way we can overwrite that and write out the old
  149. // packager's CLSID so that the old packager can read new packages.
  150. //
  151. if (FAILED(WriteClassStg(pstg,CLSID_OldPackage))) {
  152. DebugMsg(DM_TRACE,
  153. " couldn't write CLSID to storage!!");
  154. return E_FAIL;
  155. }
  156. //
  157. // ok, we have four possible ways we could be calling Save:
  158. // 1. we're creating a new package and saving to the same
  159. // storage we received in InitNew
  160. // 2. We're creating a new package and saving to a different
  161. // storage than we received in InitNew
  162. // 3. We were loaded by a container and we're saving to the
  163. // same stream we received in Load
  164. // 4. We were loaded by a container and we're saving to a
  165. // different stream than we received in Load
  166. //
  167. //////////////////////////////////////////////////////////////////
  168. //
  169. // Same Storage as Load
  170. //
  171. //////////////////////////////////////////////////////////////////
  172. if (fSameAsLoad) {
  173. DebugMsg(DM_TRACE," Same as load.");
  174. LARGE_INTEGER li = {0,0};
  175. pstm = _pPackage->_pstm;
  176. // If we're not dirty, so there's nothing new to save.
  177. if (FALSE == _pPackage->_fIsDirty) {
  178. DebugMsg(DM_TRACE, " not saving cause we're not dirty!!");
  179. return S_OK;
  180. }
  181. // if we are dirty, set the seek pointer to the beginning and write
  182. // the package information to the stream
  183. hr = pstm->Seek(li, STREAM_SEEK_SET, NULL);
  184. if (FAILED(hr)) {
  185. DebugMsg(DM_TRACE, " couldn't set contents pointer!!");
  186. return hr;
  187. }
  188. // case 1: new package
  189. if (!_pPackage->_fLoaded) {
  190. switch(_pPackage->_panetype) {
  191. LPTSTR temp;
  192. case PEMBED:
  193. // if haven't created a temp file yet, then use the the
  194. // file to be packaged to get our file contents from,
  195. // otherwise we just use the temp file, because if we
  196. // have a temp file, it contains the most recent info.
  197. //
  198. temp = _pPackage->_pEmbed->pszTempName;
  199. if (!_pPackage->_pEmbed->pszTempName) {
  200. DebugMsg(DM_TRACE, " case 1a:not loaded, using initFile.");
  201. _pPackage->_pEmbed->pszTempName = _pPackage->_pEmbed->fd.cFileName;
  202. }
  203. else {
  204. DebugMsg(DM_TRACE, " case 1b:not loaded, using tempfile.");
  205. }
  206. hr = _pPackage->PackageWriteToStream(pstm);
  207. // reset our temp name back, since we might have changed it
  208. // basically, this just sets it to NULL if it was before
  209. _pPackage->_pEmbed->pszTempName = temp;
  210. break;
  211. case CMDLINK:
  212. // nothing screwy to do here...just write out the info
  213. // which we already have in memory.
  214. hr = _pPackage->PackageWriteToStream(pstm);
  215. break;
  216. }
  217. if (FAILED(hr))
  218. return hr;
  219. }
  220. // case 3: loaded package
  221. else {
  222. hr = _pPackage->PackageWriteToStream(pstm);
  223. }
  224. }
  225. //////////////////////////////////////////////////////////////////
  226. //
  227. // NEW Storage
  228. //
  229. //////////////////////////////////////////////////////////////////
  230. else {
  231. DebugMsg(DM_TRACE," NOT same as load.");
  232. hr = pstg->CreateStream(SZCONTENTS,STGM_DIRECT | STGM_CREATE |
  233. STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0,
  234. &pstm);
  235. if (FAILED(hr)) {
  236. DebugMsg(DM_TRACE, " couldn't create contents stream!!");
  237. return hr;
  238. }
  239. WriteFmtUserTypeStg(pstg, (CLIPFORMAT)_pPackage->_cf,SZUSERTYPE);
  240. // case 2:
  241. if (!_pPackage->_fLoaded) {
  242. switch(_pPackage->_panetype) {
  243. LPTSTR temp;
  244. case PEMBED:
  245. temp = _pPackage->_pEmbed->pszTempName;
  246. if (!_pPackage->_pEmbed->pszTempName) {
  247. DebugMsg(DM_TRACE, " case 2a:not loaded, using initFile.");
  248. _pPackage->_pEmbed->pszTempName = _pPackage->_pEmbed->fd.cFileName;
  249. }
  250. else {
  251. DebugMsg(DM_TRACE, " case 2b:not loaded, using tempfile.");
  252. }
  253. hr = _pPackage->PackageWriteToStream(pstm);
  254. // reset our temp name back, since we might have changed it
  255. // basically, this just sets it to NULL if it was before
  256. _pPackage->_pEmbed->pszTempName = temp;
  257. break;
  258. case CMDLINK:
  259. // nothing interesting to do here, other than write out
  260. // the package.
  261. hr = _pPackage->PackageWriteToStream(pstm);
  262. break;
  263. }
  264. if (FAILED(hr))
  265. goto ErrRet;
  266. }
  267. // case 4:
  268. else {
  269. if (_pPackage->_panetype == PEMBED && _pPackage->_pEmbed->pszTempName ) {
  270. DebugMsg(DM_TRACE," case 4a:loaded, using tempfile.");
  271. hr = _pPackage->PackageWriteToStream(pstm);
  272. if (FAILED(hr))
  273. goto ErrRet;
  274. }
  275. else {
  276. DebugMsg(DM_TRACE," case 4b:loaded, using stream.");
  277. ULARGE_INTEGER uli = { 0xFFFFFFFF, 0xFFFFFFFF };
  278. LARGE_INTEGER li = {0,0};
  279. hr = _pPackage->_pstm->Seek(li,STREAM_SEEK_SET,NULL);
  280. if (FAILED(hr))
  281. goto ErrRet;
  282. hr = _pPackage->_pstm->CopyTo(pstm,uli,NULL,NULL);
  283. if (FAILED(hr))
  284. goto ErrRet;
  285. }
  286. }
  287. ErrRet:
  288. UINT u = pstm->Release();
  289. DebugMsg(DM_TRACE," new stream released. cRef==%d.",u);
  290. if (FAILED(hr))
  291. return hr;
  292. }
  293. _psState = PSSTATE_ZOMBIE;
  294. DebugMsg(DM_TRACE, " leaving Save()");
  295. return S_OK;
  296. }
  297. HRESULT CPackage_IPersistStorage::SaveCompleted(IStorage *pstg)
  298. {
  299. HRESULT hr;
  300. LPSTREAM pstm;
  301. DebugMsg(DM_TRACE, "pack ps - SaveCompleted() called.");
  302. // must be called from no-scribble or hands-off state
  303. if (!(_psState == PSSTATE_ZOMBIE || _psState == PSSTATE_HANDSOFF))
  304. return E_UNEXPECTED;
  305. // if we're hands-off, we'd better get a storage to re-init from
  306. if (!pstg && _psState == PSSTATE_HANDSOFF)
  307. return E_UNEXPECTED;
  308. // if pstg is NULL then we have everything we need, otherwise we must
  309. // release our held pointers and reinitialize.
  310. //
  311. if (pstg != NULL) {
  312. DebugMsg(DM_TRACE, " getting new storage.");
  313. hr = pstg->OpenStream(SZCONTENTS, 0, STGM_DIRECT | STGM_READWRITE |
  314. STGM_SHARE_EXCLUSIVE, 0, &pstm);
  315. if (FAILED(hr))
  316. return hr;
  317. if (_pPackage->_pstm != NULL)
  318. _pPackage->_pstm->Release();
  319. // this will be reinitialized when it's needed
  320. if (_pPackage->_pstmFileContents != NULL) {
  321. _pPackage->_pstmFileContents->Release();
  322. _pPackage->_pstmFileContents = NULL;
  323. }
  324. if (_pPackage->_pIStorage != NULL)
  325. _pPackage->_pIStorage->Release();
  326. _pPackage->_pstm = pstm;
  327. _pPackage->_pIStorage = pstg;
  328. _pPackage->_pIStorage->AddRef();
  329. }
  330. _psState = PSSTATE_SCRIBBLE;
  331. _pPackage->_fIsDirty = FALSE;
  332. DebugMsg(DM_TRACE, " leaving SaveCompleted()");
  333. return S_OK;
  334. }
  335. HRESULT CPackage_IPersistStorage::HandsOffStorage(void)
  336. {
  337. DebugMsg(DM_TRACE, "pack ps - HandsOffStorage() called.");
  338. // must come from scribble or no-scribble. a repeated call to
  339. // HandsOffStorage is an unexpected error (bug in client).
  340. //
  341. if (_psState == PSSTATE_UNINIT || _psState == PSSTATE_HANDSOFF)
  342. return E_UNEXPECTED;
  343. // release our held pointers
  344. //
  345. if (_pPackage->_pstmFileContents != NULL) {
  346. _pPackage->_pstmFileContents->Release();
  347. _pPackage->_pstmFileContents = NULL;
  348. }
  349. if (_pPackage->_pstm != NULL) {
  350. _pPackage->_pstm->Release();
  351. _pPackage->_pstm = NULL;
  352. }
  353. if (_pPackage->_pIStorage != NULL) {
  354. _pPackage->_pIStorage->Release();
  355. _pPackage->_pIStorage = NULL;
  356. }
  357. _psState = PSSTATE_HANDSOFF;
  358. DebugMsg(DM_TRACE, " leaving HandsOffStorage()");
  359. return S_OK;
  360. }