NT4/private/ole32/stg/docfile/tests/prop.cxx
2020-09-30 17:12:29 +02:00

956 lines
28 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: prop.cxx
//
// Contents: Non-OFS property test
//
// History: 03-Sep-93 DrewB Created
//
//----------------------------------------------------------------------------
#include "pch.cxx"
#pragma hdrstop
struct PropDesc
{
DFPROPTYPE dpt;
char *pszName;
BOOL fArray;
size_t size;
};
PropDesc props[] =
{
VT_EMPTY, "Empty", FALSE, 0,
VT_I2, "I2", TRUE, sizeof(short int),
VT_I4, "I4", TRUE, sizeof(long int),
VT_R4, "R4", TRUE, sizeof(float),
VT_R8, "R8", TRUE, sizeof(double),
VT_CY, "Currency", TRUE, sizeof(CY),
VT_DATE, "Date", TRUE, sizeof(DATE),
VT_BSTR, "Basic string", TRUE, sizeof(BSTR),
VT_WBSTR, "Wide basic string", TRUE, sizeof(WBSTR),
VT_BOOL, "BOOL", TRUE, sizeof(VARIANT_BOOL),
VT_I8, "I8", TRUE, sizeof(LARGE_INTEGER),
VT_LPSTR, "char string", TRUE, sizeof(LPSTR),
VT_BLOB, "BLOB", FALSE, sizeof(BLOB),
VT_BLOB_OBJECT, "BLOB object", FALSE, sizeof(BLOB),
VT_LPWSTR, "WCHAR string", TRUE, sizeof(LPWSTR),
VT_FILETIME, "File time", TRUE, sizeof(FILETIME),
VT_UUID, "UUID", TRUE, sizeof(GUID),
VT_VARIANT, "Variant", TRUE, sizeof(VARIANT),
VT_STREAM, "Stream", FALSE, sizeof(IStream *),
VT_STREAMED_OBJECT, "Streamed object", FALSE, sizeof(IStream *),
VT_STORAGE, "Storage", FALSE, sizeof(IStorage *),
VT_STORED_OBJECT, "Stored object", FALSE, sizeof(IStorage *),
VT_CF, "Clipboard data", FALSE, sizeof(CLIPDATA)
};
#define CPROPS (sizeof(props)/sizeof(props[0]))
#define CTOTPROPS (2*CPROPS)
#define ARRAY_SIZE 16
#define BSTR_PTR(pb) ((BYTE *)(pb)-sizeof(UINT))
#define BSTR_LEN(pb) (*(UINT *)BSTR_PTR(pb)+sizeof(UINT)+1)
#define WBSTR_PTR(pb) ((BYTE *)(pb)-sizeof(UINT))
#define WBSTR_LEN(pb) (*(UINT *)WBSTR_PTR(pb)+sizeof(UINT)+sizeof(WCHAR))
struct _BSTR
{
UINT len;
char str[80];
};
struct _WBSTR
{
UINT len;
WCHAR str[80];
};
#define I2_VAL ((short)0x8564)
#define I4_VAL ((long)0xfef1f064)
#define R4_VAL ((float)1.25)
#define R8_VAL ((double)3.1415926535)
#define DATE_VAL ((DATE)4.0)
#define F_VAL ((VARIANT_BOOL)TRUE)
#define BSTR_STR "This is a BSTR"
_BSTR BSTR_STRUCT = {sizeof(BSTR_STR)-1, BSTR_STR};
#define BSTR_VAL ((BSTR)(&BSTR_STRUCT.str))
#define WBSTR_STR L"This is a WBSTR"
_WBSTR WBSTR_STRUCT = {sizeof(WBSTR_STR)-sizeof(WCHAR), WBSTR_STR};
#define WBSTR_VAL ((WBSTR)(&WBSTR_STRUCT.str))
#define LPSTR_VAL "This is an LPSTR"
#define BLOB_VAL "This is binary data for a BLOB"
#define LPWSTR_VAL L"This is an LPWSTR"
#define STREAM_VAL "This is data for an IStream"
LARGE_INTEGER I8_VAL = {0x12345678, 0x87654321};
#define CF_FMT ((ULONG)12345678)
#define CF_VAL "This is binary data for VT_CF"
#define VARIANT_VAL VT_R8
CY CY_VAL = {0x43215678, 0x56784321};
FILETIME FILETIME_VAL = {0x11223344, 0x55667788};
#define UUID_VAL IID_IStorage
WCHAR wcsNames[CTOTPROPS][CWCSTORAGENAME];
WCHAR *pwcsNames[CTOTPROPS];
IStorage *pstgProp;
IStream *pstmProp;
int prop_index(DFPROPTYPE dpt)
{
int i;
for (i = 0; i<CPROPS; i++)
if (dpt == props[i].dpt)
return i;
printf("** Unknown prop type 0x%X **\n", dpt);
return 0;
}
void MakeVal(DFPROPTYPE dpt, VARIANT *pval);
void MakeSingleVal(DFPROPTYPE dpt, void *pval)
{
switch(dpt)
{
case VT_EMPTY:
break;
case VT_I2:
case VT_I2 | VT_VECTOR:
*(short int *)pval = (short int)I2_VAL;
break;
case VT_I4:
case VT_I4 | VT_VECTOR:
*(long int *)pval = I4_VAL;
break;
case VT_R4:
case VT_R4 | VT_VECTOR:
*(float *)pval = R4_VAL;
break;
case VT_R8:
case VT_R8 | VT_VECTOR:
*(double *)pval = R8_VAL;
break;
case VT_CY:
case VT_CY | VT_VECTOR:
CY *pcy;
pcy = (CY *)pval;
*pcy = CY_VAL;
break;
case VT_DATE:
case VT_DATE | VT_VECTOR:
*(DATE *)pval = DATE_VAL;
break;
case VT_BSTR:
case VT_BSTR | VT_VECTOR:
*(BSTR *)pval = BSTR_VAL;
break;
case VT_WBSTR:
case VT_WBSTR | VT_VECTOR:
*(WBSTR *)pval = WBSTR_VAL;
break;
case VT_BOOL:
case VT_BOOL | VT_VECTOR:
*(VARIANT_BOOL *)pval = F_VAL;
break;
case VT_I8:
case VT_I8 | VT_VECTOR:
*(LARGE_INTEGER *)pval = I8_VAL;
break;
case VT_LPSTR:
case VT_LPSTR | VT_VECTOR:
*(LPSTR *)pval = LPSTR_VAL;
break;
case VT_BLOB:
case VT_BLOB_OBJECT:
BLOB *pblob;
pblob = (BLOB *)pval;
#ifndef ZERO_LENGTH_BLOB
pblob->cbSize = sizeof(BLOB_VAL);
#else
pblob->cbSize = 0;
#endif
pblob->pBlobData = (BYTE *)BLOB_VAL;
break;
case VT_LPWSTR:
case VT_LPWSTR | VT_VECTOR:
*(LPWSTR *)pval = LPWSTR_VAL;
break;
case VT_FILETIME:
case VT_FILETIME | VT_VECTOR:
FILETIME *pstm;
pstm = (FILETIME *)pval;
*pstm = FILETIME_VAL;
break;
case VT_UUID:
*(GUID **)pval = (GUID *)&UUID_VAL;
break;
case VT_UUID | VT_VECTOR:
memcpy(pval, &UUID_VAL, sizeof(GUID));
break;
case VT_VARIANT:
VARIANT *pvar;
pvar = new VARIANT;
MakeVal(VARIANT_VAL, pvar);
*(VARIANT **)pval = pvar;
break;
case VT_VARIANT | VT_VECTOR:
MakeVal(VARIANT_VAL | VT_VECTOR, (VARIANT *)pval);
break;
case VT_STREAM:
case VT_STREAMED_OBJECT:
*(IStream **)pval = pstmProp;
break;
case VT_STORAGE:
case VT_STORED_OBJECT:
*(IStorage **)pval = pstgProp;
break;
case VT_CF:
CLIPDATA *pcd;
pcd = new CLIPDATA;
pcd->cbSize = sizeof(CF_VAL)+sizeof(ULONG);
pcd->ulClipFmt = CF_FMT;
pcd->pClipData = (BYTE *)CF_VAL;
*(CLIPDATA **)pval = pcd;
break;
default:
printf("** Unknown property type in MakeVal: %X\n", dpt);
break;
}
}
void MakeVal(DFPROPTYPE dpt, VARIANT *pval)
{
int i;
pval->vt = dpt;
if (dpt & VT_VECTOR)
{
BYTE *pb;
int indx;
indx = prop_index(dpt & VT_TYPEMASK);
pval->cai.cElems = ARRAY_SIZE;
pb = new BYTE[props[indx].size*ARRAY_SIZE];
pval->cai.pElems = (short int *)pb;
for (i = 0; i < ARRAY_SIZE; i++)
{
MakeSingleVal(dpt, pb);
pb += props[indx].size;
}
}
else
MakeSingleVal(dpt, &pval->iVal);
}
void UnmakeVal(VARIANT *pval)
{
if (pval->vt & VT_VECTOR)
{
if ((pval->vt & VT_TYPEMASK) == VT_VARIANT)
{
ULONG i;
for (i = 0; i < ARRAY_SIZE; i++)
UnmakeVal(pval->cavar.pElems+i);
}
delete pval->cai.pElems;
}
else if (pval->vt == VT_VARIANT)
{
UnmakeVal(pval->pvarVal);
delete pval->pvarVal;
}
else if (pval->vt == VT_CF)
delete pval->pClipData;
}
void DispVal(VARIANT *pdpv);
void DispSingleVal(DFPROPTYPE dpt, void *pval)
{
HRESULT hr;
switch(dpt)
{
case VT_ILLEGAL:
printf("illegal\n");
break;
case VT_EMPTY:
printf("empty\n");
break;
case VT_I2:
case VT_I2 | VT_VECTOR:
printf("0x%04hX\n", *(short int *)pval);
break;
case VT_I4:
case VT_I4 | VT_VECTOR:
printf("0x%08lX\n", *(long int *)pval);
break;
case VT_R4:
case VT_R4 | VT_VECTOR:
printf("%f\n", *(float *)pval);
break;
case VT_R8:
case VT_R8 | VT_VECTOR:
printf("%lf\n", *(double *)pval);
break;
case VT_CY:
case VT_CY | VT_VECTOR:
CY *pcy;
pcy = (CY *)pval;
printf("0x%08lX:0x%08lX\n", pcy->Hi, pcy->Lo);
break;
case VT_DATE:
case VT_DATE | VT_VECTOR:
printf("%lf\n", *(DATE *)pval);
break;
case VT_BSTR:
case VT_BSTR | VT_VECTOR:
BSTR bstr;
bstr = *(BSTR *)pval;
printf("string form: '%s'\n", bstr);
printf("binary form: %lu bytes\n", BSTR_LEN(bstr));
BinText(BSTR_LEN(bstr), BSTR_PTR(bstr));
break;
case VT_WBSTR:
case VT_WBSTR | VT_VECTOR:
char str[80];
WBSTR wbstr;
wbstr = *(WBSTR *)pval;
wcstombs(str, wbstr, 80);
printf("string form: '%s'\n", str);
printf("binary form: %lu bytes\n", WBSTR_LEN(wbstr));
BinText(WBSTR_LEN(wbstr), WBSTR_PTR(wbstr));
break;
case VT_BOOL:
case VT_BOOL | VT_VECTOR:
printf("%d\n", *(VARIANT_BOOL *)pval);
break;
case VT_I8:
case VT_I8 | VT_VECTOR:
LARGE_INTEGER *pli;
pli = (LARGE_INTEGER *)pval;
printf("0x%08lX:%08lX\n", pli->HighPart, pli->LowPart);
break;
case VT_LPSTR:
case VT_LPSTR | VT_VECTOR:
printf("'%s'\n", *(LPSTR *)pval);
break;
case VT_BLOB:
case VT_BLOB_OBJECT:
BLOB *pblob;
pblob = (BLOB *)pval;
printf("%lu bytes\n", pblob->cbSize);
BinText(pblob->cbSize, pblob->pBlobData);
break;
case VT_LPWSTR:
case VT_LPWSTR | VT_VECTOR:
#define BUFSIZE 256
char szVal[BUFSIZE];
wcstombs(szVal, *(LPWSTR *)pval, BUFSIZE);
printf("'%s'\n", szVal);
break;
case VT_FILETIME:
case VT_FILETIME | VT_VECTOR:
FILETIME *pstm;
pstm = (FILETIME *)pval;
printf("0x%08lX:0x%08lX\n", pstm->dwHighDateTime, pstm->dwLowDateTime);
break;
case VT_UUID:
printf("UUID: %s\n", GuidText(*(GUID **)pval));
break;
case VT_UUID | VT_VECTOR:
printf("UUID: %s\n", GuidText((GUID *)pval));
break;
case VT_VARIANT:
printf("VARIANT type 0x%X: ", (*(VARIANT **)pval)->vt);
DispVal(*(VARIANT **)pval);
break;
case VT_VARIANT | VT_VECTOR:
printf("VARIANT type 0x%X: ", ((VARIANT *)pval)->vt);
DispVal((VARIANT *)pval);
break;
case VT_STREAM:
case VT_STREAMED_OBJECT:
IStream *pistm;
pistm = *(IStream **)pval;
BYTE buf[sizeof(STREAM_VAL)];
ULONG cbRead;
LARGE_INTEGER li;
li.HighPart = 0;
li.LowPart = 0;
hr = pistm->Seek(li, STREAM_SEEK_SET, NULL);
if (FAILED(hr))
Result(hr, "DispVal stream seek");
hr = pistm->Read(buf, sizeof(STREAM_VAL), &cbRead);
if (FAILED(hr))
Result(hr, "DispVal stream read");
printf("read %lu bytes\n", cbRead);
BinText(cbRead, buf);
break;
case VT_STORAGE:
case VT_STORED_OBJECT:
IStorage *pistg;
pistg = *(IStorage **)pval;
printf("contents:\n");
c_tree(pistg);
break;
case VT_CF:
CLIPDATA *pcd;
pcd = *(CLIPDATA **)pval;
printf("%lu bytes, format %lu\n", pcd->cbSize, pcd->ulClipFmt);
BinText(pcd->cbSize-sizeof(ULONG), pcd->pClipData);
break;
default:
printf("** Unknown property type in DispVal: 0x%X\n", dpt);
break;
}
}
void DispVal(VARIANT *pdpv)
{
ULONG i;
DFPROPTYPE dpt;
dpt = pdpv->vt & VT_TYPEMASK;
printf("%s val is ", props[prop_index(dpt)].pszName);
if (pdpv->vt & VT_VECTOR)
{
BYTE *pb = (BYTE *)pdpv->cai.pElems;
int indx = prop_index(dpt);
printf("%lu element array:\n", pdpv->cai.cElems);
for (i = 0; i < pdpv->cai.cElems; i++)
{
printf(" %02d - ", i+1);
DispSingleVal(pdpv->vt, pb);
pb += props[indx].size;
}
}
else
DispSingleVal(pdpv->vt, &pdpv->iVal);
}
void CheckVal(VARIANT *pdpv);
void CheckSingleVal(DFPROPTYPE dpt, BYTE *pval)
{
HRESULT hr;
switch(dpt)
{
case VT_EMPTY:
break;
case VT_I2:
case VT_I2 | VT_VECTOR:
if (*(short int *)pval != I2_VAL)
Fail("I2 val is %d rather than %d\n", *(short int *)pval,
I2_VAL);
break;
case VT_I4:
case VT_I4 | VT_VECTOR:
if (*(long int *)pval != I4_VAL)
Fail("I4 val is %d rather than %d\n", *(long int *)pval,
I4_VAL);
break;
case VT_R4:
case VT_R4 | VT_VECTOR:
if (*(float *)pval != R4_VAL)
Fail("R4 val is %f rather than %f\n", *(float *)pval,
R4_VAL);
break;
case VT_R8:
case VT_R8 | VT_VECTOR:
if (*(double *)pval != R8_VAL)
Fail("R8 val is %lf rather than %lf\n", *(double *)pval,
R8_VAL);
break;
case VT_CY:
case VT_CY | VT_VECTOR:
CY *pcy;
pcy = (CY *)pval;
if (memcmp(pcy, &CY_VAL, sizeof(CY)) != 0)
Fail("CY val is 0x%08lX:0x%08lX rather than 0x%08lX:0x%08lX\n",
pcy->Hi, pcy->Lo, CY_VAL.Hi, CY_VAL.Lo);
break;
case VT_DATE:
case VT_DATE | VT_VECTOR:
if (*(DATE *)pval != DATE_VAL)
Fail("DATE val is %lf rather than %lf\n", *(DATE *)pval,
DATE_VAL);
break;
case VT_BSTR:
case VT_BSTR | VT_VECTOR:
if (BSTR_LEN(*(BSTR *)pval) != BSTR_LEN(BSTR_VAL) ||
memcmp(BSTR_PTR(*(BSTR *)pval), BSTR_PTR(BSTR_VAL),
BSTR_LEN(BSTR_VAL)) != 0)
Fail("BSTR value doesn't match\n");
break;
case VT_WBSTR:
case VT_WBSTR | VT_VECTOR:
if (WBSTR_LEN(*(WBSTR *)pval) != WBSTR_LEN(WBSTR_VAL) ||
memcmp(WBSTR_PTR(*(WBSTR *)pval), WBSTR_PTR(WBSTR_VAL),
WBSTR_LEN(WBSTR_VAL)) != 0)
{
WBSTR wbstr;
DispSingleVal(VT_WBSTR, pval);
wbstr = WBSTR_VAL;
DispSingleVal(VT_WBSTR, &wbstr);
Fail("WBSTR value doesn't match\n");
}
break;
case VT_BOOL:
case VT_BOOL | VT_VECTOR:
if (*(VARIANT_BOOL *)pval != F_VAL)
Fail("BOOL val is %d rather than %d\n", *(VARIANT_BOOL *)pval,
F_VAL);
break;
case VT_I8:
case VT_I8 | VT_VECTOR:
LARGE_INTEGER *pli;
pli = (LARGE_INTEGER *)pval;
if (memcmp(pli, &I8_VAL, sizeof(LARGE_INTEGER)) != 0)
Fail("I8 val is 0x%08lX:0x%08lX rather than 0x%08lX:0x%08lX\n",
pli->HighPart, pli->LowPart, I8_VAL.HighPart,
I8_VAL.LowPart);
break;
case VT_LPSTR:
case VT_LPSTR | VT_VECTOR:
if (strcmp(*(LPSTR *)pval, LPSTR_VAL) != 0)
Fail("LPSTR val is '%s' rather than '%s'\n", *(LPSTR *)pval,
LPSTR_VAL);
break;
case VT_BLOB:
case VT_BLOB_OBJECT:
BLOB *pblob;
pblob = (BLOB *)pval;
if (pblob->cbSize != sizeof(BLOB_VAL) ||
memcmp(pblob->pBlobData, BLOB_VAL, sizeof(BLOB_VAL)) != 0)
Fail("BLOB val doesn't match\n");
break;
case VT_LPWSTR:
case VT_LPWSTR | VT_VECTOR:
if (wcscmp(*(LPWSTR *)pval, LPWSTR_VAL) != 0)
Fail("LPWSTR val doesn't match\n");
break;
case VT_FILETIME:
case VT_FILETIME | VT_VECTOR:
FILETIME *pstm;
pstm = (FILETIME *)pval;
if (memcmp(pstm, &FILETIME_VAL, sizeof(FILETIME)) != 0)
Fail("FILETIME val doesn't match\n");
break;
case VT_UUID:
if (memcmp(*(GUID **)pval, &UUID_VAL, sizeof(GUID)) != 0)
Fail("UUID val doesn't match\n");
break;
case VT_UUID | VT_VECTOR:
if (memcmp((GUID *)pval, &UUID_VAL, sizeof(GUID)) != 0)
Fail("UUID val doesn't match\n");
break;
case VT_VARIANT:
if ((*(VARIANT **)pval)->vt != VARIANT_VAL)
Fail("VARIANT type 0x%X doesn't match 0x%X\n",
(*(VARIANT **)pval)->vt, VARIANT_VAL);
CheckVal(*(VARIANT **)pval);
break;
case VT_VARIANT | VT_VECTOR:
if (((VARIANT *)pval)->vt != (VARIANT_VAL | VT_VECTOR))
Fail("VARIANT type 0x%X doesn't match 0x%X\n",
((VARIANT *)pval)->vt, (VARIANT_VAL | VT_VECTOR));
CheckVal((VARIANT *)pval);
break;
case VT_STREAM:
case VT_STREAMED_OBJECT:
IStream *pistm;
pistm = *(IStream **)pval;
BYTE buf[sizeof(STREAM_VAL)];
ULONG cbRead;
STATSTG stat;
LARGE_INTEGER li;
hr = pistm->Stat(&stat, STATFLAG_NONAME);
if (FAILED(hr))
Result(hr, "CheckVal stream stat");
if (stat.cbSize.HighPart != 0 ||
stat.cbSize.LowPart != sizeof(STREAM_VAL))
Fail("Stream size doesn't match\n");
li.HighPart = 0;
li.LowPart = 0;
hr = pistm->Seek(li, STREAM_SEEK_SET, NULL);
if (FAILED(hr))
Result(hr, "CheckVal stream seek");
hr = pistm->Read(buf, sizeof(STREAM_VAL), &cbRead);
if (FAILED(hr))
Result(hr, "CheckVal stream read");
if (cbRead != sizeof(STREAM_VAL))
Fail("Read %d byte rather than %d\n", cbRead, sizeof(STREAM_VAL));
if (memcmp(buf, STREAM_VAL, sizeof(STREAM_VAL)) != 0)
Fail("Stream val doesn't match\n");
break;
case VT_STORAGE:
case VT_STORED_OBJECT:
IStorage *pistg;
pistg = *(IStorage **)pval;
// BUGBUG - A real pain to check
break;
case VT_CF:
CLIPDATA *pcd;
pcd = *(CLIPDATA **)pval;
if (pcd->cbSize-sizeof(ULONG) != sizeof(CF_VAL) ||
pcd->ulClipFmt != CF_FMT ||
memcmp(pcd->pClipData, CF_VAL, sizeof(CF_VAL)) != 0)
Fail("CF val doesn't match\n");
break;
default:
printf("** Unknown property type in CheckVal: 0x%X\n", dpt);
break;
}
}
void CheckVal(VARIANT *pdpv)
{
ULONG i;
if (pdpv->vt & VT_VECTOR)
{
BYTE *pb = (BYTE *)pdpv->cai.pElems;
int indx = prop_index(pdpv->vt & VT_TYPEMASK);
if (pdpv->cai.cElems != ARRAY_SIZE)
Fail("%s array is size %d rather than %d\n", props[indx].pszName,
pdpv->cai.cElems, ARRAY_SIZE);
for (i = 0; i < pdpv->cai.cElems; i++)
{
CheckSingleVal(pdpv->vt, pb);
pb += props[indx].size;
}
}
else
CheckSingleVal(pdpv->vt, (BYTE *)&pdpv->iVal);
}
void test_props(IPropertyStorage *pprop)
{
VARIANT val[CTOTPROPS], *pval;
PROPSPEC pspec[CTOTPROPS];
ULONG i, cProps;
WCHAR *pwcs, **ppwcs;
FILETIME dtm;
PROPID pid[CTOTPROPS];
HRESULT hr;
CStrList sl;
SStrEntry *pse;
// Set up property value data
pval = val;
pwcs = (WCHAR *)&wcsNames[0];
ppwcs = pwcsNames;
cProps = 0;
for (i = 0; i < CPROPS; i++)
{
pspec[cProps].ulKind = PRSPEC_LPWSTR;
pspec[cProps].lpwstr = pwcs;
mbstowcs(pwcs, props[i].pszName, CWCSTORAGENAME);
pse = sl.Add(pwcs);
pse->user.dw = props[i].dpt;
*ppwcs++ = pwcs;
pwcs += CWCSTORAGENAME;
MakeVal(props[i].dpt, pval++);
cProps++;
if (props[i].fArray)
{
pspec[cProps].ulKind = PRSPEC_LPWSTR;
pspec[cProps].lpwstr = pwcs;
pwcs[0] = L'#';
mbstowcs(pwcs+1, props[i].pszName, CWCSTORAGENAME);
pse = sl.Add(pwcs);
pse->user.dw = props[i].dpt | VT_VECTOR;
*ppwcs++ = pwcs;
pwcs += CWCSTORAGENAME;
MakeVal(props[i].dpt | VT_VECTOR, pval++);
cProps++;
}
}
printf("%lu properties\n", cProps);
// WriteMultiple for named properties
hr = pprop->WriteMultiple(cProps, pspec, pid, val);
Result(hr, "WriteMultiple");
for (i = 0; i < cProps; i++)
{
printf("%2d propid is %lu\n", i, pid[i]);
UnmakeVal(&val[i]);
}
hr = pprop->Commit(0);
Result(hr, "Commit");
hr = pprop->Revert();
Result(hr, "Revert");
// ReadMultiple for named properties
hr = pprop->ReadMultiple(cProps, pspec, &dtm, pid, val);
Result(hr, "ReadMultiple");
printf("dtm is %s\n", FileTimeText(&dtm));
for (i = 0; i<cProps; i++)
{
if (pid[i] == PROPID_UNKNOWN)
Fail("Property %d not found\n", i);
printf("%2d propid is %lu\n", i, pid[i]);
DispVal(&val[i]);
pse = sl.Find(pspec[i].lpwstr);
if (pse == NULL)
Fail("Unable to find written property '%s'\n", pspec[i].lpwstr);
if (pse->user.dw != val[i].vt)
Fail("Property '%s' is type %d rather than %d\n",
TcsText(pse->atc), val[i].vt, pse->user.dw);
CheckVal(&val[i]);
}
hr = FreeVariantArray(cProps, val);
Result(hr, "FreeVariantArray");
#ifdef GET_IDS_OF_NAMES
// GetIDsOfNames
hr = pprop->GetIDsOfNames(cProps, pwcsNames, pid);
Result(hr, "GetIDsOfNames");
for (i = 0; i < cProps; i++)
printf("%2d propid is %lu\n", i, pid[i]);
#endif
// Non-existent property
PROPSPEC pspecNot;
pspecNot.ulKind = PRSPEC_LPWSTR;
pspecNot.lpwstr = L"NotThere";
hr = pprop->ReadMultiple(1, &pspecNot, &dtm, pid, val);
Result(hr, "ReadMultiple on non-existent property");
DispVal(&val[0]);
if (val[0].vt != VT_ILLEGAL)
Fail("Nonexistent property returned a real value %d\n", val[0].vt);
if (pid[0] != PROPID_UNKNOWN)
Fail("Nonexistent property returned a real propid %lu\n", pid[0]);
// Enumerator test
IEnumSTATPROPSTG *penm;
STATPROPSTG stat;
char szName[CWCSTORAGENAME];
hr = pprop->Enum(&penm);
Result(hr, "Enum");
for (;;)
{
hr = penm->Next(1, &stat, NULL);
Result(hr, "Next");
if (GetScode(hr) == S_FALSE)
break;
if (stat.lpwstrName)
{
wcstombs(szName, stat.lpwstrName, CWCSTORAGENAME);
CoMemFree(stat.lpwstrName);
pse = sl.Find(stat.lpwstrName);
if (pse == NULL)
{
Fail("Enumerator returned unknown name '%s'\n", szName);
}
if (pse->user.dw != stat.vt)
Fail("Property '%s' is type %d rather than %d\n",
szName, val[i].vt, pse->user.dw);
sl.Remove(pse);
printf("%s, ", szName);
}
else
{
Fail("Enumerator returned unnamed property "
"dispid %lu, propid %lu\n",
stat.dispid, stat.propid);
}
printf("vt 0x%X, did %lu, pid %lu, size %lu\n", stat.vt, stat.dispid,
stat.propid, stat.cbSize);
}
printf("Release enumerator = %lu\n",
penm->Release());
if (sl.GetHead())
{
for (pse = sl.GetHead(); pse; pse = pse->pseNext)
printf("Enumerator didn't return '%s'\n", TcsText(pse->atc));
Fail("Missing elements in enumeration\n");
}
// DeleteMultiple
BOOL fPresent;
fPresent = FALSE;
hr = pprop->DeleteMultiple(cProps, pspec);
Result(hr, "DeleteMultiple");
hr = pprop->Enum(&penm);
Result(hr, "Enum");
for (;;)
{
hr = penm->Next(1, &stat, NULL);
Result(hr, "Next");
if (GetScode(hr) == S_FALSE)
break;
fPresent = TRUE;
wcstombs(szName, stat.lpwstrName, CWCSTORAGENAME);
CoMemFree(stat.lpwstrName);
printf("%s, vt 0x%X, did %lu, pid %lu, size %lu\n",
szName, stat.vt, stat.dispid, stat.propid, stat.cbSize);
}
printf("Release enumerator = %lu\n",
penm->Release());
if (fPresent)
Fail("Enumeration returned entries after DeleteMultiple\n");
#ifdef GET_IDS_OF_NAMES
// GetIDsOfNames on deleted entries
hr = pprop->GetIDsOfNames(cProps, pwcsNames, did);
Result(hr, "GetIDsOfNames on deleted");
for (i = 0; i < cProps; i++)
printf("%2d dispid is %lu\n", i, did[i]);
#endif
// WriteMultiple with ids and names
pspec[0].ulKind = PRSPEC_DISPID;
pspec[0].dispid = 1;
MakeVal(VT_I2, val);
pspec[1].ulKind = PRSPEC_LPWSTR;
pspec[1].lpwstr = L"TestName";
MakeVal(VT_I4, val+1);
pspec[2].ulKind = PRSPEC_PROPID;
// Hack
pspec[2].propid = PROPID_FIRST-1;
MakeVal(VT_I8, val+2);
cProps = 3;
hr = pprop->WriteMultiple(cProps, pspec, pid, val);
Result(hr, "WriteMultiple");
for (i = 0; i < cProps; i++)
{
printf("%2d propid is %lu\n", i, pid[i]);
UnmakeVal(&val[i]);
}
// ReadMultiple for ids and id for a named property
pspec[1].ulKind = PRSPEC_PROPID;
pspec[1].propid = pid[1];
hr = pprop->ReadMultiple(cProps, pspec, &dtm, pid, val);
Result(hr, "ReadMultiple");
printf("dtm is %s\n", FileTimeText(&dtm));
for (i = 0; i<cProps; i++)
{
printf("%2d propid is %lu\n", i, pid[i]);
DispVal(&val[i]);
CheckVal(&val[i]);
}
hr = FreeVariantArray(cProps, val);
Result(hr, "FreeVariantArray");
}
void _CRTAPI1 main(int argc, char *argv[])
{
IStorage *pstg, *pstgRoot;
IPropertySetStorage *ppset;
IPropertyStorage *pprop;
HRESULT hr;
STATPROPSETSTG stat;
StartTest("prop");
CmdArgs(argc, argv);
CreateTestFile(NULL, ROOTP(STGM_RW) | STGM_CREATE, FALSE, &pstgRoot, NULL);
hr = pstgRoot->QueryInterface(IID_IPropertySetStorage,
(void **)&ppset);
Result(hr, "QI to IPropertySetStorage");
hr = ppset->Create(IID_IPropertySetStorage, STGP(STGM_RW), &pprop);
Result(hr, "Create propset");
hr = pprop->QueryInterface(IID_IStorage, (void **)&pstg);
Result(hr, "Cheat QI to IStorage");
hr = pstg->CreateStorage(TEXT("Storage"), STGP(STGM_RW), 0, 0,
&pstgProp);
Result(hr, "Create embedding in propset");
hr = pstgProp->CreateStream(TEXT("Stream"), STMP(STGM_RW), 0, 0,
&pstmProp);
Result(hr, "Create stream in embedding");
hr = pstmProp->Write(STREAM_VAL, sizeof(STREAM_VAL), NULL);
Result(hr, "Write to stream");
LARGE_INTEGER lOff;
LISet32(lOff, 0);
hr = pstmProp->Seek(lOff, STREAM_SEEK_SET, NULL);
Result(hr, "Seek to zero");
hr = pprop->Stat(&stat);
Result(hr, "Stat propset");
if (!IsEqualIID(stat.iid, IID_IPropertySetStorage))
Fail("Property set Stat returned GUID %s\n", GuidText(&stat.iid));
printf("IID: %s\n", GuidText(&stat.iid));
printf("ctime %s\n", FileTimeText(&stat.ctime));
printf("mtime %s\n", FileTimeText(&stat.mtime));
printf("atime %s\n", FileTimeText(&stat.atime));
test_props(pprop);
printf("Release IPropertyStorage = %lu\n",
pprop->Release());
printf("Release stream = %lu\n",
pstmProp->Release());
printf("Release embedding = %lu\n",
pstgProp->Release());
printf("Release cheat IStorage = %lu\n",
pstg->Release());
hr = ppset->Open(IID_IPropertySetStorage, STGP(STGM_RW), &pprop);
Result(hr, "Open propset");
printf("Release IPropertyStorage = %lu\n",
pprop->Release());
IEnumSTATPROPSETSTG *penm;
hr = ppset->Enum(&penm);
Result(hr, "Enum");
for (;;)
{
hr = penm->Next(1, &stat, NULL);
Result(hr, "Next");
if (GetScode(hr) == S_FALSE)
break;
printf("IID: %s\n", GuidText(&stat.iid));
printf("ctime %s\n", FileTimeText(&stat.ctime));
printf("mtime %s\n", FileTimeText(&stat.mtime));
printf("atime %s\n", FileTimeText(&stat.atime));
}
printf("Release enumerator = %lu\n",
penm->Release());
hr = ppset->Delete(IID_IPropertySetStorage);
Result(hr, "Delete propset");
hr = ppset->Enum(&penm);
Result(hr, "Enum");
for (;;)
{
hr = penm->Next(1, &stat, NULL);
Result(hr, "Next");
if (GetScode(hr) == S_FALSE)
break;
printf("IID: %s\n", GuidText(&stat.iid));
printf("ctime %s\n", FileTimeText(&stat.ctime));
printf("mtime %s\n", FileTimeText(&stat.mtime));
printf("atime %s\n", FileTimeText(&stat.atime));
}
printf("Release enumerator = %lu\n",
penm->Release());
printf("Release IPropertySetStorage = %lu\n",
ppset->Release());
printf("Release root docfile = %lu\n",
pstgRoot->Release());
EndTest(0);
}