//+-------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1992. // // File: tests.cxx // // Contents: DRT tests // // History: 23-Sep-92 DrewB Created // //--------------------------------------------------------------- #include "headers.cxx" #pragma hdrstop #include "tests.hxx" #include "ilb.hxx" void t_create(void) { WStorage *pstgRoot, *pstgChild, *pstgChild2; WStream *pstm; WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstgRoot); pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0, 0, &pstgChild); pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0, 0, &pstgChild2); pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Unwrap(); pstgChild2->Commit(0); pstgChild2->Unwrap(); pstgChild->Commit(0); pstgChild->Unwrap(); VerifyStructure(pstgRoot->GetI(), "dChild(dChild2(sStream))"); pstgRoot->Unwrap(); } void t_open(void) { WStorage *pstgRoot, *pstgChild, *pstgChild2; WStream *pstm; WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstgRoot); CreateStructure(pstgRoot->GetI(), "dChild(dChild2(sStream))"); pstgRoot->Commit(0); pstgRoot->Unwrap(); WStgOpenStorage(DRTDF, NULL, ROOTP(WSTG_READWRITE), NULL, 0, &pstgRoot); pstgRoot->OpenStorage(STR("Child"), NULL, STGP(WSTG_READWRITE), NULL, 0, &pstgChild); pstgChild->OpenStorage(STR("Child2"), NULL, STGP(WSTG_READWRITE), NULL, 0, &pstgChild2); pstgChild2->OpenStream(STR("Stream"), NULL, STMP(WSTG_READWRITE), 0, &pstm); pstm->Unwrap(); pstgChild2->Unwrap(); pstgChild->Unwrap(); pstgRoot->Unwrap(); } void t_addref(void) { WStorage *pstg; WStream *pstm; ULONG ul; WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstg); pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); #ifndef FLAT if ((ul = pstm->AddRef()) != 2) error(EXIT_BADSC, "Wrong reference count - %lu\n", ul); if ((ul = pstm->Release()) != 1) error(EXIT_BADSC, "Wrong reference count - %lu\n", ul); pstm->Unwrap(); if ((ul = pstg->AddRef()) != 2) error(EXIT_BADSC, "Wrong reference count - %lu\n", ul); if ((ul = pstg->Release()) != 1) error(EXIT_BADSC, "Wrong reference count - %lu\n", ul); #else if ((ul = pstm->AddRef()) <= 0) error(EXIT_BADSC, "Wrong reference count - %lu\n", ul); if ((ul = pstm->Release()) <= 0) error(EXIT_BADSC, "Wrong reference count - %lu\n", ul); pstm->Unwrap(); if ((ul = pstg->AddRef()) <= 0) error(EXIT_BADSC, "Wrong reference count - %lu\n", ul); if ((ul = pstg->Release()) <= 0) error(EXIT_BADSC, "Wrong reference count - %lu\n", ul); #endif pstg->Unwrap(); } void t_tmodify(void) { WStorage *pstgRoot, *pstgChild, *pstgChild2; WStream *pstm; // This test must use transacted mode to reproduce the // expected behavior ForceTransacted(); WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstgRoot); pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0, 0, &pstgChild); pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0, 0, &pstgChild2); pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Unwrap(); pstgChild2->Commit(0); VerifyStructure(pstgChild2->GetI(), "sStream"); // Test renaming a closed stream pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream")); VerifyStructure(pstgChild2->GetI(), "sRenamedStream"); // Test rename reversion pstgChild2->Revert(); VerifyStructure(pstgChild2->GetI(), "sStream"); // Test destruction of closed object pstgChild2->DestroyElement(STR("Stream")); pstgChild2->Commit(0); // Test create of previously deleted object pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstgChild2->Commit(0); VerifyStructure(pstgChild2->GetI(), "sStream"); #if 0 // 08/11/93 - Renaming open children no longer allowed // Test renaming an open stream pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream")); VerifyStructure(pstgChild2->GetI(), "sRenamedStream"); #endif pstgChild2->Revert(); VerifyStructure(pstgChild2->GetI(), "sStream"); pstgChild2->DestroyElement(STR("Stream")); pstgChild2->Commit(0); pstm->Unwrap(); pstgChild2->Unwrap(); VerifyStructure(pstgChild->GetI(), "dChild2()"); // Test rename of storage pstgChild->RenameElement(STR("Child2"), STR("RenamedChild")); pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Unwrap(); pstgChild->DestroyElement(STR("Stream")); pstgChild->Commit(0); // Test SetElementTimes FILETIME tm; STATSTG stat; tm.dwLowDateTime = 0x12345678; tm.dwHighDateTime = 0x01bcdef0; // Set when element not open pstgChild->SetElementTimes(STR("RenamedChild"), &tm, NULL, NULL); pstgChild->SetElementTimes(STR("RenamedChild"), NULL, &tm, NULL); pstgChild->SetElementTimes(STR("RenamedChild"), NULL, NULL, &tm); pstgChild->OpenStorage(STR("RenamedChild"), NULL, STGP(WSTG_READWRITE), NULL, 0, &pstgChild2); pstgChild2->Stat(&stat, STATFLAG_NONAME); if (!IsEqualTime(stat.ctime, tm) || !IsEqualTime(stat.mtime, tm)) error(EXIT_BADSC, "Times don't match those set by SetElementTimes\n"); // Test SetClass and SetStateBits pstgChild2->SetClass(IID_IStorage); fExitOnFail = FALSE; pstgChild2->SetStateBits(0xff00ff00, 0xffffffff); pstgChild2->SetStateBits(0x00880088, 0xeeeeeeee); fExitOnFail = TRUE; pstgChild2->Stat(&stat, STATFLAG_NONAME); if (!IsEqualCLSID(stat.clsid, IID_IStorage)) error(EXIT_BADSC, "Class ID set to %s\n", GuidText(&stat.clsid)); if (stat.grfStateBits != 0x11881188) errorprint("State bits set improperly: has %lX vs. %lX\n", stat.grfStateBits, 0x11881188); pstgChild2->Revert(); pstgChild2->Stat(&stat, STATFLAG_NONAME); if (!IsEqualCLSID(stat.clsid, CLSID_NULL)) error(EXIT_BADSC, "Class ID reverted to %s\n", GuidText(&stat.clsid)); if (stat.grfStateBits != 0) errorprint("State bits reverted improperly: has %lX vs. %lX\n", stat.grfStateBits, 0); pstgChild2->Unwrap(); pstgChild->Unwrap(); VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())"); pstgRoot->Revert(); VerifyStructure(pstgRoot->GetI(), ""); pstgRoot->Commit(0); VerifyStructure(pstgRoot->GetI(), ""); pstgRoot->Unwrap(); Unforce(); } void t_dmodify(void) { WStorage *pstgRoot, *pstgChild, *pstgChild2; WStream *pstm; ULONG cbSize1, cbSize2; // This test must use direct mode to reproduce the // expected behavior ForceDirect(); WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstgRoot); pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0, 0, &pstgChild); pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0, 0, &pstgChild2); pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Unwrap(); VerifyStructure(pstgChild2->GetI(), "sStream"); // Test renaming a closed stream pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream")); VerifyStructure(pstgChild2->GetI(), "sRenamedStream"); // Test destroying a stream pstgChild2->DestroyElement(STR("RenamedStream")); #if 0 // 08/11/93 - Renaming open child no longer allowed // Test renaming an open stream pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); VerifyStructure(pstgChild2->GetI(), "sStream"); pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream")); VerifyStructure(pstgChild2->GetI(), "sRenamedStream"); pstgChild2->DestroyElement(STR("RenamedStream")); pstm->Unwrap(); #endif pstgChild2->Unwrap(); VerifyStructure(pstgChild->GetI(), "dChild2()"); // Test renaming a storage pstgChild->RenameElement(STR("Child2"), STR("RenamedChild")); pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Unwrap(); pstgChild->DestroyElement(STR("Stream")); // Test SetElementTimes FILETIME tm; STATSTG stat; tm.dwLowDateTime = 0x12345678; tm.dwHighDateTime = 0x01bcdef0; // Set when element not open pstgChild->SetElementTimes(STR("RenamedChild"), &tm, NULL, NULL); pstgChild->SetElementTimes(STR("RenamedChild"), NULL, &tm, NULL); pstgChild->SetElementTimes(STR("RenamedChild"), NULL, NULL, &tm); pstgChild->OpenStorage(STR("RenamedChild"), NULL, STMP(WSTG_READWRITE), NULL, 0, &pstgChild2); pstgChild2->Stat(&stat, STATFLAG_NONAME); if (!IsEqualTime(stat.ctime, tm) || !IsEqualTime(stat.mtime, tm)) error(EXIT_BADSC, "Times don't match those set by SetElementTimes\n"); // Test SetClass and SetStateBits pstgChild2->SetClass(IID_IStorage); fExitOnFail = FALSE; pstgChild2->SetStateBits(0xff00ff00, 0xffffffff); pstgChild2->SetStateBits(0x00880088, 0xeeeeeeee); fExitOnFail = TRUE; pstgChild2->Stat(&stat, STATFLAG_NONAME); if (!IsEqualCLSID(stat.clsid, IID_IStorage)) error(EXIT_BADSC, "Class ID set improperly\n"); if (stat.grfStateBits != 0x11881188) errorprint("State bits set improperly: has %lX vs. %lX\n", stat.grfStateBits, 0x11881188); pstgChild2->Unwrap(); pstgChild->Unwrap(); VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())"); pstgRoot->Revert(); VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())"); pstgRoot->Commit(0); VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())"); pstgRoot->DestroyElement(STR("Child")); VerifyStructure(pstgRoot->GetI(), ""); // Verify that space is reclaimed after modifications pstgRoot->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->SetSize(65536); pstm->Unwrap(); cbSize1 = Length(DRTDF); pstgRoot->DestroyElement(STR("Stream")); pstgRoot->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->SetSize(65536); pstm->Unwrap(); cbSize2 = Length(DRTDF); if (cbSize1 != cbSize2) error(EXIT_BADSC, "Space is not being reclaimed, original %lu, " "now %lu\n", cbSize1, cbSize2); pstgRoot->Unwrap(); WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE | WSTG_DELETEONRELEASE, 0, &pstgRoot); // removal cases // 1) no right child CreateStructure(pstgRoot->GetI(), "d64,d32"); VerifyStructure(pstgRoot->GetI(), "d64,d32"); pstgRoot->DestroyElement(STR("64")); VerifyStructure(pstgRoot->GetI(), "d32"); // 2) right child has no left child CreateStructure(pstgRoot->GetI(), "d64"); VerifyStructure(pstgRoot->GetI(), "d32,d64"); pstgRoot->DestroyElement(STR("32")); VerifyStructure(pstgRoot->GetI(), "d64"); // 3) right child has left child CreateStructure(pstgRoot->GetI(), "d96,d80"); VerifyStructure(pstgRoot->GetI(), "d64,d80,d96"); pstgRoot->DestroyElement(STR("64")); VerifyStructure(pstgRoot->GetI(), "d80,d96"); // 4) right child's left child has children CreateStructure(pstgRoot->GetI(), "d88,d84,d92"); VerifyStructure(pstgRoot->GetI(), "d80,d84,d88,d92,d96"); pstgRoot->DestroyElement(STR("80")); VerifyStructure(pstgRoot->GetI(), "d84,d88,d92,d96"); pstgRoot->Unwrap(); Unforce(); } void t_stat(void) { WStorage *pstgRoot, *pstgChild; WStream *pstm; STATSTG stat; WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstgRoot); pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0, 0, &pstgChild); pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Stat(&stat, 0); VerifyStat(&stat, STR("Stream"), STGTY_STREAM, STMP(WSTG_READWRITE)); drtMemFree(stat.pwcsName); pstm->Stat(&stat, STATFLAG_NONAME); VerifyStat(&stat, NULL, STGTY_STREAM, STMP(WSTG_READWRITE)); pstm->Unwrap(); pstgChild->Stat(&stat, 0); VerifyStat(&stat, STR("Child"), STGTY_STORAGE, STGP(WSTG_READWRITE)); drtMemFree(stat.pwcsName); pstgChild->Stat(&stat, STATFLAG_NONAME); VerifyStat(&stat, NULL, STGTY_STORAGE, STGP(WSTG_READWRITE)); pstgChild->Unwrap(); pstgRoot->Stat(&stat, 0); OLECHAR atcFullPath[_MAX_PATH]; GetFullPath(DRTDF, atcFullPath); VerifyStat(&stat, atcFullPath, STGTY_STORAGE, ROOTP(WSTG_READWRITE)); drtMemFree(stat.pwcsName); pstgRoot->Stat(&stat, STATFLAG_NONAME); VerifyStat(&stat, NULL, STGTY_STORAGE, ROOTP(WSTG_READWRITE)); pstgRoot->Unwrap(); } static char NUMBERS[] = "12345678901234567890123456789012345678901234567890"; void t_stream(void) { WStorage *pstg; WStream *pstm, *pstmC; char buf[sizeof(NUMBERS)*2]; ULONG cb, ulPos; WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstg); pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Write(NUMBERS, sizeof(NUMBERS), &cb); pstm->Commit(0); pstm->Seek(0, WSTM_SEEK_SET, &ulPos); if (ulPos != 0) error(EXIT_BADSC, "Incorrect seek, ptr is %lu\n", ulPos); pstm->Read(buf, sizeof(NUMBERS), &cb); if (strcmp(buf, NUMBERS)) error(EXIT_BADSC, "Incorrect stream contents\n"); pstm->SetSize(sizeof(NUMBERS)/2); pstm->Seek(0, WSTM_SEEK_SET, NULL); fExitOnFail = FALSE; pstm->Read(buf, sizeof(NUMBERS), &cb); fExitOnFail = TRUE; if (cb != sizeof(NUMBERS)/2) error(EXIT_BADSC, "SetSize failed to size stream properly\n"); if (memcmp(buf, NUMBERS, sizeof(NUMBERS)/2)) error(EXIT_BADSC, "SetSize corrupted contents\n"); pstm->Clone(&pstmC); pstm->Seek(0, WSTM_SEEK_SET, NULL); pstm->CopyTo(pstmC, sizeof(NUMBERS)/2, NULL, NULL); pstm->Seek(0, WSTM_SEEK_SET, NULL); pstm->CopyTo(pstmC, sizeof(NUMBERS)&~1, NULL, NULL); pstm->Seek(0, WSTM_SEEK_SET, NULL); pstm->Read(buf, (sizeof(NUMBERS)&~1)*2, &cb); if (memcmp(buf, NUMBERS, sizeof(NUMBERS)/2) || memcmp(buf+sizeof(NUMBERS)/2, NUMBERS, sizeof(NUMBERS)/2) || memcmp(buf+(sizeof(NUMBERS)&~1), NUMBERS, sizeof(NUMBERS)/2) || memcmp(buf+3*(sizeof(NUMBERS)/2), NUMBERS, sizeof(NUMBERS)/2)) error(EXIT_BADSC, "Stream contents incorrect\n"); pstmC->Unwrap(); pstm->Unwrap(); pstg->Unwrap(); } // Number of entries for enumeration test #define ENUMENTRIES 10 // Flag indicating a name has already shown up in enumeration, // must not conflict with STGTY_* #define ENTRY_SEEN 0x100 // Check the validity of an enumeration element static void elt_check(STATSTG *pstat, CStrList *psl) { SStrEntry *pse; pse = psl->Find(pstat->pwcsName); if (pse == NULL) error(EXIT_BADSC, "Spurious element '%s'\n", pstat->pwcsName); else if ((pse->user.dw & ~ENTRY_SEEN) != pstat->type) error(EXIT_BADSC, "Element '%s' has wrong type - " "has %lX vs. %lX\n", pstat->pwcsName, pstat->type, pse->user.dw & ~ENTRY_SEEN); else if (pse->user.dw & ENTRY_SEEN) error(EXIT_BADSC, "Element '%s' has already been seen\n", pstat->pwcsName); pse->user.dw |= ENTRY_SEEN; } // Do final validity checks for enumeration static void enum_list_check(CStrList *psl) { SStrEntry *pse; for (pse = psl->GetHead(); pse; pse = pse->pseNext) { if ((pse->user.dw & ENTRY_SEEN) == 0) error(EXIT_BADSC, "Element '%s' not found\n", pse->atc); pse->user.dw &= ~ENTRY_SEEN; } } void t_enum(void) { int i; OLECHAR atcName[CWCSTORAGENAME]; WStorage *pstg, *pstg2; WStream *pstm; SStrEntry *pse; CStrList sl; // Create some entries to enumerate WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstg); for (i = 0; iuser.dw = STGTY_STORAGE; pstg->CreateStorage(atcName, STGP(WSTG_READWRITE), 0, 0, &pstg2); pstg2->Unwrap(); } else { pse->user.dw = STGTY_STREAM; pstg->CreateStream(atcName, STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Unwrap(); } } WEnumSTATSTG *penm; STATSTG stat[2*ENUMENTRIES]; SCODE sc; // Test plain, single element enumeration pstg->EnumElements(0, NULL, 0, &penm); for (;;) { sc = DfGetScode(penm->Next(1, stat, NULL)); if (sc == S_FALSE) break; elt_check(stat, &sl); drtMemFree(stat->pwcsName); } enum_list_check(&sl); ULONG cFound; // Test rewind and multiple element enumeration with too many elements penm->Reset(); sc = DfGetScode(penm->Next(ENUMENTRIES*2, stat, &cFound)); if (sc != S_FALSE) error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of " "S_FALSE\n", ScText(sc), sc); if (cFound != ENUMENTRIES) error(EXIT_BADSC, "Enumerator found %lu entries instead of " "%d entries\n", cFound, ENUMENTRIES); for (; cFound > 0; cFound--) { elt_check(&stat[cFound-1], &sl); drtMemFree(stat[cFound-1].pwcsName); } enum_list_check(&sl); // Test skip and multiple enumeration with exact number of elements penm->Reset(); penm->Skip(ENUMENTRIES/2); sc = DfGetScode(penm->Next(ENUMENTRIES-ENUMENTRIES/2, stat, &cFound)); if (sc != S_OK) error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of " "S_OK\n", ScText(sc), sc); if (cFound != ENUMENTRIES-ENUMENTRIES/2) error(EXIT_BADSC, "Enumerator found %lu entries instead of " "%d entries\n", cFound, ENUMENTRIES-ENUMENTRIES/2); for (; cFound > 0; cFound--) { elt_check(&stat[cFound-1], &sl); drtMemFree(stat[cFound-1].pwcsName); } sc = DfGetScode(penm->Next(1, stat, NULL)); if (sc != S_FALSE) error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of " "S_FALSE\n", ScText(sc), sc); penm->Unwrap(); pstg->Unwrap(); } #define SCT_CLASSID IID_ILockBytes #define SCT_STATEBITS 0xfef1f0f0 void t_stgcopyto(void) { WStorage *pstgFrom, *pstgTo; STATSTG statFrom, statTo; WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE | WSTG_DELETEONRELEASE, 0, &pstgFrom); pstgFrom->Stat(&statFrom, 0); // Set some interesting values to make sure they're copied pstgFrom->SetClass(SCT_CLASSID); fExitOnFail = FALSE; pstgFrom->SetStateBits(SCT_STATEBITS, 0xffffffff); fExitOnFail = TRUE; WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE | WSTG_DELETEONRELEASE, 0, &pstgTo); CreateStructure(pstgFrom->GetI(), "dA(dB(dC(sA,sB,sC),sCs),sBs),sAs"); CreateStructure(pstgTo->GetI(), "dA(dY(sZ),sBs)"); pstgFrom->CopyTo(0, NULL, NULL, pstgTo); VerifyStructure(pstgTo->GetI(), "dA(dB(dC(sA,sB,sC),sCs),dY(sZ),sBs),sAs"); pstgTo->Stat(&statTo, 0); if (!IsEqualCLSID(statTo.clsid, SCT_CLASSID)) error(EXIT_BADSC, "Class ID mismatch after copy\n"); if (statTo.grfStateBits != SCT_STATEBITS) errorprint("State bits mismatch: has %lX vs. %lX\n", statTo.grfStateBits, SCT_STATEBITS); pstgFrom->Unwrap(); pstgTo->Unwrap(); if (Exists(statFrom.pwcsName)) error(EXIT_BADSC, "Storage '%s' not deleted\n", statFrom.pwcsName); drtMemFree(statFrom.pwcsName); if (Exists(statTo.pwcsName)) error(EXIT_BADSC, "Storage '%s' not deleted\n", statTo.pwcsName); drtMemFree(statTo.pwcsName); } #define MARSHAL_STM STR("Marshal") void do_marshal(WStorage *pstg, WStream *pstm) { WStorage *pstgMarshal; WStream *pstmMarshal; WStgCreateDocfile(MARSHALDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstgMarshal); pstgMarshal->CreateStream(MARSHAL_STM, STMP(WSTG_READWRITE), 0, 0, &pstmMarshal); WCoMarshalInterface(pstmMarshal, IID_IStorage, pstg->GetI(), 0, NULL, MSHLFLAGS_NORMAL); WCoMarshalInterface(pstmMarshal, IID_IStream, pstm->GetI(), 0, NULL, MSHLFLAGS_NORMAL); WCoMarshalInterface(pstmMarshal, IID_IUnknown, pstg->GetI(), 0, NULL, MSHLFLAGS_NORMAL); WCoMarshalInterface(pstmMarshal, IID_IUnknown, pstm->GetI(), 0, NULL, MSHLFLAGS_NORMAL); pstmMarshal->Unwrap(); pstgMarshal->Commit(0); pstgMarshal->Unwrap(); } static char STREAM_DATA[] = "This is data to be written"; void do_unmarshal(WStorage **ppstg, WStream **ppstm, IUnknown **ppstg2, IUnknown **ppstm2) { IStorage *pistg; WStorage *pstgMarshal; WStream *pstmMarshal; IStream *pistm; WStgOpenStorage(MARSHALDF, NULL, ROOTP(WSTG_READWRITE), NULL, 0, &pstgMarshal); pstgMarshal->OpenStream(MARSHAL_STM, NULL, STMP(WSTG_READWRITE), 0, &pstmMarshal); WCoUnmarshalInterface(pstmMarshal, IID_IStorage, (void **)&pistg); *ppstg = WStorage::Wrap(pistg); WCoUnmarshalInterface(pstmMarshal, IID_IStream, (void **)&pistm); *ppstm = WStream::Wrap(pistm); WCoUnmarshalInterface(pstmMarshal, IID_IUnknown, (void **)ppstg2); WCoUnmarshalInterface(pstmMarshal, IID_IUnknown, (void **)ppstm2); pstmMarshal->Unwrap(); pstgMarshal->Unwrap(); } void t_marshal(void) { WStorage *pstg, *pstgM; WStream *pstm, *pstmM; IUnknown *pstgM2, *pstmM2; ULONG cbRead, cbWritten; char buf[sizeof(STREAM_DATA)]; WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE | WSTG_DELETEONRELEASE, 0, &pstg); pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm); pstm->Write(STREAM_DATA, sizeof(STREAM_DATA), &cbWritten); CreateStructure(pstg->GetI(), "dChild(dChild(sStream))"); do_marshal(pstg, pstm); do_unmarshal(&pstgM, &pstmM, &pstgM2, &pstmM2); pstm->Unwrap(); pstg->Unwrap(); pstmM->Seek(0, WSTM_SEEK_SET, NULL); pstmM->Read(buf, sizeof(STREAM_DATA), &cbRead); if (strcmp(buf, STREAM_DATA)) error(EXIT_BADSC, "Stream data mismatch\n"); pstmM->Unwrap(); pstmM2->Release(); VerifyStructure(pstgM->GetI(), "dChild(dChild(sStream)),sStream"); pstgM->Unwrap(); pstgM2->Release(); } void t_stgmisc(void) { WStorage *pstg; SCODE sc; STATSTG stat; // Can't make this call in transacted mode because we want // the storage signature to make it into the file right away WStgCreateDocfile(DRTDF, WSTG_READWRITE | WSTG_CREATE | WSTG_SHARE_EXCLUSIVE, 0, &pstg); if (!fOfs) { sc = DfGetScode(WStgIsStorageFile(DRTDF)); if (sc == S_FALSE) error(EXIT_BADSC, "Open file - Should be a storage object\n"); pstg->Unwrap(); sc = DfGetScode(WStgIsStorageFile(DRTDF)); if (sc == S_FALSE) error(EXIT_BADSC, "Closed file - Should be a storage object\n"); } WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE | WSTG_DELETEONRELEASE, 0, &pstg); pstg->Stat(&stat, 0); if (!Exists(stat.pwcsName)) error(EXIT_BADSC, "Storage '%s' not created\n", stat.pwcsName); pstg->Unwrap(); if (Exists(stat.pwcsName)) error(EXIT_BADSC, "Storage '%s' not deleted on release\n", stat.pwcsName); drtMemFree(stat.pwcsName); } void t_ilb(void) { WStorage *pstg; SCODE sc; // create an ILockBytes ILockBytes *pilb = new CMapBytes(); if (pilb == NULL) error(EXIT_BADSC, "Unable to allocate an ILockBytes\n"); // create a storage on the ILockBytes WStgCreateDocfileOnILockBytes(pilb, WSTG_READWRITE | WSTG_CREATE | WSTG_SHARE_EXCLUSIVE, 0, &pstg); // verify the ILockBytes sc = DfGetScode(WStgIsStorageILockBytes(pilb)); if (sc == S_FALSE) error(EXIT_BADSC, "Open ILockBytes - Should be a storage object\n"); // release the storage pstg->Unwrap(); // verify the ILockBytes sc = DfGetScode(WStgIsStorageILockBytes(pilb)); if (sc == S_FALSE) error(EXIT_BADSC, "Released ILockBytes - Should be a storage object\n"); // open the ILockBytes WStgOpenStorageOnILockBytes(pilb, NULL, ROOTP(WSTG_READWRITE), NULL, 0, &pstg); // release the storage pstg->Unwrap(); // release the ILockBytes pilb->Release(); } void t_movecopy(void) { WStorage *pstgFrom, *pstgTo; STATSTG statFrom, statTo; // create a source WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE | WSTG_DELETEONRELEASE, 0, &pstgFrom); pstgFrom->Stat(&statFrom, 0); // create a destination WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE | WSTG_DELETEONRELEASE, 0, &pstgTo); pstgTo->Stat(&statTo, 0); // populate source CreateStructure(pstgFrom->GetI(), "dA(dB(dC(sA,sB,sC),sCs),sBs),sAs"); // move a storage pstgFrom->MoveElementTo(STR("A"), pstgTo, STR("M"), STGMOVE_MOVE); VerifyStructure(pstgFrom->GetI(), "sAs"); VerifyStructure(pstgTo->GetI(), "dM(dB(dC(sA,sB,sC),sCs),sBs)"); // copy a stream pstgFrom->MoveElementTo(STR("As"), pstgTo, STR("Bs"), STGMOVE_COPY); VerifyStructure(pstgFrom->GetI(), "sAs"); VerifyStructure(pstgTo->GetI(), "dM(dB(dC(sA,sB,sC),sCs),sBs),sBs"); pstgFrom->Unwrap(); pstgTo->Unwrap(); if (Exists(statFrom.pwcsName)) error(EXIT_BADSC, "Storage '%s' not deleted\n", statFrom.pwcsName); drtMemFree(statFrom.pwcsName); if (Exists(statTo.pwcsName)) error(EXIT_BADSC, "Storage '%s' not deleted\n", statTo.pwcsName); drtMemFree(statTo.pwcsName); }