/*++ 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 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 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 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 pProp(pItemData->pWiaItem); CComPtr 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 pStatPropStg(ulNumProps); ULONG celtFetched = -1; CHECK_HR(pEnumSTATPROPSTG->Next(ulNumProps, pStatPropStg, &celtFetched)); // CCppMem 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 pulAccessRights(ulNumProps); CCppMem pvarValidValues(ulNumProps); if (LOG_HR(pProp->GetPropertyAttributes(ulNumProps, pPropSpec, pulAccessRights, pvarValidValues), == S_OK)) { CCppMem 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 pProp(pItemData->pWiaItem); CHECK(pProp != 0); CComPtr 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 pProp(pItemData->pWiaItem); CComPtr 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 pStatPropStg(ulNumProps); ULONG celtFetched = -1; CHECK_HR(pEnumSTATPROPSTG->Next(ulNumProps, pStatPropStg, &celtFetched)); // test legal case CCppMem pPropId(ulNumProps); CCppMem 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 pProp(pItemData->pWiaItem); CHECK(pProp != 0); // test valid cases CComPtr 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