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.

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