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.

698 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1994.
  5. //
  6. // File: simpstg2.cxx
  7. //
  8. // Contents: SimpStorageOpen class implementation
  9. //
  10. // Classes: CSimpStorageOpen, CSafeBYTEArray
  11. //
  12. // Functions:
  13. //
  14. // Notes: No error labels, tried to use destructors for cleanup
  15. //
  16. // History: 04-May-96 HenryLee Created
  17. //
  18. //----------------------------------------------------------------------------
  19. #include "simphead.cxx"
  20. #pragma hdrstop
  21. #include <expparam.hxx>
  22. //+---------------------------------------------------------------------------
  23. //
  24. // Class: CSafeBYTEArray
  25. //
  26. // Purpose: automatically allocate & destroy an array of BYTEs
  27. //
  28. // Interface:
  29. //
  30. // History: 04-Jun-96 HenryLee Created
  31. //
  32. // Notes: destructor automatically cleans up
  33. //
  34. //----------------------------------------------------------------------------
  35. class CSafeBYTEArray
  36. {
  37. public:
  38. inline CSafeBYTEArray (ULONG cBYTE) {_p = new BYTE[cBYTE]; };
  39. inline ~CSafeBYTEArray () { if (_p) delete [] _p; };
  40. inline operator BYTE* () { return _p; };
  41. private:
  42. BYTE *_p; // allowed to be NULL
  43. };
  44. //+---------------------------------------------------------------------------
  45. //
  46. // Member: CSimpStorageOpen::Init, public
  47. //
  48. // Synopsis: Init function
  49. //
  50. // Arguments: [psdh] -- Pointer to hints structure
  51. //
  52. // Returns: Appropriate status code
  53. //
  54. // History: 04-May-96 HenryLee Created
  55. // 14-Oct-97 HenryLee recoginize CNSS file format
  56. //
  57. //----------------------------------------------------------------------------
  58. SCODE CSimpStorageOpen::Init(WCHAR const * pwcsName, DWORD grfMode,
  59. SSimpDocfileHints *psdh)
  60. {
  61. SCODE sc = S_OK;
  62. simpDebugOut((DEB_ITRACE,
  63. "In CSimpStorageOpen::Init:%p(%ws)\n", this, pwcsName));
  64. #ifdef UNICODE
  65. TCHAR const *atcPath = pwcsName;
  66. #else
  67. TCHAR atcPath[_MAX_PATH+1];
  68. UINT uCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
  69. if (!WideCharToMultiByte( uCodePage, 0, pwcsName, -1,
  70. atcPath, _MAX_PATH + 1, NULL, NULL))
  71. {
  72. return STG_E_INVALIDNAME;
  73. }
  74. #endif
  75. DWORD dwMode;
  76. switch (grfMode & (STGM_READ | STGM_WRITE | STGM_READWRITE))
  77. {
  78. case STGM_READWRITE : dwMode = GENERIC_READ | GENERIC_WRITE; break;
  79. case STGM_READ : dwMode = GENERIC_READ; break;
  80. case STGM_WRITE : dwMode = GENERIC_WRITE; break;
  81. default: Win4Assert (!"Invalid mode"); return STG_E_INVALIDPARAMETER;
  82. }
  83. _hFile = CreateFileT(atcPath, dwMode, 0,
  84. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  85. if (_hFile == INVALID_HANDLE_VALUE)
  86. {
  87. return Win32ErrorToScode(GetLastError());
  88. }
  89. _grfMode = grfMode;
  90. _sectMax = 0;
  91. _fDirty = FALSE;
  92. _clsid = IID_NULL;
  93. _grfStateBits = 0;
  94. simpAssert (pwcsName != NULL); // CreateFileT would fail above if it was NULL
  95. sc = StringCbCopy(_awcsName, sizeof(_awcsName), pwcsName);
  96. if (FAILED(sc))
  97. return sc;
  98. ULONG cbRead;
  99. BOOL f= ReadFile(_hFile, _hdr.GetData(), HEADERSIZE, &cbRead, NULL);
  100. if (!f)
  101. {
  102. return Win32ErrorToScode(GetLastError());
  103. }
  104. if (cbRead != HEADERSIZE)
  105. {
  106. return STG_E_READFAULT;
  107. }
  108. if (!SUCCEEDED(sc = ValidateHeader(_hdr)))
  109. {
  110. return sc;
  111. }
  112. ULONG ulEndOfFile = GetFileSize(_hFile, NULL);
  113. if (ulEndOfFile == 0xFFFFFFFF && GetLastError() != NO_ERROR)
  114. return Win32ErrorToScode(GetLastError());
  115. const ULONG ulFatStart=_hdr.GetFatStart()*SECTORSIZE + HEADERSIZE;
  116. const ULONG ulDifStart=_hdr.GetDifStart()*SECTORSIZE + HEADERSIZE;
  117. const ULONG ulFatLength = _hdr.GetFatLength()*SECTORSIZE;
  118. const ULONG ulDifLength = _hdr.GetDifLength()*SECTORSIZE;
  119. const ULONG ulDirLength = ulEndOfFile - ulFatStart - ulFatLength;
  120. const ULONG cBytes = ulDirLength + ulFatLength + ulDifLength;
  121. if (ulFatLength == 0 || ulDirLength == 0)
  122. return STG_E_DOCFILECORRUPT;
  123. DWORD dwErr;
  124. CSafeBYTEArray pByte (cBytes);
  125. if (pByte == NULL)
  126. return STG_E_INSUFFICIENTMEMORY;
  127. if ((dwErr = SetFilePointer (_hFile,
  128. (ulDifLength == 0 ? ulFatStart : ulDifStart),
  129. NULL, FILE_BEGIN)) == 0xFFFFFFFF)
  130. {
  131. return Win32ErrorToScode(GetLastError());
  132. }
  133. // Read the FAT, DIFAT, and Directory into one big buffer
  134. //
  135. if (!(f=ReadFile(_hFile, pByte, cBytes, &cbRead, NULL)))
  136. {
  137. return Win32ErrorToScode(GetLastError());
  138. }
  139. if (cbRead != cBytes)
  140. {
  141. return STG_E_READFAULT;
  142. }
  143. if (!SUCCEEDED(sc = ValidateDirectory(
  144. pByte+ulDifLength+ulFatLength, ulDirLength)))
  145. {
  146. return sc;
  147. }
  148. if (!SUCCEEDED(sc = ValidateFat ((SECT*) (pByte+ulDifLength),
  149. ulFatLength)))
  150. {
  151. return sc;
  152. }
  153. if (ulDifLength != 0 && !SUCCEEDED(sc = ValidateDIFat ((SECT *) (pByte+0),
  154. ulDifLength, _hdr.GetFatSect(CSECTFAT-1))))
  155. {
  156. return sc;
  157. }
  158. simpDebugOut((DEB_ITRACE, "Out CSimpStorage::Init\n"));
  159. return sc;
  160. }
  161. //+---------------------------------------------------------------------------
  162. //
  163. // Member: CSimpStorageOpen::ValidateHeader, public
  164. //
  165. // Synopsis: verifies header is in simple mode format
  166. //
  167. // Arguments: [hdr] -- reference to a docfile header
  168. //
  169. // Returns: Appropriate status code
  170. //
  171. // History: 04-May-96 HenryLee Created
  172. // 14-Oct-97 HenryLee recoginize CNSS file format
  173. //
  174. //----------------------------------------------------------------------------
  175. SCODE CSimpStorageOpen::ValidateHeader (CMSFHeader &hdr)
  176. {
  177. SCODE sc = S_OK;
  178. if (!SUCCEEDED(sc = hdr.Validate()))
  179. {
  180. return sc;
  181. }
  182. const SECT sectDifStart = hdr.GetDifStart();
  183. const SECT sectFatStart = hdr.GetFatStart();
  184. const SECT sectDirStart = hdr.GetDirStart();
  185. // in simple mode, DifStart < FatStart < DirStart
  186. //
  187. if(hdr.GetMiniFatStart() != ENDOFCHAIN || hdr.GetMiniFatLength() != 0 ||
  188. (sectDifStart != ENDOFCHAIN && sectDifStart >= sectFatStart))
  189. {
  190. return STG_E_OLDFORMAT;
  191. }
  192. // in simple mode, DifStart+DifLength = FatStart
  193. // FatStart+FatLength = DirStart
  194. //
  195. //
  196. if (sectDifStart != ENDOFCHAIN &&
  197. (sectDifStart + hdr.GetDifLength() != sectFatStart))
  198. {
  199. return STG_E_OLDFORMAT;
  200. }
  201. if (sectDirStart != 0 &&
  202. (sectFatStart + hdr.GetFatLength() != sectDirStart))
  203. {
  204. return STG_E_OLDFORMAT;
  205. }
  206. // make sure the FAT is contiguous within the header
  207. //
  208. for (INT i=1; i < CSECTFAT; i++)
  209. {
  210. if (hdr.GetFatSect(i) == FREESECT)
  211. break;
  212. if (hdr.GetFatSect(i-1)+1 != hdr.GetFatSect(i))
  213. return STG_E_OLDFORMAT;
  214. }
  215. return sc;
  216. }
  217. //+---------------------------------------------------------------------------
  218. //
  219. // Member: CSimpStorageOpen::ValidateDirectory, public
  220. //
  221. // Synopsis: verifies stream entries are correct
  222. //
  223. // Arguments:
  224. //
  225. // Returns: Appropriate status code
  226. //
  227. // History: 04-May-96 HenryLee Created
  228. // 14-Oct-97 HenryLee recoginize CNSS file format
  229. //
  230. //----------------------------------------------------------------------------
  231. SCODE CSimpStorageOpen::ValidateDirectory (BYTE *pByte, ULONG ulDirLength)
  232. {
  233. SCODE sc = S_OK;
  234. CDfNameList *pdflRoot = _pdfl;
  235. SECT sectStartLowest = ENDOFCHAIN;
  236. ULONG ulSize = 0;
  237. ULONG cbStorages = 0;
  238. CDirEntry *pde = (CDirEntry *) pByte;
  239. // Read the directory entries until the end of buffer
  240. CDfNameList *pdflPrev = NULL;
  241. for (ULONG i=0; i < ulDirLength/sizeof(CDirEntry); i++)
  242. {
  243. if (!pde[i].IsFree())
  244. {
  245. if (pde[i].GetFlags() != STGTY_ROOT &&
  246. pde[i].GetFlags() != STGTY_STREAM &&
  247. pde[i].GetFlags() != STGTY_STORAGE)
  248. return STG_E_OLDFORMAT;
  249. if (STORAGELIKE(pde[i].GetFlags()))
  250. {
  251. cbStorages++; // first entry must be a storage
  252. if (pdflPrev != NULL || cbStorages > 1)
  253. return STG_E_OLDFORMAT;
  254. }
  255. if (pde[i].GetRightSib() == (SID) i ||
  256. pde[i].GetLeftSib() == (SID) i)
  257. return STG_E_DOCFILECORRUPT;
  258. CDfNameList *pdfl = new CDfNameList;
  259. if (pdfl != NULL)
  260. {
  261. pdfl->SetDfName(pde[i].GetName());
  262. pdfl->SetStart(pde[i].GetStart());
  263. if (sectStartLowest > pdfl->GetStart())
  264. sectStartLowest = pdfl->GetStart();
  265. #ifdef LARGE_STREAMS
  266. pdfl->SetSize((ULONG)pde[i].GetSize(FALSE));
  267. #else
  268. pdfl->SetSize((ULONG)pde[i].GetSize());
  269. #endif
  270. pdfl->Insert (&_pdfl, pdflPrev, NULL); //insert at end
  271. pdflPrev = pdfl;
  272. }
  273. else return STG_E_INSUFFICIENTMEMORY;
  274. }
  275. }
  276. pdflRoot = _pdfl;
  277. if (pdflRoot == 0 || pdflRoot->GetStart() != ENDOFCHAIN ||
  278. pdflRoot->GetSize() != 0)
  279. {
  280. return STG_E_OLDFORMAT;
  281. }
  282. else pdflRoot = pdflRoot->GetNext();
  283. // make sure streams are one after another
  284. //
  285. for (CDfNameList *pdfl = pdflRoot; pdfl != NULL; pdfl = pdfl->GetNext())
  286. {
  287. // start should be after another stream's end
  288. // In the CNSS case, the pdflRoot points to 1st stream in file
  289. // In the docfile case, entry with 0 start sector is 1st stream in file
  290. if (pdfl->GetStart() != sectStartLowest) // skip 1st stream
  291. {
  292. CDfNameList *pdfl2 = NULL;
  293. for (pdfl2 = pdflRoot; pdfl2 != NULL; pdfl2=pdfl2->GetNext())
  294. {
  295. if (pdfl->GetStart() == (pdfl2->GetStart() + (
  296. pdfl2->GetSize()+SECTORSIZE-1)/SECTORSIZE))
  297. break;
  298. }
  299. if (pdfl2 == NULL) // did not find a match
  300. return STG_E_OLDFORMAT;
  301. }
  302. }
  303. return sc;
  304. }
  305. //+---------------------------------------------------------------------------
  306. //
  307. // Member: CSimpStorageOpen::ValidateFat, public
  308. //
  309. // Synopsis: verifies that stream sectors are contiguous
  310. //
  311. // Arguments: [pSect] array of Fat sectors
  312. // [ulFatLength] length of the Fat
  313. //
  314. // Returns: Appropriate status code
  315. //
  316. // History: 04-May-96 HenryLee Created
  317. //
  318. //----------------------------------------------------------------------------
  319. SCODE CSimpStorageOpen::ValidateFat (SECT *pSect, ULONG ulFatLength)
  320. {
  321. SCODE sc = S_OK;
  322. simpAssert (_pdfl != NULL && pSect != NULL);
  323. for (CDfNameList *pdfl = _pdfl->GetNext(); pdfl; pdfl = pdfl->GetNext())
  324. {
  325. SECT sectStart = pdfl->GetStart();
  326. ULONG ulSize = pdfl->GetSize();
  327. SECT *psect = &pSect[sectStart];
  328. SECT sectCount = sectStart+1;
  329. for (ULONG i = sectStart;
  330. i < sectStart + (ulSize+SECTORSIZE-1)/SECTORSIZE; i++)
  331. {
  332. if (*psect != sectCount && *psect != ENDOFCHAIN)
  333. return STG_E_OLDFORMAT;
  334. psect++; // check for sector numbers
  335. sectCount++; // increasing in order by 1
  336. }
  337. if ((ULONG)(psect - pSect) > ulFatLength / sizeof(SECT))
  338. {
  339. return STG_E_OLDFORMAT;
  340. }
  341. }
  342. return sc;
  343. }
  344. //+---------------------------------------------------------------------------
  345. //
  346. // Member: CSimpStorageOpen::ValidateDIFat, public
  347. //
  348. // Synopsis: verifies that FAT sectors are contiguous
  349. //
  350. // Arguments: [pSect] array of DIFat sectors
  351. // [ulDIFatLength] length of the DIFat
  352. // [sectStart] last Fat sector in header
  353. //
  354. // Returns: Appropriate status code
  355. //
  356. // History: 04-May-96 HenryLee Created
  357. //
  358. //----------------------------------------------------------------------------
  359. SCODE CSimpStorageOpen::ValidateDIFat (SECT *pSect, ULONG ulDIFatLength,
  360. SECT sectStart)
  361. {
  362. SCODE sc = S_OK;
  363. simpAssert (pSect != NULL);
  364. simpAssert (sectStart != ENDOFCHAIN);
  365. SECT *psect = pSect;
  366. SECT sectCount = sectStart + 1;
  367. SECT iLastSect = SECTORSIZE / sizeof(SECT);
  368. for (ULONG i = 0; i < ulDIFatLength/sizeof(SECT); i++)
  369. {
  370. // skip last sector entry
  371. if (*psect != FREESECT && ((i+1) % iLastSect) != 0)
  372. {
  373. if (*psect != sectCount)
  374. return STG_E_OLDFORMAT;
  375. sectCount++; // check for sector numbers increasing by 1
  376. }
  377. psect++;
  378. }
  379. return sc;
  380. }
  381. //+--------------------------------------------------------------
  382. //
  383. // Member: CSimpStorageOpen::Release, public
  384. //
  385. // Synopsis: Releases resources for a CSimpStorageOpen
  386. // override CSimpStorage::Release because of delete this
  387. //
  388. // Returns: Appropriate status code
  389. //
  390. // History: 04-May-96 HenryLee Created
  391. //
  392. //---------------------------------------------------------------
  393. STDMETHODIMP_(ULONG) CSimpStorageOpen::Release(void)
  394. {
  395. simpDebugOut((DEB_TRACE, "In CSimpStorageOpen::Release()\n"));
  396. simpAssert(_cReferences > 0);
  397. LONG lRet = AtomicDec(&_cReferences);
  398. if (lRet == 0)
  399. {
  400. if (_fDirty)
  401. Commit(STGC_DEFAULT);
  402. CloseHandle(_hFile); // streams are not reverted
  403. delete this;
  404. }
  405. simpDebugOut((DEB_TRACE, "Out CSimpStorageOpen::Release()\n"));
  406. return (ULONG) lRet;
  407. }
  408. //+--------------------------------------------------------------
  409. //
  410. // Member: CSimpStorageOpen::Stat, public
  411. //
  412. // Synopsis: Fills in a buffer of information about this object
  413. //
  414. // Arguments: [pstatstg] - Buffer
  415. //
  416. // Returns: Appropriate status code
  417. //
  418. // Modifies: [pstatstg]
  419. //
  420. // History: 04-May-96 HenryLee Created
  421. //
  422. //---------------------------------------------------------------
  423. STDMETHODIMP CSimpStorageOpen::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
  424. {
  425. SCODE sc = S_OK;
  426. simpDebugOut((DEB_TRACE, "In CSimpStorageOpen::Stat(%p)\n", pstatstg));
  427. SIMP_VALIDATE(Stat(pstatstg, grfStatFlag));
  428. if (GetFileTime(_hFile, &pstatstg->ctime, &pstatstg->atime,
  429. &pstatstg->mtime) == FALSE)
  430. {
  431. return Win32ErrorToScode(GetLastError());
  432. }
  433. if ((grfStatFlag & STATFLAG_NONAME) == 0)
  434. {
  435. DWORD cbName;
  436. cbName = (lstrlenW(_awcsName)+1)*sizeof(WCHAR);
  437. if ((pstatstg->pwcsName = (WCHAR*) CoTaskMemAlloc(
  438. cbName)) == 0)
  439. {
  440. return STG_E_INSUFFICIENTMEMORY;
  441. }
  442. StringCbCopy(pstatstg->pwcsName, cbName, _awcsName);
  443. }
  444. pstatstg->grfMode = _grfMode;
  445. pstatstg->clsid = _clsid;
  446. pstatstg->grfStateBits = _grfStateBits;
  447. pstatstg->type = STGTY_STORAGE;
  448. ULISet32(pstatstg->cbSize, 0);
  449. pstatstg->grfLocksSupported = 0;
  450. pstatstg->STATSTG_dwStgFmt = 0;
  451. simpDebugOut((DEB_TRACE, "Out CSimpStorageOpen::Stat\n"));
  452. return sc;
  453. }
  454. //+--------------------------------------------------------------
  455. //
  456. // Member: CSimpStorageOpen::OpenStream, public
  457. //
  458. // Synopsis: Opens an existing stream
  459. //
  460. // Arguments: [pwcsName] - Name
  461. // [reserved1]
  462. // [grfMode] - Permissions
  463. // [reserved2]
  464. // [ppstm] - Stream return
  465. //
  466. // Returns: Appropriate status code
  467. //
  468. // Modifies: [ppstm]
  469. //
  470. // History: 04-May-96 HenryLee Created
  471. //
  472. //---------------------------------------------------------------
  473. STDMETHODIMP CSimpStorageOpen::OpenStream(WCHAR const *pwcsName,
  474. void *reserved1,
  475. DWORD grfMode,
  476. DWORD reserved2,
  477. IStream **ppstm)
  478. {
  479. SCODE sc = S_OK;
  480. simpAssert (_pdfl != NULL);
  481. CDfNameList *pdflLoop = _pdfl->GetNext();
  482. CDfName dfn;
  483. simpDebugOut((DEB_TRACE, "In CSimpStorageOpen:OpenStream("
  484. "%ws, %p, %lX, %lu, %p)\n", pwcsName, reserved1,
  485. grfMode, reserved2, ppstm));
  486. SIMP_VALIDATE(OpenStream(pwcsName,
  487. reserved1,
  488. grfMode,
  489. reserved2,
  490. ppstm));
  491. if (_pdflCurrent != NULL)
  492. return STG_E_INVALIDFUNCTION;
  493. if (grfMode != (STGM_READWRITE | STGM_SHARE_EXCLUSIVE) &&
  494. grfMode != (STGM_READ | STGM_SHARE_EXCLUSIVE))
  495. return STG_E_INVALIDFLAG;
  496. if (_grfMode == (STGM_READ | STGM_SHARE_EXCLUSIVE) &&
  497. grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE))
  498. return STG_E_ACCESSDENIED;
  499. dfn.Set(pwcsName);
  500. while (pdflLoop != NULL)
  501. {
  502. INT iCmp = CDirectory::NameCompare(&dfn, pdflLoop->GetName());
  503. if (iCmp == 0)
  504. {
  505. //Found a stream with this name
  506. CSimpStreamOpen *pstm = new CSimpStreamOpen ();
  507. if (pstm != NULL)
  508. {
  509. _pdflCurrent = pdflLoop;
  510. if (!SUCCEEDED(sc = pstm->Init (this, _hFile,
  511. (_pdflCurrent->GetStart()+1)*SECTORSIZE,
  512. grfMode, _pdflCurrent)))
  513. {
  514. delete pstm;
  515. pstm = NULL;
  516. _pdflCurrent = NULL;
  517. }
  518. *ppstm = pstm;
  519. break;
  520. }
  521. else return STG_E_INSUFFICIENTMEMORY;
  522. }
  523. pdflLoop = pdflLoop->GetNext();
  524. }
  525. if (pdflLoop == NULL)
  526. {
  527. sc = STG_E_FILENOTFOUND;
  528. }
  529. simpDebugOut((DEB_TRACE, "Out CSimpStorageOpen::OpenStream => %p\n",
  530. *ppstm));
  531. return sc;
  532. }
  533. //+--------------------------------------------------------------
  534. //
  535. // Member: CSimpStorageOpen::CreateStream, public
  536. //
  537. // Synopsis: stub
  538. //
  539. // History: 04-May-96 HenryLee Created
  540. //
  541. //---------------------------------------------------------------
  542. STDMETHODIMP CSimpStorageOpen::CreateStream(WCHAR const *pwcsName,
  543. DWORD grfMode,
  544. DWORD reserved1,
  545. DWORD reserved2,
  546. IStream **ppstm)
  547. {
  548. simpDebugOut((DEB_TRACE, "Stb CSimpStorageOpen::CreateStream\n"));
  549. return STG_E_INVALIDFUNCTION;
  550. }
  551. //+--------------------------------------------------------------
  552. //
  553. // Member: CSimpStorageOpen::EnumElements, public
  554. //
  555. // Synopsis: Starts an iterator
  556. //
  557. // Arguments: [reserved1]
  558. // [reserved2]
  559. // [reserved3]
  560. // [ppenm] - Enumerator return
  561. //
  562. // Returns: Appropriate status code
  563. //
  564. // Modifies: [ppenm]
  565. //
  566. // History: 04-May-96 HenryLee Created
  567. //
  568. //---------------------------------------------------------------
  569. STDMETHODIMP CSimpStorageOpen::EnumElements(DWORD reserved1,
  570. void *reserved2,
  571. DWORD reserved3,
  572. IEnumSTATSTG **ppenm)
  573. {
  574. simpDebugOut((DEB_TRACE, "In CSimpStorageOpen::EnumElements\n"));
  575. SCODE sc = S_OK;
  576. SIMP_VALIDATE(EnumElements(reserved1,
  577. reserved2,
  578. reserved3,
  579. ppenm));
  580. if ((*ppenm = new CSimpEnumSTATSTG (_pdfl, _pdfl)) == NULL)
  581. sc = STG_E_INSUFFICIENTMEMORY;
  582. simpDebugOut((DEB_TRACE, "Out CSimpStorageOpen::EnumElements => %x\n", sc));
  583. return sc;
  584. }
  585. //+--------------------------------------------------------------
  586. //
  587. // Member: CSimpStorageOpen::SetClass, public
  588. //
  589. // Synopsis: Sets storage class
  590. //
  591. // Arguments: [clsid] - class id
  592. //
  593. // Returns: Appropriate status code
  594. //
  595. // History: 04-May-96 HenryLee Created
  596. //
  597. //---------------------------------------------------------------
  598. STDMETHODIMP CSimpStorageOpen::SetClass(REFCLSID rclsid)
  599. {
  600. simpDebugOut((DEB_TRACE, "Stb CSimpStorageOpen::SetClass\n"));
  601. return STG_E_INVALIDFUNCTION;
  602. }