813 lines
26 KiB
C++
813 lines
26 KiB
C++
|
//+--------------------------------------------------------------
|
||
|
//
|
||
|
// 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; i<ENUMENTRIES; i++)
|
||
|
{
|
||
|
olecsprintf(atcName, STR("Name%d"), rand());
|
||
|
pse = sl.Add(atcName);
|
||
|
if (rand()%100 < 50)
|
||
|
{
|
||
|
pse->user.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);
|
||
|
}
|