void ReadStorage(LPSTORAGE pStg) // reads one storage -- recursive calls for substorages { USES_CONVERSION; LPSTORAGE pSubStg = NULL; LPSTREAM pStream = NULL; LPENUMSTATSTG pEnum = NULL; LPMALLOC pMalloc = NULL; // for freeing statstg STATSTG statstg; ULONG nLength; BYTE buffer[101]; g_nIndent++; ::CoGetMalloc(MEMCTX_TASK, &pMalloc); // assumes AfxOleInit // was called VERIFY(pStg->EnumElements(0, NULL, 0, &pEnum) == S_OK); while (pEnum->Next(1, &statstg, NULL) == S_OK) { if (statstg.type == STGTY_STORAGE) { VERIFY(pStg->OpenStorage(statstg.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, 0, &pSubStg) == S_OK); ASSERT(pSubStg != NULL); TRACE("%0.*sStorage = %s\n", (g_nIndent - 1) * 4, g_szBlanks, OLE2CT(statstg.pwcsName)); ReadStorage(pSubStg); pSubStg->Release(); } else if (statstg.type == STGTY_STREAM) { VERIFY(pStg->OpenStream(statstg.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream) == S_OK); ASSERT(pStream != NULL); TRACE("%0.*sStream = %s\n", (g_nIndent - 1) * 4, g_szBlanks, OLE2CT(statstg.pwcsName)); pStream->Read(buffer, 100, &nLength); buffer[nLength] = '\0'; TRACE("%s\n", buffer); pStream->Release(); } else { ASSERT(FALSE); // LockBytes? } pMalloc->Free(statstg.pwcsName); // avoids memory leaks } pMalloc->Release(); pEnum->Release(); g_nIndent--; }
STDAPI UtDoStreamOperation(LPSTORAGE pstgSrc, LPSTORAGE pstgDst, int iOpCode, DWORD grfAllowedStmTypes) { VDATEHEAP(); HRESULT error; // error status so far IEnumSTATSTG FAR* penumStg; // used to enumerate the storage elements ULONG celtFetched; // how many storage elements were fetched STATSTG statstg; // get an enumerator over the source storage if (error = pstgSrc->EnumElements(NULL, NULL, NULL, &penumStg)) return error; // repeat for every storage while(penumStg->Next(1, &statstg, &celtFetched) == NOERROR) { // operate on streams that we're interested in if (statstg.type == STGTY_STREAM) { DWORD stmType; // find the type of the stream // REVIEW, we must have constants for these name // prefixes!!! switch (statstg.pwcsName[0]) { case '\1': stmType = STREAMTYPE_CONTROL; break; case '\2': stmType = STREAMTYPE_CACHE; break; case '\3': stmType = STREAMTYPE_CONTAINER; break; default: stmType = (DWORD)STREAMTYPE_OTHER; } // check whether it should be operated upon if (stmType & grfAllowedStmTypes) { switch(iOpCode) { #ifdef LATER case OPCODE_COPY: pstgDst->DestroyElement( statstg.pwcsName); error = pstgSrc->MoveElementTo( statstg.pwcsName, pstgDst, statstg.pwcsName, STGMOVE_COPY); break; case OPCODE_MOVE: pstgDst->DestroyElement( statstg.pwcsName); error = pstgSrc->MoveElementTo( statstg.pwcsName, pstgDst, statstg.pwcsName, STGMOVE_MOVE); break; case OPCODE_EXCLUDEFROMCOPY: AssertSz(FALSE, "Not yet implemented"); break; #endif // LATER case OPCODE_REMOVE: error = pstgSrc->DestroyElement( statstg.pwcsName); break; default: AssertSz(FALSE, "Invalid opcode"); break; } } } // if the enumerator allocated a new name string, get rid of it if (statstg.pwcsName) PubMemFree(statstg.pwcsName); // quit the enumeration loop if we've hit an error if (error != NOERROR) break; } // release the enumerator penumStg->Release(); // return the error state return error; }