|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
TestIWiaPropertyStorage.cpp
Abstract:
Author:
Hakki T. Bostanci (hakkib) 06-Apr-2000
Revision History:
--*/
#include "stdafx.h"
#ifdef DEFINE_TEMPLATES
template <class T, class U> void SubTestValidValuesRange( CMyWiaPropertyStorage *pProp, const CPropSpec &rPropSpec, VARTYPE vt, T &Range, U &CurrentValue, BOOL bReadOnly ) { if (LOG_CMP(Range.cElems, ==, WIA_RANGE_NUM_ELEMS)) { // minimum value must be lower than the maximum value
LOG_CMP(Range.pElems[WIA_RANGE_MIN], <, Range.pElems[WIA_RANGE_MAX]);
// nominal value must be in the given range
LOG_CMP(Range.pElems[WIA_RANGE_NOM], >=, Range.pElems[WIA_RANGE_MIN]); LOG_CMP(Range.pElems[WIA_RANGE_NOM], <=, Range.pElems[WIA_RANGE_MAX]);
// current value must be in the given range
LOG_CMP(CurrentValue, >=, Range.pElems[WIA_RANGE_MIN]); LOG_CMP(CurrentValue, <=, Range.pElems[WIA_RANGE_MAX]);
// the step must be greater than zero
LOG_CMP(Range.pElems[WIA_RANGE_STEP], >, 0);
// skip changing values if another thread is in image transfer mode
if (!bReadOnly && s_PropWriteCritSect.TryEnter()) { // try to write the min, max, nom values and a random value
LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_MIN]) ), == S_OK);
LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_MAX]) ), == S_OK); LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_NOM]) ), == S_OK); LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_MIN] + Range.pElems[WIA_RANGE_STEP]) ), == S_OK); LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_MAX] - Range.pElems[WIA_RANGE_STEP]) ), == S_OK); LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_MIN] - Range.pElems[WIA_RANGE_STEP]) ), != S_OK); LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_MAX] + Range.pElems[WIA_RANGE_STEP]) ), != S_OK);
if (Range.pElems[WIA_RANGE_STEP] > 1) { LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_MIN] + 1) ), != S_OK); LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Range.pElems[WIA_RANGE_MAX] - 1) ), != S_OK); } // write back the current value
LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(CurrentValue) ), == S_OK);
s_PropWriteCritSect.Leave(); } } }
template <class T, class U> void SubTestValidValuesList( CMyWiaPropertyStorage *pProp, const CPropSpec &rPropSpec, VARTYPE vt, T &List, U &CurrentValue, BOOL bReadOnly ) { if (LOG_CMP(List.cElems, >=, WIA_LIST_NUM_ELEMS)) { // compare WIA_LIST_COUNT entry against the value we expect
ULONG ulNumValues = List.cElems - WIA_LIST_NUM_ELEMS;
//LOG_CMP((ULONG) List.pElems[WIA_LIST_COUNT], ==, ulNumValues);
// search the list for any duplicates and find the indices of
// the nominal value and the current value
ULONG nNomIndex = -1; ULONG nCurIndex = -1;
for (int i = WIA_LIST_VALUES; i < ulNumValues + WIA_LIST_VALUES; ++i) { for (int j = i + 1; j < ulNumValues + WIA_LIST_VALUES; ++j) { LOG_CMP(List.pElems[i], !=, List.pElems[j]); }
if (IsEqual(List.pElems[i], List.pElems[WIA_LIST_NOM])) { nNomIndex = i; }
if (IsEqual(List.pElems[i], CurrentValue)) { nCurIndex = i; } }
// the nominal value must be one of the legal values
if (nNomIndex == -1) { LOG_ERROR( _T("List.pElems[WIA_LIST_NOM] == (%s) %s not found in list"), (PCTSTR) VarTypeToStr(vt), (PCTSTR) ToStr((PVOID) &List.pElems[WIA_LIST_NOM], vt) ); }
// the current value must be set to one of the legal values
if (nCurIndex == -1) { LOG_ERROR( _T("Current value == (%s) %s not found in list"), (PCTSTR) VarTypeToStr(vt), (PCTSTR) ToStr((PVOID) &CurrentValue, vt) ); }
// skip changing values if another thread is in image transfer mode
if (!bReadOnly && s_PropWriteCritSect.TryEnter()) { // try to write each property in the list
for (int j = WIA_LIST_VALUES; j < ulNumValues + WIA_LIST_VALUES; ++j) { LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(List.pElems[j]) ), == S_OK); } // write back the current value
LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(CurrentValue) ), == S_OK);
s_PropWriteCritSect.Leave(); } } }
template <class T, class U> void SubTestValidValuesFlags( CMyWiaPropertyStorage *pProp, const CPropSpec &rPropSpec, VARTYPE vt, T &Flags, U &CurrentValue, BOOL bReadOnly ) { if (LOG_CMP(Flags.cElems, ==, WIA_FLAG_NUM_ELEMS)) { // the nominal and current values should have no unallowed bits set
LOG_CMP(Flags.pElems[WIA_FLAG_NOM] & ~Flags.pElems[WIA_FLAG_VALUES], ==, 0);
LOG_CMP(CurrentValue & ~Flags.pElems[WIA_FLAG_VALUES], ==, 0);
// skip changing values if another thread is in image transfer mode
if (!bReadOnly && s_PropWriteCritSect.TryEnter()) { // try to write all allowed flags, no flags
LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(Flags.pElems[WIA_FLAG_VALUES]) ), == S_OK);
LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(0) ), == S_OK); if (~Flags.pElems[WIA_FLAG_VALUES] != 0) { LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(~Flags.pElems[WIA_FLAG_VALUES]) ), != S_OK); }
// write back the current value
LOG_HR(pProp->WriteVerifySingle( rPropSpec, CPropVariant(CurrentValue) ), == S_OK);
s_PropWriteCritSect.Leave(); } } } #else //DEFINE_TEMPLATES
#include "WiaStress.h"
//////////////////////////////////////////////////////////////////////////
//
//
//
void CWiaStressThread::TestValidValuesRange( CMyWiaPropertyStorage *pProp, const CPropSpec &rPropSpec, CPropVariant &varRange, CPropVariant &varValue, BOOL bReadOnly ) { switch (varRange.vt) { case VT_VECTOR | VT_I1: SubTestValidValuesRange(pProp, rPropSpec, VT_I1, varRange.cac, varValue.cVal, bReadOnly); break;
case VT_VECTOR | VT_UI1: SubTestValidValuesRange(pProp, rPropSpec, VT_UI1, varRange.caub, varValue.bVal, bReadOnly); break;
case VT_VECTOR | VT_I2: SubTestValidValuesRange(pProp, rPropSpec, VT_I2, varRange.cai, varValue.iVal, bReadOnly); break;
case VT_VECTOR | VT_UI2: SubTestValidValuesRange(pProp, rPropSpec, VT_UI2, varRange.caui, varValue.uiVal, bReadOnly); break;
case VT_VECTOR | VT_I4: SubTestValidValuesRange(pProp, rPropSpec, VT_I4, varRange.cal, varValue.lVal, bReadOnly); break;
case VT_VECTOR | VT_UI4: SubTestValidValuesRange(pProp, rPropSpec, VT_UI4, varRange.caul, varValue.ulVal, bReadOnly); break;
case VT_VECTOR | VT_R4: SubTestValidValuesRange(pProp, rPropSpec, VT_R4, varRange.caflt, varValue.fltVal, bReadOnly); break;
case VT_VECTOR | VT_R8: SubTestValidValuesRange(pProp, rPropSpec, VT_R8, varRange.cadbl, varValue.dblVal, bReadOnly); break;
default: LOG_ERROR(_T("Illegal values type %d for WIA_PROP_RANGE"), varValue.vt); break; } }
//////////////////////////////////////////////////////////////////////////
//
//
//
void CWiaStressThread::TestValidValuesList( CMyWiaPropertyStorage *pProp, const CPropSpec &rPropSpec, CPropVariant &varList, CPropVariant &varValue, BOOL bReadOnly ) { switch (varList.vt) { case VT_VECTOR | VT_I1: SubTestValidValuesList(pProp, rPropSpec, VT_I1, varList.cac, varValue.cVal, bReadOnly); break;
case VT_VECTOR | VT_UI1: SubTestValidValuesList(pProp, rPropSpec, VT_UI1, varList.caub, varValue.bVal, bReadOnly); break;
case VT_VECTOR | VT_I2: SubTestValidValuesList(pProp, rPropSpec, VT_I2, varList.cai, varValue.iVal, bReadOnly); break;
case VT_VECTOR | VT_UI2: SubTestValidValuesList(pProp, rPropSpec, VT_UI2, varList.caui, varValue.uiVal, bReadOnly); break;
case VT_VECTOR | VT_I4: SubTestValidValuesList(pProp, rPropSpec, VT_I4, varList.cal, varValue.lVal, bReadOnly); break;
case VT_VECTOR | VT_UI4: SubTestValidValuesList(pProp, rPropSpec, VT_UI4, varList.caul, varValue.ulVal, bReadOnly); break;
case VT_VECTOR | VT_R4: SubTestValidValuesList(pProp, rPropSpec, VT_R4, varList.caflt, varValue.fltVal, bReadOnly); break;
case VT_VECTOR | VT_R8: SubTestValidValuesList(pProp, rPropSpec, VT_R8, varList.cadbl, varValue.dblVal, bReadOnly); break;
case VT_VECTOR | VT_BSTR: SubTestValidValuesList(pProp, rPropSpec, VT_BSTR, varList.cabstr, varValue.bstrVal, bReadOnly); break;
case VT_VECTOR | VT_LPSTR: SubTestValidValuesList(pProp, rPropSpec, VT_LPSTR, varList.calpstr, varValue.pszVal, bReadOnly); break;
case VT_VECTOR | VT_LPWSTR: SubTestValidValuesList(pProp, rPropSpec, VT_LPWSTR, varList.calpwstr, varValue.pwszVal, bReadOnly); break;
case VT_VECTOR | VT_CLSID: SubTestValidValuesList(pProp, rPropSpec, VT_CLSID, varList.cauuid, *varValue.puuid, bReadOnly); break;
default: LOG_ERROR(_T("Illegal values type %d for WIA_PROP_LIST"), varValue.vt); break; } }
//////////////////////////////////////////////////////////////////////////
//
//
//
void CWiaStressThread::TestValidValuesFlags( CMyWiaPropertyStorage *pProp, const CPropSpec &rPropSpec, CPropVariant &varFlags, CPropVariant &varValue, BOOL bReadOnly ) { switch (varFlags.vt) { case VT_VECTOR | VT_I1: SubTestValidValuesFlags(pProp, rPropSpec, VT_I1, varFlags.cac, varValue.cVal, bReadOnly); break;
case VT_VECTOR | VT_UI1: SubTestValidValuesFlags(pProp, rPropSpec, VT_UI1, varFlags.caub, varValue.bVal, bReadOnly); break;
case VT_VECTOR | VT_I2: SubTestValidValuesFlags(pProp, rPropSpec, VT_I2, varFlags.cai, varValue.iVal, bReadOnly); break;
case VT_VECTOR | VT_UI2: SubTestValidValuesFlags(pProp, rPropSpec, VT_UI2, varFlags.caui, varValue.uiVal, bReadOnly); break;
case VT_VECTOR | VT_I4: SubTestValidValuesFlags(pProp, rPropSpec, VT_I4, varFlags.cal, varValue.lVal, bReadOnly); break;
case VT_VECTOR | VT_UI4: SubTestValidValuesFlags(pProp, rPropSpec, VT_UI4, varFlags.caul, varValue.ulVal, bReadOnly); break;
default: LOG_ERROR(_T("Illegal values type %d for WIA_PROP_FLAG"), varFlags.vt); break; } }
//////////////////////////////////////////////////////////////////////////
//
// test GetPropertyAttributes, ReadMultiple, WriteMultiple
//
void CWiaStressThread::TestPropStorage(CWiaItemData *pItemData) { LOG_INFO(_T("Testing IWiaPropertyStorage on %ws"), pItemData->bstrFullName);
CComQIPtr<CMyWiaPropertyStorage, &IID_IWiaPropertyStorage> pProp(pItemData->pWiaItem);
CComPtr<CMyEnumSTATPROPSTG> pEnumSTATPROPSTG;
CHECK_HR(pProp->Enum((IEnumSTATPROPSTG **) &pEnumSTATPROPSTG));
// find the number of properties
ULONG ulNumProps = -1;
CHECK_HR(pProp->GetCount(&ulNumProps));
if (ulNumProps == 0) { return; }
// read the property names
CCppMem<CStatPropStg> pStatPropStg(ulNumProps);
ULONG celtFetched = -1;
CHECK_HR(pEnumSTATPROPSTG->Next(ulNumProps, pStatPropStg, &celtFetched));
//
CCppMem<CPropSpec> pPropSpec(ulNumProps);
for (int i = 0; i < ulNumProps; ++i) { if (rand() % 8 < 4) // bugbug: cover all str, all propid and mixed cases...
{ pPropSpec[i] = pStatPropStg[i].lpwstrName; } else { pPropSpec[i] = pStatPropStg[i].propid; } }
//
CPropSpec InvalidPropSpec = L"invalid property name";
//
CCppMem<ULONG> pulAccessRights(ulNumProps); CCppMem<CPropVariant> pvarValidValues(ulNumProps);
if (LOG_HR(pProp->GetPropertyAttributes(ulNumProps, pPropSpec, pulAccessRights, pvarValidValues), == S_OK)) { CCppMem<CPropVariant> pvarValue(ulNumProps);
if (LOG_HR(pProp->ReadMultiple(ulNumProps, pPropSpec, pvarValue), == S_OK)) { FOR_SELECTED(i, ulNumProps) { USES_CONVERSION; m_pszContext = W2T(pStatPropStg[i].lpwstrName);
// examine R/W rights and legal values separately
ULONG ulReadWriteRights = pulAccessRights[i] & (WIA_PROP_READ | WIA_PROP_WRITE);
ULONG ulLegalValues = pulAccessRights[i] & (WIA_PROP_NONE | WIA_PROP_RANGE | WIA_PROP_LIST | WIA_PROP_FLAG);
// at least one of the R/W rights should be set
if (ulReadWriteRights == 0) { LOG_ERROR(_T("WIA_PROP_READ and/or WIA_PROP_WRITE should be specified")); }
// if this is a read only item, a list of legal values is not necessary
BOOL bReadOnly = !(ulReadWriteRights & WIA_PROP_WRITE);
// check that the type of the returned value is the same as the advertised
LOG_CMP(pvarValue[i].vt, ==, pStatPropStg[i].vt);
// check that the type of the legal values are the same as the advertised
if (ulLegalValues != WIA_PROP_NONE) { LOG_CMP(pvarValidValues[i].vt, ==, VT_VECTOR | pStatPropStg[i].vt); }
switch (ulLegalValues) { case WIA_PROP_NONE: break;
case WIA_PROP_RANGE: TestValidValuesRange(pProp, pPropSpec[i], pvarValidValues[i], pvarValue[i], bReadOnly); break;
case WIA_PROP_LIST: TestValidValuesList(pProp, pPropSpec[i], pvarValidValues[i], pvarValue[i], bReadOnly); break;
case WIA_PROP_FLAG: TestValidValuesFlags(pProp, pPropSpec[i], pvarValidValues[i], pvarValue[i], bReadOnly); break;
default: LOG_ERROR(_T("Unrecognized legal values flag 0x%p"), ulLegalValues); break; }
m_pszContext = 0; } }
// bad parameter tests for ReadMultiple
if (m_bRunBadParamTests) { // pass NULL propspecs
FreePropVariantArray(ulNumProps, pvarValue);
LOG_HR(pProp->ReadMultiple(ulNumProps, 0, pvarValue), != S_OK);
for (i = 0; i < ulNumProps; ++i) { LOG_CMP(pvarValue[i].vt, ==, VT_EMPTY); }
// pass invalid propspec
FreePropVariantArray(ulNumProps, pvarValue);
LOG_HR(pProp->ReadMultiple(1, &InvalidPropSpec, pvarValue), != S_OK);
for (i = 0; i < ulNumProps; ++i) { LOG_CMP(pvarValue[i].vt, ==, VT_EMPTY); }
// pass NULL pvarValue
LOG_HR(pProp->ReadMultiple(ulNumProps, pPropSpec, 0), != S_OK);
for (i = 0; i < ulNumProps; ++i) { LOG_CMP(pvarValue[i].vt, ==, VT_EMPTY); }
// bad parameter test for WriteMultiple
FreePropVariantArray(ulNumProps, pvarValue);
// pass NULL propspecs
LOG_HR(pProp->WriteMultiple(ulNumProps, 0, pvarValue, WIA_IPA_FIRST), != S_OK);
// pass NULL pvarValue
LOG_HR(pProp->WriteMultiple(ulNumProps, pPropSpec, 0, WIA_IPA_FIRST), != S_OK); } }
// bad parameter tests for GetPropertyAttributes
if (m_bRunBadParamTests) { // try to read 0 properties
FreePropVariantArray(ulNumProps, pvarValidValues);
LOG_HR(pProp->GetPropertyAttributes(0, pPropSpec, pulAccessRights, pvarValidValues), == S_FALSE);
for (i = 0; i < ulNumProps; ++i) { LOG_CMP(pvarValidValues[i].vt, ==, VT_EMPTY); }
// pass NULL propspecs
FreePropVariantArray(ulNumProps, pvarValidValues);
LOG_HR(pProp->GetPropertyAttributes(ulNumProps, 0, pulAccessRights, pvarValidValues), != S_OK);
for (i = 0; i < ulNumProps; ++i) { LOG_CMP(pvarValidValues[i].vt, ==, VT_EMPTY); }
// pass invalid propspec
FreePropVariantArray(ulNumProps, pvarValidValues);
LOG_HR(pProp->GetPropertyAttributes(1, &InvalidPropSpec, pulAccessRights, pvarValidValues), == S_FALSE);
for (i = 0; i < ulNumProps; ++i) { LOG_CMP(pvarValidValues[i].vt, ==, VT_EMPTY); }
// pass NULL access rights array
FreePropVariantArray(ulNumProps, pvarValidValues);
LOG_HR(pProp->GetPropertyAttributes(ulNumProps, pPropSpec, 0, pvarValidValues), != S_OK);
for (i = 0; i < ulNumProps; ++i) { LOG_CMP(pvarValidValues[i].vt, ==, VT_EMPTY); } } }
//////////////////////////////////////////////////////////////////////////
//
//
//
void CWiaStressThread::TestPropGetCount(CWiaItemData *pItemData) { LOG_INFO(_T("Testing GetCount() on %ws"), pItemData->bstrFullName);
CComQIPtr<IWiaPropertyStorage> pProp(pItemData->pWiaItem);
CHECK(pProp != 0);
CComPtr<IEnumSTATPROPSTG> pEnum;
CHECK_HR(pProp->Enum(&pEnum));
// First, get the item count using GetCount()
ULONG cItemsFromGetCount = 0;
if (LOG_HR(pProp->GetCount(&cItemsFromGetCount), == S_OK)) { // Now, find the item count by first resetting the enumerator
// and then querying for each item one by one using Next()
ULONG cItemsFromNext = 0;
CHECK_HR(pEnum->Reset());
HRESULT hr;
do { // verify that GetCount returns the same result after a Next or Reset
ULONG cItemsFromGetCountNow = 0;
LOG_HR(pProp->GetCount(&cItemsFromGetCountNow), == S_OK);
LOG_CMP(cItemsFromGetCountNow, ==, cItemsFromGetCount);
// get the next item
CStatPropStg Item; ULONG cFetched = 0;
hr = pEnum->Next(1, &Item, &cFetched);
cItemsFromNext += cFetched; } while (hr == S_OK);
LOG_HR(hr, == S_FALSE);
// verify that the two counts are equal
LOG_CMP(cItemsFromNext, ==, cItemsFromGetCount); }
// test bad param
if (m_bRunBadParamTests) { LOG_HR(pProp->GetCount(0), != S_OK); } }
//////////////////////////////////////////////////////////////////////////
//
//
//
void CWiaStressThread::TestReadPropertyNames(CWiaItemData *pItemData) { LOG_INFO(_T("Testing ReadPropertyNames() on %ws"), pItemData->bstrFullName);
int i;
CComQIPtr<CMyWiaPropertyStorage, &IID_IWiaPropertyStorage> pProp(pItemData->pWiaItem);
CComPtr<CMyEnumSTATPROPSTG> pEnumSTATPROPSTG;
CHECK_HR(pProp->Enum((IEnumSTATPROPSTG **) &pEnumSTATPROPSTG));
// find the number of properties
ULONG ulNumProps = -1;
CHECK_HR(pProp->GetCount(&ulNumProps));
if (ulNumProps == 0) { return; }
// read the property names and id's using the enum interface
CCppMem<CStatPropStg> pStatPropStg(ulNumProps);
ULONG celtFetched = -1;
CHECK_HR(pEnumSTATPROPSTG->Next(ulNumProps, pStatPropStg, &celtFetched));
// test legal case
CCppMem<PROPID> pPropId(ulNumProps); CCppMem<LPOLESTR> ppwstrName(ulNumProps, TRUE);
for (i = 0; i < ulNumProps; ++i) { pPropId[i] = pStatPropStg[i].propid; }
LOG_HR(pProp->ReadPropertyNames(ulNumProps, pPropId, ppwstrName), == S_OK);
// cross check the results
for (i = 0; i < ulNumProps; ++i) { if (wcssafecmp(ppwstrName[i], pStatPropStg[i].lpwstrName) != 0) { LOG_ERROR( _T("ReadPropertyNames() %ws != Enum() %ws for PROPID=%d"), ppwstrName[i], pStatPropStg[i].lpwstrName, pPropId[i] ); } }
for (i = 0; i < ulNumProps; ++i) { CoTaskMemFree(ppwstrName[i]); ppwstrName[i] = 0; }
// test illegal cases
// if we try to read 0 properties, ReadPropertyNames() should
// return S_FALSE and should not touch ppwstrName
LOG_HR(pProp->ReadPropertyNames(0, pPropId, ppwstrName), == S_FALSE);
for (i = 0; i < ulNumProps; ++i) { if (ppwstrName[i] != 0) { LOG_ERROR(_T("ReadPropertyNames() hr == S_FALSE but ppwstrName[%d]=%ws"), i, ppwstrName[i]); } }
// pass invalid ppwstrName pointer
LOG_HR(pProp->ReadPropertyNames(ulNumProps, pPropId, 0), != S_OK);
// pass invalid pPropId pointer
LOG_HR(pProp->ReadPropertyNames(ulNumProps, 0, ppwstrName), != S_OK);
// try to read non-existent name
PROPID PropId = -1; LPOLESTR pwstrName = 0;
LOG_HR(pProp->ReadPropertyNames(1, &PropId, &pwstrName), == S_FALSE); }
//////////////////////////////////////////////////////////////////////////
//
//
//
void CWiaStressThread::TestEnumSTATPROPSTG(CWiaItemData *pItemData) { LOG_INFO(_T("Testing EnumSTATPROPSTG() on %ws"), pItemData->bstrFullName);
CComQIPtr<IWiaPropertyStorage> pProp(pItemData->pWiaItem);
CHECK(pProp != 0);
// test valid cases
CComPtr<CMyEnumSTATPROPSTG> pEnumSTATPROPSTG;
if (LOG_HR(pProp->Enum((IEnumSTATPROPSTG **) &pEnumSTATPROPSTG), == S_OK)) { TestEnum(pEnumSTATPROPSTG, _T("EnumSTATPROPSTG")); }
// test invalid cases
LOG_HR(pProp->Enum(0), != S_OK); }
//////////////////////////////////////////////////////////////////////////
//
//
//
#endif //DEFINE_TEMPLATES
|