//*************************************************************************** // // TestInfo.CPP // // Module: CDM Provider // // Purpose: Defines the CClassPro class. An object of this class is // created by the class factory for each connection. // // Copyright (c) 2000 Microsoft Corporation // //*************************************************************************** // @@BEGIN_DDKSPLIT // // What is left to do: // // Finish reboot diagnostics - This involves persisting the pending // result in the schema and then trying to query for the actual // results later // // Keep more than 1 historical result instance. This involves // persisting the historical results in the schema and picking them // up from there // @@END_DDKSPLIT #include #ifndef _MT #define _MT #endif #include #include "debug.h" #include "testinfo.h" #include "wbemmisc.h" #include "cimmap.h" #include "reload.h" IWbemServices *pCimServices; IWbemServices *pWdmServices; HRESULT TestInfoInitialize( void ) /*+++ Routine Description: This routine will establishes a connection to the root\wmi and root\cimv2 namespaces in global memory Arguments: Return Value: HRESULT ---*/ { HRESULT hr; WmipAssert(pCimServices == NULL); WmipAssert(pWdmServices == NULL); hr = WmiConnectToWbem(L"root\\cimv2", &pCimServices); if (hr == WBEM_S_NO_ERROR) { hr = WmiConnectToWbem(L"root\\wmi", &pWdmServices); if (hr != WBEM_S_NO_ERROR) { pCimServices->Release(); pCimServices = NULL; } } return(hr); } void TestInfoDeinitialize( void ) /*+++ Routine Description: This routine will disestablish a connection to the root\wmi and root\cimv2 namespaces in global memory Arguments: Return Value: ---*/ { WmipAssert(pCimServices != NULL); WmipAssert(pWdmServices != NULL); pCimServices->Release(); pCimServices = NULL; pWdmServices->Release(); pWdmServices = NULL; } CTestServices::CTestServices() /*+++ Routine Description: Constructor for CTestServices class Arguments: Return Value: ---*/ { WdmTestClassName = NULL; WdmSettingClassName = NULL; WdmSettingListClassName = NULL; WdmResultClassName = NULL; WdmOfflineResultClassName = NULL; CdmTestClassName = NULL; CdmTestRelPath = NULL; CdmResultClassName = NULL; CdmSettingClassName = NULL; CdmTestForMSEClassName = NULL; CdmTestForMSERelPath = NULL; CdmSettingForTestClassName = NULL; CdmSettingForTestRelPath = NULL; CdmResultForMSEClassName = NULL; CdmResultForTestClassName = NULL; CdmTestForSoftwareClassName = NULL; CdmTestForSoftwareRelPath = NULL; CdmTestInPackageClassName = NULL; CdmTestInPackageRelPath = NULL; CdmResultInPackageClassName = NULL; CdmResultInPackageRelPath = NULL; CimClassMappingClassName = NULL; CimRelPaths = NULL; WdmRelPaths = NULL; PnPDeviceIdsX = NULL; WdmInstanceNames = NULL; CdmSettingsList = NULL; CdmResultsList = NULL; Next = NULL; Prev = NULL; } CTestServices::~CTestServices() /*+++ Routine Description: Destructor for CTestServices class Arguments: Return Value: ---*/ { int i; if (WdmTestClassName != NULL) { SysFreeString(WdmTestClassName); } if (WdmSettingClassName != NULL) { SysFreeString(WdmSettingClassName); } if (WdmResultClassName != NULL) { SysFreeString(WdmResultClassName); } if (WdmOfflineResultClassName != NULL) { SysFreeString(WdmOfflineResultClassName); } if (WdmSettingListClassName != NULL) { SysFreeString(WdmSettingListClassName); } if (CdmTestClassName != NULL) { SysFreeString(CdmTestClassName); } if (CdmTestRelPath != NULL) { SysFreeString(CdmTestRelPath); } if (CdmResultClassName != NULL) { SysFreeString(CdmResultClassName); } if (CdmSettingClassName != NULL) { SysFreeString(CdmSettingClassName); } if (CdmTestForMSEClassName != NULL) { SysFreeString(CdmTestForMSEClassName); } FreeTheBSTRArray(CdmTestForMSERelPath, RelPathCount); if (CdmSettingForTestClassName != NULL) { SysFreeString(CdmSettingForTestClassName); } if (CdmSettingForTestRelPath != NULL) { for (i = 0; i < RelPathCount; i++) { delete CdmSettingForTestRelPath[i]; } WmipFree(CdmSettingForTestRelPath); } if (CdmResultForMSEClassName != NULL) { SysFreeString(CdmResultForMSEClassName); } if (CdmResultForTestClassName != NULL) { SysFreeString(CdmResultForTestClassName); } if (CdmTestForSoftwareClassName != NULL) { SysFreeString(CdmTestForSoftwareClassName); } if (CdmTestForSoftwareRelPath != NULL) { SysFreeString(CdmTestForSoftwareRelPath); } if (CdmTestInPackageClassName != NULL) { SysFreeString(CdmTestInPackageClassName); } if (CdmTestInPackageRelPath != NULL) { SysFreeString(CdmTestInPackageRelPath); } if (CdmResultInPackageClassName != NULL) { SysFreeString(CdmResultInPackageClassName); } if (CdmResultInPackageRelPath != NULL) { SysFreeString(CdmResultInPackageRelPath); } if (CimClassMappingClassName != NULL) { SysFreeString(CimClassMappingClassName); } FreeTheBSTRArray(CimRelPaths, RelPathCount); FreeTheBSTRArray(WdmRelPaths, RelPathCount); FreeTheBSTRArray(WdmInstanceNames, RelPathCount); FreeTheBSTRArray(PnPDeviceIdsX, RelPathCount); if (CdmSettingsList != NULL) { for (i = 0; i < RelPathCount; i++) { delete CdmSettingsList[i]; } WmipFree(CdmSettingsList); } if (CdmResultsList != NULL) { for (i = 0; i < RelPathCount; i++) { delete &CdmResultsList[i]; } } } BOOLEAN ClassIsCdmBaseClass( BSTR ClassName, BOOLEAN *IsTestClass ) /*+++ Routine Description: This routine determines if the class name is a CDM base class name Arguments: ClassName is the name of the class *IsTestClass returns TRUE if the class name is CIM_DiagnosticTest Return Value: TRUE if class is a CDM base class else FALSE ---*/ { WmipAssert(ClassName != NULL); WmipAssert(IsTestClass != NULL); if (_wcsicmp(ClassName, L"CIM_DiagnosticTest") == 0) { *IsTestClass = TRUE; return(TRUE); } if ((_wcsicmp(ClassName, L"CIM_DiagnosticResult") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticSetting") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticResultForMSE") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticResultForTest") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticTestForMSE") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticTestSoftware") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticTestInPackage") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticResultInPackage") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticResultForMSE") == 0) || (_wcsicmp(ClassName, L"CIM_DiagnosticSettingForTest") == 0)) { *IsTestClass = FALSE; return(TRUE); } return(FALSE); } HRESULT CTestServices::GetCdmClassNamesFromOne( PWCHAR CdmClass ) /*+++ Routine Description: This routine obtains the names of all of the CDM classes from the name of a single CDM class Arguments: CdmClass is the name of the CDM class Return Value: HRESULT ---*/ { IWbemServices * pCdmServices = GetCdmServices(); VARIANT v, vClass, vSuper; HRESULT hr, hrDontCare; BOOLEAN IsTestClass; BSTR SuperClass; BSTR CdmTestClass; // // First thing is that we need to do is figure out what kind of // class we have been handed. If it is a CIM_DiagnosticTest derived // class then we can proceed to obtain all of the other class names // via qualifiers. If not then we have to link back from the class // we have to the CIM_DiagnosticTest derived class via the // CdmDiagTest qualifier. // // // Get a class object for Cdm class passed and then check the // __SUPERCLASS property to see which CDM class it is derived from. // SuperClass = SysAllocString(CdmClass); if (SuperClass == NULL) { return(WBEM_E_OUT_OF_MEMORY); } v.vt = VT_BSTR; v.bstrVal = SuperClass; do { hr = WmiGetPropertyByName(pCdmServices, v.bstrVal, L"__SuperClass", CIM_STRING, &vSuper); if (hr == WBEM_S_NO_ERROR) { #ifdef VERBOSE_DEBUG WmipDebugPrint(("CDMPROV: Class %ws has superclass of %ws\n", SuperClass, vSuper.bstrVal)); #endif if (_wcsicmp(v.bstrVal, vSuper.bstrVal) == 0) { // // When the superclass is the same as the base // class then we are at the top of the class tree // and so this class must not be in the CDM // heirarchy. In this case the cdm provider cannot // support it. // hr = WBEM_E_NOT_FOUND; VariantClear(&vSuper); } else if (ClassIsCdmBaseClass(vSuper.bstrVal, &IsTestClass)) { // // We have found a CDM base class // if (! IsTestClass) { // // The CDM base class was not the test class so // lookup the CdmDiagTest qualifier to find it // PWCHAR Name = L"CdmDiagTest"; VARTYPE VarType = VT_BSTR; hr = WmiGetQualifierListByName(pCdmServices, CdmClass, NULL, 1, &Name, &VarType, &vClass); if (hr == WBEM_S_NO_ERROR) { CdmTestClass = vClass.bstrVal; #ifdef VERBOSE_DEBUG WmipDebugPrint(("CDMPROV: Class %ws has a CdmDiagTestClass %ws\n", CdmClass, CdmTestClass)); #endif } } else { CdmTestClass = SysAllocString(CdmClass); if (CdmTestClass == NULL) { hr = WBEM_E_OUT_OF_MEMORY; } #ifdef VERBOSE_DEBUG WmipDebugPrint(("CDMPROV: Class %ws is already CdmDiagTestClass\n", CdmClass)); #endif } VariantClear(&vSuper); } else { // // This is a more basic class, but is not the CDM base // class, so we need to continue up the derivation // chain // } } VariantClear(&v); v = vSuper; } while ((CdmTestClass == NULL) && (hr == WBEM_S_NO_ERROR)); if (hr == WBEM_S_NO_ERROR) { PWCHAR Names[11]; VARTYPE VarType[11]; VARIANT Values[11]; // // Now that we know the CDM Diagnostic test class name we can // go and discover the rest of the CDM class names via // the appropriate qualifiers on the Cdm Test class. // Names[0] = L"CimClassMapping"; VarType[0] = VT_BSTR; VariantInit(&Values[0]); Names[1] = L"CdmDiagResult"; VarType[1] = VT_BSTR; VariantInit(&Values[1]); Names[2] = L"CdmDiagSetting"; VarType[2] = VT_BSTR; VariantInit(&Values[2]); Names[3] = L"CdmDiagTestForMSE"; VarType[3] = VT_BSTR; VariantInit(&Values[3]); Names[4] = L"CdmDiagResultForMSE"; VarType[4] = VT_BSTR; VariantInit(&Values[4]); Names[5] = L"CdmDiagResultForTest"; VarType[5] = VT_BSTR; VariantInit(&Values[5]); Names[6] = L"CdmDiagTestSoftware"; VarType[6] = VT_BSTR; VariantInit(&Values[6]); Names[7] = L"CdmDiagTestInPackage"; VarType[7] = VT_BSTR; VariantInit(&Values[7]); Names[8] = L"CdmDiagResultInPackage"; VarType[8] = VT_BSTR; VariantInit(&Values[8]); Names[9] = L"CdmDiagSettingForTest"; VarType[9] = VT_BSTR; VariantInit(&Values[9]); Names[10] = L"WdmDiagTest"; VarType[10] = VT_BSTR; VariantInit(&Values[10]); hr = WmiGetQualifierListByName(pCdmServices, CdmTestClass, NULL, 11, Names, VarType, Values); if (hr == WBEM_S_NO_ERROR) { // // Remember the class names // CimClassMappingClassName = Values[0].bstrVal; CdmResultClassName = Values[1].bstrVal; CdmSettingClassName = Values[2].bstrVal; CdmTestForMSEClassName = Values[3].bstrVal; CdmResultForMSEClassName = Values[4].bstrVal; CdmResultForTestClassName = Values[5].bstrVal; CdmTestForSoftwareClassName = Values[6].bstrVal; CdmTestInPackageClassName = Values[7].bstrVal; CdmResultInPackageClassName = Values[8].bstrVal; CdmSettingForTestClassName = Values[9].bstrVal; WdmTestClassName = Values[10].bstrVal; // // Now that we have got all of the Cdm class names we need // to get the WdmDiagResult, WdmDiagSetting and // WdmDiagSettingList classes // Names[0] = L"WdmDiagResult"; VariantInit(&Values[0]); hr = WmiGetQualifierListByName(pCdmServices, CdmResultClassName, NULL, 1, Names, VarType, Values); if (hr == WBEM_S_NO_ERROR) { WdmResultClassName = Values[0].bstrVal; // // See if this is an offline diagnostic class // Names[0] = L"WdmDiagOfflineResult"; VariantInit(&Values[0]); hrDontCare = WmiGetQualifierListByName(pCdmServices, CdmResultClassName, NULL, 1, Names, VarType, Values); if (hrDontCare == WBEM_S_NO_ERROR) { WdmOfflineResultClassName = Values[0].bstrVal; } Names[0] = L"WdmDiagSetting"; VariantInit(&Values[0]); hr = WmiGetQualifierListByName(pCdmServices, CdmSettingClassName, NULL, 1, Names, VarType, Values); if (hr == WBEM_S_NO_ERROR) { WdmSettingClassName = Values[0].bstrVal; Names[0] = L"WdmDiagSettingList"; VariantInit(&Values[0]); hr = WmiGetQualifierListByName(pCdmServices, CdmSettingClassName, NULL, 1, Names, VarType, Values); if (hr == WBEM_S_NO_ERROR) { // // Whew, we got all of our class names // successfully. Setup the CdmTestClassName which // denotes that we are all setup properly // WdmSettingListClassName = Values[0].bstrVal; CdmTestClassName = CdmTestClass; } } } } } return(hr); } HRESULT CTestServices::BuildResultRelPaths( IN int RelPathIndex, IN BSTR ExecutionId, OUT BSTR *ResultRelPath, OUT BSTR *ResultForMSERelPath, OUT BSTR *ResultForTestRelPath ) /*+++ Routine Description: This routine will create the string names for the CDM Result relative paths for a specific index. These are for the classes CIM_DiagnosticResult CIM_DiagnosticResultForMSE CIM_DiagnosticResultForTest Arguments: RelPathIndex is the index into the list of result objects ExecutionId is the unique id used for the execution ResultRelPath returns with the result relpath ResultForMSERelPath returns with the ResultForMSE association relpath ResultForTestRelPath returns with the ResultForTest association relpath Return Value: HRESULT ---*/ { PWCHAR RelPath; HRESULT hr; ULONG AllocSize; WCHAR s1[2*MAX_PATH]; WCHAR s2[2*MAX_PATH]; RelPath = (PWCHAR)WmipAlloc(4096); if (RelPath != NULL) { // // Create the relpaths for the result classes and associations // wsprintfW(RelPath, L"%ws.DiagnosticCreationClassName=\"%ws\",DiagnosticName=\"%ws\",ExecutionID=\"%ws\"", CdmResultClassName, AddSlashesToStringExW(s1, WdmRelPaths[RelPathIndex]), CdmTestClassName, ExecutionId); *ResultRelPath = SysAllocString(RelPath); if (*ResultRelPath != NULL) { wsprintfW(RelPath, L"%ws.Result=\"%ws\",SystemElement=\"%ws\"", CdmResultForMSEClassName, AddSlashesToStringExW(s1, *ResultRelPath), AddSlashesToStringExW(s2, CimRelPaths[RelPathIndex])); *ResultForMSERelPath = SysAllocString(RelPath); wsprintfW(RelPath, L"%ws.DiagnosticResult=\"%ws\",DiagnosticTest=\"%ws\"", CdmResultForTestClassName, AddSlashesToStringExW(s1, *ResultRelPath), AddSlashesToStringExW(s2, CdmTestRelPath)); *ResultForTestRelPath = SysAllocString(RelPath); if ((*ResultForMSERelPath == NULL) || (*ResultForTestRelPath == NULL)) { SysFreeString(*ResultRelPath); if (*ResultForMSERelPath != NULL) { SysFreeString(*ResultForMSERelPath); } if (*ResultForTestRelPath != NULL) { SysFreeString(*ResultForTestRelPath); } hr = WBEM_E_OUT_OF_MEMORY; } else { hr = WBEM_S_NO_ERROR; } } else { hr = WBEM_E_OUT_OF_MEMORY; } WmipFree(RelPath); } else { hr = WBEM_E_OUT_OF_MEMORY; } return(hr); } HRESULT CTestServices::BuildTestRelPaths( void ) /*+++ Routine Description: This routine will create the string names for the CDM Test relative paths for all index These are for the following classes: CIM_DiagnosticTest, CIM_DiagnosticTestForMSE Arguments: Return Value: HRESULT ---*/ { PWCHAR RelPath; int i; HRESULT hr; WCHAR s1[MAX_PATH]; WCHAR s2[MAX_PATH]; ULONG AllocSize; RelPath = (PWCHAR)WmipAlloc(4096); if (RelPath != NULL) { wsprintfW(RelPath, L"%ws.Name=\"%ws\"", CdmTestClassName, CdmTestClassName); CdmTestRelPath = SysAllocString(RelPath); if (CdmTestRelPath != NULL) { AllocSize = RelPathCount * sizeof(BSTR); CdmTestForMSERelPath = (PWCHAR *)WmipAlloc(AllocSize); if (CdmTestForMSERelPath != NULL) { memset(CdmTestForMSERelPath, 0, AllocSize); hr = WBEM_S_NO_ERROR; for (i = 0; (i < RelPathCount) && (hr == WBEM_S_NO_ERROR); i++) { wsprintfW(RelPath, L"%ws.Antecedent=\"%ws\",Dependent=\"%ws\"", CdmTestForMSEClassName, AddSlashesToStringExW(s1, CimRelPaths[i]), AddSlashesToStringExW(s2, CdmTestRelPath)); CdmTestForMSERelPath[i] = SysAllocString(RelPath); if (CdmTestForMSERelPath[i] == NULL) { SysFreeString(CdmTestRelPath); CdmTestRelPath = NULL; FreeTheBSTRArray(CdmTestForMSERelPath, RelPathCount); CdmTestForMSERelPath = NULL; hr = WBEM_E_OUT_OF_MEMORY; } } } else { SysFreeString(CdmTestRelPath); CdmTestRelPath = NULL; hr = WBEM_E_OUT_OF_MEMORY; } } else { hr = WBEM_E_OUT_OF_MEMORY; } WmipFree(RelPath); } else { hr = WBEM_E_OUT_OF_MEMORY; } return(hr); } HRESULT CTestServices::BuildSettingForTestRelPath( OUT BSTR *RelPath, IN IWbemClassObject *pCdmSettingInstance ) { WCHAR *Buffer; VARIANT v; WCHAR s[MAX_PATH]; HRESULT hr; WmipAssert(RelPath != NULL); WmipAssert(pCdmSettingInstance != NULL); WmipAssert(IsThisInitialized()); Buffer = (WCHAR *)WmipAlloc(4096); if (Buffer != NULL) { hr = WmiGetProperty(pCdmSettingInstance, L"__RELPATH", CIM_REFERENCE, &v); if (hr == WBEM_S_NO_ERROR) { wsprintfW(Buffer, L"%ws.Element=\"%ws.Name=\\\"%ws\\\"\",Setting=\"%ws\"", CdmSettingForTestClassName, CdmTestClassName, CdmTestClassName, AddSlashesToStringExW(s, v.bstrVal)); VariantClear(&v); *RelPath = SysAllocString(Buffer); if (*RelPath != NULL) { hr = WBEM_S_NO_ERROR; } else { hr = WBEM_E_OUT_OF_MEMORY; } } WmipFree(Buffer); } else { hr = WBEM_E_OUT_OF_MEMORY; } return(hr); } HRESULT CTestServices::ParseSettingList( VARIANT *SettingList, CWbemObjectList *CdmSettings, CBstrArray *CdmSettingForTestRelPath, int RelPathIndex ) /*+++ Routine Description: This routine will obtain all of the settings for a particular test and store them into a settings list object Arguments: SettingList points at a variant continaing an array of embedded WDM setting objects CdmSettings points at a WbemObjectList class CdmSettingForTestRelPath has the relpaths for the cdm settings for test classes RelPathIndex is the relpath index associated with the settings Return Value: HRESULT ---*/ { HRESULT hr; IWbemClassObject *pWdmSettingInstance; IWbemClassObject *pCdmSettingInstance; LONG Index, UBound, LBound, NumberElements; LONG i; IUnknown *punk; BSTR s; WCHAR SettingId[MAX_PATH]; VARIANT v; WmipAssert(SettingList != NULL); WmipAssert(CdmSettingForTestRelPath != NULL); WmipAssert(SettingList->vt == (CIM_OBJECT | CIM_FLAG_ARRAY)); WmipAssert(CdmSettings != NULL); hr = WmiGetArraySize(SettingList->parray, &LBound, &UBound, &NumberElements); if (hr == WBEM_S_NO_ERROR) { hr = CdmSettingForTestRelPath->Initialize(NumberElements); if (hr == WBEM_S_NO_ERROR) { hr = CdmSettings->Initialize(NumberElements); for (i = 0, Index = LBound; (i < NumberElements) && (hr == WBEM_S_NO_ERROR); i++, Index++) { hr = SafeArrayGetElement(SettingList->parray, &Index, &punk); if (hr == WBEM_S_NO_ERROR) { hr = punk->QueryInterface(IID_IWbemClassObject, (PVOID *)&pWdmSettingInstance); if (hr == WBEM_S_NO_ERROR) { hr = CreateInst(GetCdmServices(), &pCdmSettingInstance, CdmSettingClassName, NULL); if (hr == WBEM_S_NO_ERROR) { hr = CopyBetweenCdmAndWdmClasses(pCdmSettingInstance, pWdmSettingInstance, TRUE); if (hr == WBEM_S_NO_ERROR) { // // Set CdmSetting.SettingId to a unique // setting id // wsprintfW(SettingId, L"%ws_%d_%d", CdmTestClassName, RelPathIndex, i); s = SysAllocString(SettingId); if (s != NULL) { VariantInit(&v); v.vt = VT_BSTR; v.bstrVal = s; hr = WmiSetProperty(pCdmSettingInstance, L"SettingId", &v); VariantClear(&v); if (hr == WBEM_S_NO_ERROR) { hr = BuildSettingForTestRelPath(&s, pCdmSettingInstance); if (hr == WBEM_S_NO_ERROR) { CdmSettingForTestRelPath->Set(i, s); CdmSettings->Set(i, pCdmSettingInstance, TRUE); } } } else { hr = WBEM_E_OUT_OF_MEMORY; } } if (hr != WBEM_S_NO_ERROR) { pCdmSettingInstance->Release(); } } pWdmSettingInstance->Release(); } punk->Release(); } } } } return(hr); } HRESULT CTestServices::GetCdmTestSettings( void ) /*+++ Routine Description: This routine will obtain all of the CDM settings available for all instnaces of the test Arguments: Return Value: HRESULT ---*/ { WCHAR Query[MAX_PATH * 2]; WCHAR s[MAX_PATH]; ULONG AllocSize; BSTR sWQL, sQuery; IEnumWbemClassObject *pWdmEnumInstances; IWbemClassObject *pWdmInstance; int i; ULONG Count; HRESULT hr; VARIANT SettingList; // // We need to get all of the settings exposed by the WDM class and // then convert them to Cdm classes. // sWQL = SysAllocString(L"WQL"); if (sWQL != NULL) { AllocSize = RelPathCount * sizeof(CWbemObjectList *); CdmSettingsList = (CWbemObjectList **)WmipAlloc(AllocSize); if (CdmSettingsList != NULL) { memset(CdmSettingsList, 0, AllocSize); AllocSize = RelPathCount * sizeof(CBstrArray *); CdmSettingForTestRelPath = (CBstrArray **)WmipAlloc(AllocSize); if (CdmSettingForTestRelPath != NULL) { memset(CdmSettingForTestRelPath, 0, AllocSize); hr = WBEM_S_NO_ERROR; for (i = 0; (i < RelPathCount) && (hr == WBEM_S_NO_ERROR); i++) { CdmSettingsList[i] = new CWbemObjectList(); CdmSettingForTestRelPath[i] = new CBstrArray; wsprintfW(Query, L"select * from %ws where InstanceName = \"%ws\"", WdmSettingListClassName, AddSlashesToStringW(s, WdmInstanceNames[i])); sQuery = SysAllocString(Query); if (sQuery != NULL) { hr = pWdmServices->ExecQuery(sWQL, sQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_ENSURE_LOCATABLE, NULL, &pWdmEnumInstances); if (hr == WBEM_S_NO_ERROR) { hr = pWdmEnumInstances->Next(WBEM_INFINITE, 1, &pWdmInstance, &Count); if ((hr == WBEM_S_NO_ERROR) && (Count == 1)) { hr = WmiGetProperty(pWdmInstance, L"SettingList", CIM_FLAG_ARRAY | CIM_OBJECT, &SettingList); if (hr == WBEM_S_NO_ERROR) { if (SettingList.vt & VT_ARRAY) { hr = ParseSettingList(&SettingList, CdmSettingsList[i], CdmSettingForTestRelPath[i], i); } else { hr = WBEM_E_FAILED; } VariantClear(&SettingList); } pWdmInstance->Release(); } pWdmEnumInstances->Release(); } else { // // There must not be any predefined settings // hr = CdmSettingsList[i]->Initialize(0); } SysFreeString(sQuery); } else { hr = WBEM_E_OUT_OF_MEMORY; } } } else { hr = WBEM_E_OUT_OF_MEMORY; } } else { hr = WBEM_E_OUT_OF_MEMORY; } SysFreeString(sWQL); } else { hr = WBEM_E_OUT_OF_MEMORY; } return(hr); } HRESULT CTestServices::InitializeCdmClasses( PWCHAR CdmClass ) /*+++ Routine Description: This routine will setup this class and initialize everything so that the provider can interact with the CDM and WDM classes Arguments: CdmClass is the name of the CDM class Return Value: HRESULT ---*/ { HRESULT hr, hrDontCare; ULONG AllocSize; int i; WmipAssert(CdmClass != NULL); WmipAssert(! IsThisInitialized()); // // We assume that this method will always be the first one called // by the class provider // if ((pCimServices == NULL) && (pWdmServices == NULL)) { hr = TestInfoInitialize(); if (hr != WBEM_S_NO_ERROR) { return(hr); } } // // We are given a random CDM class name - it could be a test, // setting, association, etc so we need to go from that class name // and obtain all of the class names related to this diagnostic // hr = GetCdmClassNamesFromOne(CdmClass); if (hr == WBEM_S_NO_ERROR) { // // Use worker function to determine which // Wdm relpaths map to which Cdm relpaths // hr = MapWdmClassToCimClass(pWdmServices, pCimServices, WdmTestClassName, CimClassMappingClassName, &PnPDeviceIdsX, &WdmInstanceNames, &WdmRelPaths, &CimRelPaths, &RelPathCount); if (hr == WBEM_S_NO_ERROR) { // // Obtain all of the possible settings for this test // hr = GetCdmTestSettings(); if (hr == WBEM_S_NO_ERROR) { // // Initialize the results object lists // CdmResultsList = new CResultList[RelPathCount]; // // Build the test class instance relpaths // hr = BuildTestRelPaths(); // @@BEGIN_DDKSPLIT #ifdef REBOOT_DIAGNOSTICS if (hr == WBEM_S_NO_ERROR) { hrDontCare = GatherRebootResults(); } #else // // Reboot diagnostics are not yet supported // #endif // @@END_DDKSPLIT } } } return(hr); } IWbemServices *CTestServices::GetWdmServices( void ) /*+++ Routine Description: Accessor for the WDM namespace IWbemServices Arguments: Return Value: IWbemServices ---*/ { WmipAssert(pWdmServices != NULL); return(pWdmServices); } IWbemServices *CTestServices::GetCdmServices( void ) /*+++ Routine Description: Accessor for the CIM namespace IWbemServices Arguments: Return Value: IWbemServices ---*/ { WmipAssert(pCimServices != NULL); return(pCimServices); } HRESULT CTestServices::WdmPropertyToCdmProperty( IN IWbemClassObject *pCdmClassInstance, IN IWbemClassObject *pWdmClassInstance, IN BSTR PropertyName, IN OUT VARIANT *PropertyValue, IN CIMTYPE CdmCimType, IN CIMTYPE WdmCimType ) /*+++ Routine Description: This routine will convert a property in a Wdm class into the form required for the property in the Cdm class. Arguments: pCdmClassInstance is the instnace of the Cdm class that will get the property value pWdmClassInstance is the instance of the Wdm class that has the property value PropertyName is the name of the property in the Wdm and Cdm classes PropertyValue on entry has the value of the property in the Wdm instance and on return has the value to set in the Cdm instance CdmCimType is the property type for the property in the Cdm instance WdmCimType is the property type for the property in the Wdm instance Return Value: HRESULT ---*/ { HRESULT hr; BSTR Mapped; VARIANT vClassName; CIMTYPE BaseWdmCimType, BaseCdmCimType; CIMTYPE WdmCimArray, CdmCimArray; LONG i; WmipAssert(pCdmClassInstance != NULL); WmipAssert(pWdmClassInstance != NULL); WmipAssert(PropertyName != NULL); WmipAssert(PropertyValue != NULL); WmipAssert(IsThisInitialized()); // // Rules for converting Wdm Classes into Cdm Classes // Wdm Class Type Cdm Class Type Conversion Done // enumeration string Build string from enum // BaseWdmCimType = WdmCimType & ~CIM_FLAG_ARRAY; BaseCdmCimType = CdmCimType & ~CIM_FLAG_ARRAY; WdmCimArray = WdmCimType & CIM_FLAG_ARRAY; CdmCimArray = CdmCimType & CIM_FLAG_ARRAY; if (((BaseWdmCimType == CIM_UINT32) || (BaseWdmCimType == CIM_UINT16) || (BaseWdmCimType == CIM_UINT8)) && (BaseCdmCimType == CIM_STRING) && (WdmCimArray == CdmCimArray) && (PropertyValue->vt != VT_NULL)) { hr = WmiGetProperty(pWdmClassInstance, L"__Class", CIM_STRING, &vClassName); if (hr == WBEM_S_NO_ERROR) { if (WdmCimArray) { SAFEARRAYBOUND Bounds; SAFEARRAY *Array; ULONG Value; LONG UBound, LBound, Elements, Index; // // We have an array of enumeration types to convert into an // array of corresponding strings // hr = WmiGetArraySize(PropertyValue->parray, &LBound, &UBound, &Elements); if (hr == WBEM_S_NO_ERROR) { Bounds.lLbound = LBound; Bounds.cElements = Elements; Array = SafeArrayCreate(VT_BSTR, 1, &Bounds); if (Array != NULL) { for (i = 0; (i < Elements) && (hr == WBEM_S_NO_ERROR); i++) { Index = i + LBound; hr = SafeArrayGetElement(PropertyValue->parray, &Index, &Value); if (hr == WBEM_S_NO_ERROR) { hr = LookupValueMap(GetWdmServices(), vClassName.bstrVal, PropertyName, Value, &Mapped); if (hr == WBEM_S_NO_ERROR) { hr = SafeArrayPutElement(Array, &Index, Mapped); } } } if (hr == WBEM_S_NO_ERROR) { VariantClear(PropertyValue); PropertyValue->vt = VT_BSTR | VT_ARRAY; PropertyValue->parray = Array; } else { SafeArrayDestroy(Array); } } else { hr = WBEM_E_OUT_OF_MEMORY; } } } else { // // We need to convert a scalar enumeration type into the // corresponding string. First we need to get the Wdm class // object and from that get the Values and ValueMap qualifiers // to determine the string we need to place into the cim class // hr = LookupValueMap(GetWdmServices(), vClassName.bstrVal, PropertyName, PropertyValue->uiVal, &Mapped); if (hr == WBEM_S_NO_ERROR) { VariantClear(PropertyValue); PropertyValue->vt = VT_BSTR; PropertyValue->bstrVal = Mapped; } } VariantClear(&vClassName); } } else { // // No conversion needs to occur // hr = WBEM_S_NO_ERROR; } return(hr); } HRESULT CTestServices::CdmPropertyToWdmProperty( IN IWbemClassObject *pWdmClassInstance, IN IWbemClassObject *pCdmClassInstance, IN BSTR PropertyName, IN OUT VARIANT *PropertyValue, IN CIMTYPE WdmCimType, IN CIMTYPE CdmCimType ) /*+++ Routine Description: This routine will convert a property in a Cdm class into the form required for the property in the Wdm class. Arguments: pWdmClassInstance is the instance of the Wdm class that has the property value pCdmClassInstance is the instnace of the Cdm class that will get the property value PropertyName is the name of the property in the Wdm and Cdm classes PropertyValue on entry has the value of the property in the Wdm instance and on return has the value to set in the Cdm instance WdmCimType is the property type for the property in the Wdm instance CdmCimType is the property type for the property in the Cdm instance Return Value: HRESULT ---*/ { WmipAssert(pCdmClassInstance != NULL); WmipAssert(pWdmClassInstance != NULL); WmipAssert(PropertyName != NULL); WmipAssert(PropertyValue != NULL); WmipAssert(IsThisInitialized()); // // Rules for converting Wdm Classes into Cdm Classes // Wdm Class Type Cdm Class Type Conversion Done // // // There are no conversion requirements when converting from Cdm to // Wdm instances // return(WBEM_S_NO_ERROR); } HRESULT CTestServices::CopyBetweenCdmAndWdmClasses( IN IWbemClassObject *pDestinationInstance, IN IWbemClassObject *pSourceInstance, IN BOOLEAN WdmToCdm ) /*+++ Routine Description: This routine will do the work to copy and convert all properties in an instance of a Wdm or Cdm class to an instance of a Cdm or Wdm class. Note that properties from one instance are only copied to properties of another instance when the property names are identical. No assumption is ever made on the name of the properties. The only info used to determine how to convert a property is based upon the source and destination cim type. Arguments: pDestinationInstance is the class instance that the properties will be copied into pSourceInstance is the class instance that the properties will be copied from WdmToCdm is TRUE if copying from Wdm to Cdm, else FALSE Return Value: HRESULT ---*/ { HRESULT hr; VARIANT PropertyValue; BSTR PropertyName; CIMTYPE SourceCimType, DestCimType; HRESULT hrDontCare; WmipAssert(pDestinationInstance != NULL); WmipAssert(pSourceInstance != NULL); WmipAssert(IsThisInitialized()); // // Now we need to move over all of the properties from the source // class into the destination class. Note that some properties need // some special effort such as OtherCharacteristics which needs // to be converted from an enumeration value (in wdm) to a // string (in CDM). // // Our strategy is to enumerate all of the proeprties in the // source class and then look for a property with the same name // and type in the destination class. If so we just copy over the // value. If the data type is different we need to do some // conversion. // hr = pSourceInstance->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY); if (hr == WBEM_S_NO_ERROR) { do { // // Get a property from the source class // hr = pSourceInstance->Next(0, &PropertyName, &PropertyValue, &SourceCimType, NULL); if (hr == WBEM_S_NO_ERROR) { // // Try to get a property with the same name from the // dest class. If the identically named property does // not exist in the destination class then it is ignored // hrDontCare = pDestinationInstance->Get(PropertyName, 0, NULL, &DestCimType, NULL); if (hrDontCare == WBEM_S_NO_ERROR) { if (WdmToCdm) { hr = WdmPropertyToCdmProperty(pDestinationInstance, pSourceInstance, PropertyName, &PropertyValue, DestCimType, SourceCimType); } else { hr = CdmPropertyToWdmProperty(pDestinationInstance, pSourceInstance, PropertyName, &PropertyValue, DestCimType, SourceCimType); } if (hr == WBEM_S_NO_ERROR) { // // Try to place the transformed property into the // destination class. // hr = pDestinationInstance->Put(PropertyName, 0, &PropertyValue, 0); } } SysFreeString(PropertyName); VariantClear(&PropertyValue); } else if (hr == WBEM_S_NO_MORE_DATA) { // // This signifies the end of the enumerations // hr = WBEM_S_NO_ERROR; break; } } while (hr == WBEM_S_NO_ERROR); pSourceInstance->EndEnumeration(); } return(hr); } HRESULT CTestServices::QueryWdmTest( OUT IWbemClassObject *pCdmTest, IN int RelPathIndex ) /*+++ Routine Description: This routine will query the Wdm test class instance and copy the results into the Cdm Test class instance Arguments: pCdmTest points at the Cdm Test class instance RelPathIndex Return Value: HRESULT ---*/ { IWbemClassObject *pWdmTest; HRESULT hr; WmipAssert(pCdmTest != NULL); WmipAssert(IsThisInitialized()); hr = ConnectToWdmClass(RelPathIndex, &pWdmTest); if (hr == WBEM_S_NO_ERROR) { hr = CopyBetweenCdmAndWdmClasses(pCdmTest, pWdmTest, TRUE); pWdmTest->Release(); } return(hr); } #define OBJECTCOLONSIZE (((sizeof(L"object:")/sizeof(WCHAR)))-1) HRESULT CTestServices::FillTestInParams( OUT IWbemClassObject *pInParamInstance, IN IWbemClassObject *pCdmSettings, IN BSTR ExecutionID ) { HRESULT hr; IWbemServices *pWdmServices; VARIANT v; VARIANT PropertyValues[2]; PWCHAR PropertyNames[2]; PWCHAR ClassName; IWbemClassObject *pRunTestIn; IWbemClassObject *pWdmSettingsInstance; IWbemQualifierSet *pQualSet; WmipAssert(pInParamInstance != NULL); pWdmServices = GetWdmServices(); pRunTestIn = NULL; // // Get the name of the embedded class for the RunTestIn input // parameter. This should be an embedded class that contains all of // the input parameters. We get this from the __CIMTYPE qualifier // on the RunTestIn property. // // We need to do this since the wmiprov can't // handle anything with an embedded object as an input parameter to // a method // hr = pInParamInstance->GetPropertyQualifierSet(L"RunTestIn", &pQualSet); if (hr == WBEM_S_NO_ERROR) { hr = WmiGetQualifier(pQualSet, L"CIMTYPE", VT_BSTR, &v); if (hr == WBEM_S_NO_ERROR) { if (_wcsnicmp(v.bstrVal, L"object:", OBJECTCOLONSIZE) == 0) { ClassName = v.bstrVal + OBJECTCOLONSIZE; hr = CreateInst(pWdmServices, &pRunTestIn, ClassName, NULL); if (hr == WBEM_S_NO_ERROR) { hr = CreateInst(pWdmServices, &pWdmSettingsInstance, WdmSettingClassName, NULL); if (hr == WBEM_S_NO_ERROR) { if (pCdmSettings != NULL) { hr = CopyBetweenCdmAndWdmClasses(pWdmSettingsInstance, pCdmSettings, FALSE); } if (hr == WBEM_S_NO_ERROR) { PWCHAR PropertyNames[2]; VARIANT PropertyValues[2]; PropertyNames[0] = L"DiagSettings"; PropertyValues[0].vt = VT_UNKNOWN; PropertyValues[0].punkVal = pWdmSettingsInstance; PropertyNames[1] = L"ExecutionID"; PropertyValues[1].vt = VT_BSTR; PropertyValues[1].bstrVal = ExecutionID; hr = WmiSetPropertyList(pRunTestIn, 2, PropertyNames, PropertyValues); if (hr == WBEM_S_NO_ERROR) { PropertyValues[0].vt = VT_UNKNOWN; PropertyValues[0].punkVal = pRunTestIn; hr = WmiSetProperty(pInParamInstance, L"RunTestIn", &PropertyValues[0]); } } // // We can release here since we know that wbem // took a ref count when we set the property // pWdmSettingsInstance->Release(); } } } VariantClear(&v); } pQualSet->Release(); } if ((hr != WBEM_S_NO_ERROR) && (pRunTestIn != NULL)) { pRunTestIn->Release(); } return(hr); } HRESULT CTestServices::GetTestOutParams( IN IWbemClassObject *OutParams, OUT IWbemClassObject *pCdmResult, OUT ULONG *Result ) { HRESULT hr; VARIANT v; IWbemClassObject *pRunTestOut; IWbemClassObject *pWdmResult; WmipAssert(OutParams != NULL); WmipAssert(pCdmResult != NULL); WmipAssert(Result != NULL); hr = WmiGetProperty(OutParams, L"RunTestOut", CIM_OBJECT, &v); if (hr == WBEM_S_NO_ERROR) { hr = v.punkVal->QueryInterface(IID_IWbemClassObject, (PVOID *)&pRunTestOut); VariantClear(&v); if (hr == WBEM_S_NO_ERROR) { hr = WmiGetProperty(pRunTestOut, L"Result", CIM_UINT32, &v); if (hr == WBEM_S_NO_ERROR) { *Result = v.ulVal; VariantClear(&v); hr = WmiGetProperty(pRunTestOut, L"DiagResult", CIM_OBJECT, &v); if (hr == WBEM_S_NO_ERROR) { if (v.vt != VT_NULL) { hr = v.punkVal->QueryInterface(IID_IWbemClassObject, (PVOID *)&pWdmResult); if (hr == WBEM_S_NO_ERROR) { hr = CopyBetweenCdmAndWdmClasses(pCdmResult, pWdmResult, TRUE); pWdmResult->Release(); } } else { hr = WBEM_E_FAILED; } VariantClear(&v); } } pRunTestOut->Release(); } } return(hr); } LONG GlobalExecutionID; BSTR CTestServices::GetExecutionID( void ) { BSTR s; WCHAR x[MAX_PATH]; // // We make up a unique execution ID for this test by using the // current date and time plus a unique counter. The execution id // must be unique. // s = GetCurrentDateTime(); if (s != NULL) { wsprintfW(x, L"%ws*%08x", s, InterlockedIncrement(&GlobalExecutionID)); SysFreeString(s); s = SysAllocString(x); } return(s); } HRESULT CTestServices::ExecuteWdmTest( IN IWbemClassObject *pCdmSettings, OUT IWbemClassObject *pCdmResult, IN int RelPathIndex, OUT ULONG *Result, OUT BSTR *ExecutionID ) /*+++ Routine Description: This routine will execute a test on the Wdm class instance and copy the results back to the Cdm results instance, along with creating all result instance relpaths Arguments: pCdmSettings is a CDM settings instance that is used to create the wdm settings instance that is used to run the test. This may be NULL if default test settings are assumed pCdmResult is a CDM result instance that returns with the results form the test RelPathIndex *Result returns with the return value result from the test *ExecutionId returns with the unique execution id for the test Return Value: HRESULT ---*/ { HRESULT hr; IWbemClassObject *pOutParams; IWbemClassObject *pInParamInstance; BSTR s; WmipAssert(pCdmResult != NULL); WmipAssert(Result != NULL); WmipAssert(ExecutionID != NULL); WmipAssert(IsThisInitialized()); // // Run in the caller's context so that if he is not able to access // the WDM classes, he can't // hr = CoImpersonateClient(); if (hr != WBEM_S_NO_ERROR) { return(hr); } *ExecutionID = GetExecutionID(); if (*ExecutionID != NULL) { s = SysAllocString(L"RunTest"); if (s != NULL) { hr = GetMethodInParamInstance(GetWdmServices(), WdmTestClassName, s, &pInParamInstance); if (hr == WBEM_S_NO_ERROR) { hr = FillTestInParams(pInParamInstance, pCdmSettings, *ExecutionID); if (hr == WBEM_S_NO_ERROR) { hr = pWdmServices->ExecMethod(WdmRelPaths[RelPathIndex], s, 0, NULL, pInParamInstance, &pOutParams, NULL); if (hr == WBEM_S_NO_ERROR) { hr = GetTestOutParams(pOutParams, pCdmResult, Result); if (hr == WBEM_S_NO_ERROR) { // // if the test requires the device being // taken offline then do that now // hr = OfflineDeviceForTest(pCdmResult, *ExecutionID, RelPathIndex); } pOutParams->Release(); } } pInParamInstance->Release(); } SysFreeString(s); } else { hr = WBEM_E_OUT_OF_MEMORY; } } else { hr = WBEM_E_OUT_OF_MEMORY; } CoRevertToSelf(); return(hr); } HRESULT CTestServices::StopWdmTest( IN int RelPathIndex, OUT ULONG *Result, OUT BOOLEAN *TestingStopped ) /*+++ Routine Description: This routine will attempt to stop an executing WDM test Arguments: RelPathIndex *Result returns with the result value *TestingStopped returns TRUE if testing was stopped successfully Return Value: HRESULT ---*/ { HRESULT hr; IWbemClassObject *OutParams; BSTR s; IWbemServices *pWdmServices; VARIANT Value; WmipAssert(Result != NULL); WmipAssert(TestingStopped != NULL); WmipAssert(IsThisInitialized()); // // Run in the caller's context so that if he is not able to access // the WDM classes, he can't // hr = CoImpersonateClient(); if (hr != WBEM_S_NO_ERROR) { return(hr); } pWdmServices = GetWdmServices(); s = SysAllocString(L"DiscontinueTest"); if (s != NULL) { hr = pWdmServices->ExecMethod(WdmRelPaths[RelPathIndex], s, 0, NULL, NULL, &OutParams, NULL); if (hr == WBEM_S_NO_ERROR) { hr = WmiGetProperty(OutParams, L"Result", CIM_UINT32, &Value); if (hr == WBEM_S_NO_ERROR) { *Result = Value.ulVal; VariantClear(&Value); hr = WmiGetProperty(OutParams, L"TestingStopped", CIM_BOOLEAN, &Value); if (hr == WBEM_S_NO_ERROR) { *TestingStopped = (Value.boolVal != 0) ? TRUE : FALSE; VariantClear(&Value); } } OutParams->Release(); } SysFreeString(s); } else { hr = WBEM_E_OUT_OF_MEMORY; } CoRevertToSelf(); return(hr); } HRESULT CTestServices::GetRelPathIndex( BSTR CimRelPath, int *RelPathIndex ) /*+++ Routine Description: This routine will return the RelPathIndex for a specific Cim Relpath Arguments: CimRelPath is the Cim relpath *RelPathIndex returns with the relpath index Return Value: HRESULT ---*/ { int i; WmipAssert(CimRelPath != NULL); WmipAssert(CimRelPaths != NULL); WmipAssert(WdmRelPaths != NULL); WmipAssert(IsThisInitialized()); for (i = 0; i < RelPathCount; i++) { if (_wcsicmp(CimRelPath, CimRelPaths[i]) == 0) { *RelPathIndex = i; return(WBEM_S_NO_ERROR); } } return(WBEM_E_NOT_FOUND); } HRESULT CTestServices::ConnectToWdmClass( IN int RelPathIndex, OUT IWbemClassObject **ppWdmClassObject ) /*+++ Routine Description: This routine will return a IWbemClassObject pointer associated with the RelPath index Arguments: RelPathIndex *ppWdmClassObject returns with an instance for the relpaht Return Value: HRESULT ---*/ { HRESULT hr; WmipAssert(ppWdmClassObject != NULL); WmipAssert(IsThisInitialized()); // // Run in the caller's context so that if he is not able to access // the WDM classes, he can't // hr = CoImpersonateClient(); if (hr == WBEM_S_NO_ERROR) { *ppWdmClassObject = NULL; hr = GetWdmServices()->GetObject(WdmRelPaths[RelPathIndex], WBEM_FLAG_USE_AMENDED_QUALIFIERS, NULL, ppWdmClassObject, NULL); CoRevertToSelf(); } return(hr); } HRESULT CTestServices::FillInCdmResult( OUT IWbemClassObject *pCdmResult, IN IWbemClassObject *pCdmSettings, IN int RelPathIndex, IN BSTR ExecutionID ) /*+++ Routine Description: This routine will fill in the various properties needed in a CDM result instance Arguments: pCdmResult has its properties set pCdmSettings has the settings used to execute the test. This can be NULL RelPathIndex ExecutionID has a unique id used to execute the test Return Value: HRESULT ---*/ { HRESULT hr, hrDontCare; WCHAR s[MAX_PATH]; PWCHAR PropertyNames[12]; VARIANT PropertyValues[12]; ULONG PropertyCount; BSTR ss; WmipAssert(pCdmResult != NULL); WmipAssert(IsThisInitialized()); PropertyNames[0] = L"DiagnosticCreationClassName"; PropertyValues[0].vt = VT_BSTR; PropertyValues[0].bstrVal = WdmRelPaths[RelPathIndex]; PropertyNames[1] = L"DiagnosticName"; PropertyValues[1].vt = VT_BSTR; PropertyValues[1].bstrVal = CdmTestClassName; PropertyNames[2] = L"ExecutionID"; PropertyValues[2].vt = VT_BSTR; PropertyValues[2].bstrVal = ExecutionID; PropertyNames[3] = L"TimeStamp"; PropertyValues[3].vt = VT_BSTR; PropertyValues[3].bstrVal = GetCurrentDateTime(); PropertyNames[4] = L"TestCompletionTime"; PropertyValues[4].vt = VT_BSTR; PropertyValues[4].bstrVal = GetCurrentDateTime(); PropertyNames[5] = L"IsPackage"; PropertyValues[5].vt = VT_BOOL; PropertyValues[5].boolVal = VARIANT_FALSE; // // These properties are copied from pCdmSettings // if (pCdmSettings != NULL) { PropertyNames[6] = L"TestWarningLevel"; hrDontCare = WmiGetProperty(pCdmSettings, L"TestWarningLevel", CIM_UINT16, &PropertyValues[6]); PropertyNames[7] = L"ReportSoftErrors"; hrDontCare = WmiGetProperty(pCdmSettings, L"ReportSoftErrors", CIM_BOOLEAN, &PropertyValues[7]); PropertyNames[8] = L"ReportStatusMessages"; hrDontCare = WmiGetProperty(pCdmSettings, L"ReportStatusMessages", CIM_BOOLEAN, &PropertyValues[8]); PropertyNames[9] = L"HaltOnError"; hrDontCare = WmiGetProperty(pCdmSettings, L"HaltOnError", CIM_BOOLEAN, &PropertyValues[9]); PropertyNames[10] = L"QuickMode"; hrDontCare = WmiGetProperty(pCdmSettings, L"QuickMode", CIM_BOOLEAN, &PropertyValues[10]); PropertyNames[11] = L"PercentOfTestCoverage"; hrDontCare = WmiGetProperty(pCdmSettings, L"PercentOfTestCoverage", CIM_UINT8, &PropertyValues[11]); PropertyCount = 12; } else { PropertyCount = 6; } hr = WmiSetPropertyList(pCdmResult, PropertyCount, PropertyNames, PropertyValues); VariantClear(&PropertyValues[3]); VariantClear(&PropertyValues[4]); return(hr); } HRESULT CTestServices::QueryOfflineResult( OUT IWbemClassObject *pCdmResult, IN BSTR ExecutionID, IN int RelPathIndex ) { WCHAR Query[MAX_PATH * 2]; WCHAR s[MAX_PATH]; BSTR sWQL, sQuery; IEnumWbemClassObject *pWdmEnumInstances; IWbemClassObject *pWdmResult, *pWdmInstance; ULONG Count; HRESULT hr; VARIANT vResult; WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); WmipAssert(WdmOfflineResultClassName != NULL); // // Run in the caller's context so that if he is not able to access // the WDM classes, he can't // hr = CoImpersonateClient(); if (hr != WBEM_S_NO_ERROR) { return(hr); } sWQL = SysAllocString(L"WQL"); if (sWQL != NULL) { wsprintfW(Query, L"select * from %ws where InstanceName = \"%ws\"", WdmOfflineResultClassName, AddSlashesToStringW(s, WdmInstanceNames[RelPathIndex])); sQuery = SysAllocString(Query); if (sQuery != NULL) { hr = GetWdmServices()->ExecQuery(sWQL, sQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_ENSURE_LOCATABLE, NULL, &pWdmEnumInstances); SysFreeString(sQuery); if (hr == WBEM_S_NO_ERROR) { hr = pWdmEnumInstances->Next(WBEM_INFINITE, 1, &pWdmInstance, &Count); if ((hr == WBEM_S_NO_ERROR) && (Count == 1)) { // // Check that the result has the correct execution // ID // hr = WmiGetProperty(pWdmInstance, L"ExecutionID", CIM_STRING, &vResult); if (hr == WBEM_S_NO_ERROR) { if (_wcsicmp(ExecutionID, vResult.bstrVal) != 0) { hr = WBEM_E_FAILED; WmipDebugPrint(("CdmProv: Expected execution ID %ws, but got %ws\n", ExecutionID, vResult.bstrVal)); } VariantClear(&vResult); if (hr == WBEM_S_NO_ERROR) { hr = WmiGetProperty(pWdmInstance, L"TestResult", CIM_OBJECT, &vResult); if (hr == WBEM_S_NO_ERROR) { hr = (vResult.punkVal)->QueryInterface(IID_IWbemClassObject, (PVOID *)&pWdmResult); VariantClear(&vResult); if (hr == WBEM_S_NO_ERROR) { hr = CopyBetweenCdmAndWdmClasses(pCdmResult, pWdmResult, TRUE); pWdmResult->Release(); } } } } pWdmInstance->Release(); } pWdmEnumInstances->Release(); } } SysFreeString(sWQL); } else { hr = WBEM_E_OUT_OF_MEMORY; } CoRevertToSelf(); return(hr); } //@@BEGIN_DDKSPLIT HRESULT CTestServices::GatherRebootResults( void ) /*+++ Routine Description: This routine will check the schema to see if there were any tests that were pending reboot for this DiagnosticTest and if so gather the results of them. When a test is pending reboot, it gets stored as an instance of the static class CDMPROV_Result. The instance contains the Test class name, the result class name, the PnPId of the device stack and the result object. What we do is get all of the saved results for this DiagTest and then see if they apply to any of the PnP Device Ids for the WdmTest. If so then we call the device to retrieve the results and build the result objects. Arguments: Return Value: HRESULT ---*/ { #ifdef REBOOT_DIAGNOSTICS HRESULT hr, hrDontCare; WCHAR Query[2*MAX_PATH]; BSTR sQuery, sWQL; IEnumWbemClassObject *pEnumInstances; IWbemClassObject *pInstance; IWbemClassObject *pCdmResult; int i; ULONG Count; VARIANT vResult, vPnPId, vExecutionID; BSTR ExecutionId; hr = WBEM_S_NO_ERROR; sWQL = SysAllocString(L"WQL"); if (sWQL != NULL) { wsprintfW(Query, L"select * from CdmProv_Result where CdmTestClass = \"%ws\"\n", CdmTestClassName); sQuery = SysAllocString(Query); if (sQuery != NULL) { hrDontCare = GetCdmServices()->ExecQuery(sWQL, sQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_ENSURE_LOCATABLE, NULL, &pEnumInstances); SysFreeString(sQuery); if (hrDontCare == WBEM_S_NO_ERROR) { hr = pEnumInstances->Next(WBEM_INFINITE, 1, &pInstance, &Count); if ((hr == WBEM_S_NO_ERROR) && (Count == 1)) { hr = WmiGetProperty(pInstance, L"PnPId", CIM_STRING, &vPnPId); if (hr == WBEM_S_NO_ERROR) { for (i = 0; i < RelPathCount; i++) { if (_wcsicmp(vPnPId.bstrVal, PnPDeviceIdsX[i]) == 0) { // // We found an instance for this class // and PnPId. get out the stored // result, assign it a new execution // id, and then retrieve the active // result from the driver // PWCHAR PropertyNames[2]; VARIANT Values[2]; CIMTYPE CimTypes[2]; PropertyNames[0] = L"CdmResult"; CimTypes[0] = CIM_OBJECT; PropertyNames[1] = L"ResultTag"; CimTypes[1] = CIM_STRING; hr = WmiGetPropertyList(pInstance, PropertyNames, CimTypes, Values); if (hr == WBEM_S_NO_ERROR) { hr = (Values[0].punkVal)->QueryInterface(IID_IWbemClassObject, (PVOID *)&pCdmResult); if (hr == WBEM_S_NO_ERROR) { hr = WmiGetProperty(pCdmResult, L"ExecutionID", CIM_STRING, &vExecutionId); WmipAssert(vExecutionId.vt != VT_NULL); if (hr == WBEM_S_NO_ERROR) { hr = QueryOfflineResult(pCdmResult, Values[1].bstrVal, i); if (hr == WBEM_S_NO_ERROR) { hr = SetResultObject(pCdmResult, i, vExecutionId.bstrVal); if (hr == WBEM_S_NO_ERROR) { hr = FillInCdmResult(pCdmResult, NULL, i, ExecutionId); if (hr != WBEM_S_NO_ERROR) { hrDontCare = SetResultObject(NULL, i, 0); } } } } } VariantClear(&Values[0]); VariantClear(&Values[1]); } } } VariantClear(&vPnPId); } } pEnumInstances->Release(); } } SysFreeString(sWQL); } return(hr); #else return(WBEM_S_NO_ERROR); #endif } HRESULT CTestServices::PersistResultInSchema( IN IWbemClassObject *pCdmResult, IN BSTR ExecutionID, IN int RelPathIndex ) /*+++ Routine Description: This routine will persist a diagnostic result into the schema Arguments: Return Value: HRESULT ---*/ { HRESULT hr; IWbemClassObject *pPendingTest; IUnknown *punk; WCHAR *PropertyNames[5]; VARIANT PropertyValues[5]; WmipAssert(pCdmResult != NULL); WmipAssert(IsThisInitialized()); hr = CreateInst(GetCdmServices(), &pPendingTest, L"CDMProv_Result", NULL); if (hr == WBEM_S_NO_ERROR) { hr = pCdmResult->QueryInterface(IID_IUnknown, (PVOID *)&punk); if (hr == WBEM_S_NO_ERROR) { PropertyNames[0] = L"PnPId"; PropertyValues[0].vt = VT_BSTR; PropertyValues[0].bstrVal = PnPDeviceIdsX[RelPathIndex]; PropertyNames[1] = L"CdmTestClass"; PropertyValues[1].vt = VT_BSTR; PropertyValues[1].bstrVal = CdmTestClassName; PropertyNames[2] = L"CdmResultClass"; PropertyValues[2].vt = VT_BSTR; PropertyValues[2].bstrVal = CdmResultClassName; PropertyNames[3] = L"CdmResult"; PropertyValues[3].vt = VT_UNKNOWN; PropertyValues[3].punkVal = punk; PropertyNames[4] = L"ExecutionID"; PropertyValues[4].vt = VT_BSTR; PropertyValues[4].bstrVal = ExecutionID; hr = WmiSetPropertyList(pPendingTest, 5, PropertyNames, PropertyValues); if (hr == WBEM_S_NO_ERROR) { hr = GetCdmServices()->PutInstance(pPendingTest, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL); } punk->Release(); } pPendingTest->Release(); } return(hr); } //@@END_DDKSPLIT HRESULT CTestServices::OfflineDeviceForTest( IWbemClassObject *pCdmResult, BSTR ExecutionID, int RelPathIndex ) { HRESULT hr = WBEM_S_NO_ERROR; ULONG Status; VARIANT v; WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); // // First determine if the test is one where it expects to be taken // offline and that the result from the RunTest method indicates // that an offline execution is pending // if (WdmOfflineResultClassName != NULL) { // // The device expects to be taken offline since it had a // WdmOfflineResultClass qualifier on the CIM_DiagnosticResult // class. Now see if the OtherStateDescription property in the // CIM_DiagnosticResult is set to "Offline Pending Execution" // hr = WmiGetProperty(pCdmResult, L"OtherStateDescription", CIM_STRING, &v); if (hr == WBEM_S_NO_ERROR) { if (_wcsicmp(v.bstrVal, L"Offline Pending Execution") == 0) { // // Ok, the test is waiting for the device to be taken // offline. Lets do this now and then when the device // comes back, pickup the results from the // OfflineResultClass // // @@BEGIN_DDKSPLIT //#define FORCE_REBOOT_REQUIRED #ifdef FORCE_REBOOT_REQUIRED Status = ERROR_INVALID_PARAMETER; #else // @@END_DDKSPLIT // // Make sure to use the clients security context to try // to bring the device offline. // hr = CoImpersonateClient(); if (hr == WBEM_S_NO_ERROR) { Status = RestartDevice(PnPDeviceIdsX[RelPathIndex]); CoRevertToSelf(); } // @@BEGIN_DDKSPLIT #endif // @@END_DDKSPLIT if (Status == ERROR_SUCCESS) { hr = QueryOfflineResult(pCdmResult, ExecutionID, RelPathIndex); } else { // // For some reason we were not able to bring the // device offline. Most likely this is because the // device is critical to the system and cannot be // taken offline right now - for example a disk // that is in the paging path. // // @@BEGIN_DDKSPLIT #if REBOOT_DIAGNOSTICS // What we'll need to do is to remember that // this test is pending and so the next time the // system is rebooted we can check for the results // of this test and report them. // hr = PersistResultInSchema(pCdmResult, RelPathIndex); #else // // Reboot diagnostics are not currently supported. // // @@END_DDKSPLIT hr = WBEM_E_FAILED; // @@BEGIN_DDKSPLIT #endif // @@END_DDKSPLIT } } VariantClear(&v); } else { // // Since the OtherStateDescription was not set then we // assume that the tests isn't setup to go offline and has // already been completed // hr = WBEM_S_NO_ERROR; } } return(hr); } BOOLEAN CTestServices::IsThisInitialized( void ) /*+++ Routine Description: This routine determines if this class has been initialized to access CDM and WDM classes Arguments: Return Value: TRUE if initialiezed else FALSE ---*/ { return( (CdmTestClassName != NULL) ); } HRESULT CTestServices::AddResultToList( IN IWbemClassObject *ResultInstance, IN BSTR ExecutionID, IN int RelPathIndex ) /*+++ Routine Description: This routine will add a result object and the related association relpaths to the list of result objects for the test Arguments: ResultInstance is an instance of CIM_DiagnosticResults RelPathIndex ExecutionID Return Value: Never fails ---*/ { HRESULT hr; BSTR ResultRelPath; BSTR ResultForMSERelPath; BSTR ResultForTestRelPath; WmipAssert(ResultInstance != NULL); WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); // // If there is a new result object then establish the various // result relpaths for it // hr = BuildResultRelPaths(RelPathIndex, ExecutionID, &ResultRelPath, &ResultForMSERelPath, &ResultForTestRelPath); if (hr == WBEM_S_NO_ERROR) { hr = CdmResultsList[RelPathIndex].Add(ResultInstance, ResultRelPath, ResultForMSERelPath, ResultForTestRelPath); } return(hr); } HRESULT CTestServices::GetResultsList( IN int RelPathIndex, OUT ULONG *ResultsCount, OUT IWbemClassObject ***Results ) { WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); return(CdmResultsList[RelPathIndex].GetResultsList(ResultsCount, Results)); } void CTestServices::ClearResultsList( int RelPathIndex ) { WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); CdmResultsList[RelPathIndex].Clear(); } BSTR /* NOFREE */ CTestServices::GetCimRelPath( int RelPathIndex ) /*+++ Routine Description: This routine will return the Cim relpath for a RelPathIndex Arguments: RelPathIndex Return Value: Cim RelPath. This should not be freed ---*/ { WmipAssert(CimRelPaths != NULL); WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); return(CimRelPaths[RelPathIndex]); } BSTR /* NOFREE */ CTestServices::GetCdmTestRelPath( void ) /*+++ Routine Description: This routine will return the Cdm Test class relpath Arguments: Return Value: Cdm Test Class RelPath. This should not be freed ---*/ { WmipAssert(IsThisInitialized()); return(CdmTestRelPath); } BSTR /* NOFREE */ CTestServices::GetCdmTestClassName( void ) /*+++ Routine Description: This routine will return the Cdm Test class name Arguments: Return Value: Cdm Test Class Name. This should not be freed ---*/ { WmipAssert(IsThisInitialized()); return(CdmTestClassName); } BSTR /* NOFREE */ CTestServices::GetCdmResultClassName( void ) /*+++ Routine Description: This routine will return the Cdm Result class name Arguments: Return Value: Cdm Result Class Name. This should not be freed ---*/ { WmipAssert(IsThisInitialized()); return(CdmResultClassName); } HRESULT CTestServices::GetCdmResultByResultRelPath( IN int RelPathIndex, IN PWCHAR ObjectPath, OUT IWbemClassObject **ppCdmResult ) /*+++ Routine Description: This routine will return the Cdm Result object for a specific RelPath Arguments: RelPathIndex Return Value: Cdm Result RelPath or NULL of there is no ressult object for the relpath. This should not be freed ---*/ { HRESULT hr; WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); hr = CdmResultsList[RelPathIndex].GetResultByResultRelPath(ObjectPath, ppCdmResult); return(hr); } HRESULT CTestServices::GetCdmResultByResultForMSERelPath( IN int RelPathIndex, IN PWCHAR ObjectPath, OUT IWbemClassObject **ppCdmResult ) /*+++ Routine Description: This routine will return the Cdm Result object for a specific RelPath Arguments: RelPathIndex Return Value: Cdm Result RelPath or NULL of there is no ressult object for the relpath. This should not be freed ---*/ { HRESULT hr; WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); hr = CdmResultsList[RelPathIndex].GetResultByResultForMSERelPath(ObjectPath, ppCdmResult); return(hr); } HRESULT CTestServices::GetCdmResultByResultForTestRelPath( IN int RelPathIndex, IN PWCHAR ObjectPath, OUT IWbemClassObject **ppCdmResult ) /*+++ Routine Description: This routine will return the Cdm Result object for a specific RelPath Arguments: RelPathIndex Return Value: Cdm Result RelPath or NULL of there is no ressult object for the relpath. This should not be freed ---*/ { HRESULT hr; WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); hr = CdmResultsList[RelPathIndex].GetResultByResultForTestRelPath(ObjectPath, ppCdmResult); return(hr); } BSTR /* NOFREE */ CTestServices::GetCdmSettingClassName( void ) /*+++ Routine Description: This routine will return the Cdm settings class name Arguments: Return Value: Cdm Settings class name. This should not be freed ---*/ { WmipAssert(IsThisInitialized()); return(CdmSettingClassName); } BSTR /* NOFREE */ CTestServices::GetCdmSettingRelPath( int RelPathIndex, ULONG SettingIndex ) /*+++ Routine Description: This routine will return the Cdm settings relpath by relpath index and index with the settings for that relpath. Arguments: RelPathIndex SettingIndex Return Value: Cdm Settings relpath. This should not be freed ---*/ { CWbemObjectList *CdmSettings; WmipAssert(RelPathIndex < RelPathCount); WmipAssert(CdmSettingsList != NULL); WmipAssert(IsThisInitialized()); CdmSettings = CdmSettingsList[RelPathIndex]; return(CdmSettings->GetRelPath(SettingIndex)); } IWbemClassObject *CTestServices::GetCdmSettingObject( int RelPathIndex, ULONG SettingIndex ) { CWbemObjectList *CdmSettings; WmipAssert(RelPathIndex < RelPathCount); WmipAssert(CdmSettingsList != NULL); WmipAssert(IsThisInitialized()); CdmSettings = CdmSettingsList[RelPathIndex]; return(CdmSettings->Get(SettingIndex)); } ULONG CTestServices::GetCdmSettingCount( int RelPathIndex ) { WmipAssert(RelPathIndex < RelPathCount); WmipAssert(CdmSettingsList != NULL); WmipAssert(IsThisInitialized()); return(CdmSettingsList[RelPathIndex]->GetListSize()); } BSTR /* NOFREE */ CTestServices::GetCdmTestForMSEClassName( void ) { WmipAssert(IsThisInitialized()); return(CdmTestForMSEClassName); } BSTR /* NOFREE */ CTestServices::GetCdmTestForMSERelPath( int RelPathIndex ) { WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); return(CdmTestForMSERelPath[RelPathIndex]); } BSTR /* NOFREE */ CTestServices::GetCdmSettingForTestClassName( void ) { WmipAssert(IsThisInitialized()); return(CdmSettingForTestClassName); } BSTR /* NOFREE */ CTestServices::GetCdmSettingForTestRelPath( int RelPathIndex, ULONG SettingIndex ) { CBstrArray *BstrArray; BSTR s; WmipAssert(RelPathIndex < RelPathCount); WmipAssert(IsThisInitialized()); if (CdmSettingForTestRelPath != NULL) { BstrArray = CdmSettingForTestRelPath[RelPathIndex]; s = BstrArray->Get(SettingIndex); } else { s = NULL; } return(s); } BSTR /* NOFREE */ CTestServices::GetCdmResultForMSEClassName( void ) { WmipAssert(IsThisInitialized()); return(CdmResultForMSEClassName); } BSTR /* NOFREE */ CTestServices::GetCdmResultForTestClassName( void ) { WmipAssert(IsThisInitialized()); return(CdmResultForTestClassName); } BSTR /* NOFREE */ CTestServices::GetCdmTestForSoftwareClassName( void ) { WmipAssert(IsThisInitialized()); return(CdmTestForSoftwareClassName); } BSTR /* NOFREE */ CTestServices::GetCdmTestForSoftwareRelPath( void ) { WmipAssert(IsThisInitialized()); return(CdmTestForSoftwareRelPath); } BSTR /* NOFREE */ CTestServices::GetCdmTestInPackageClassName( void ) { WmipAssert(IsThisInitialized()); return(CdmTestInPackageClassName); } BSTR /* NOFREE */CTestServices::GetCdmTestInPackageRelPath( void ) { WmipAssert(IsThisInitialized()); return(CdmTestInPackageRelPath); } BSTR /* NOFREE */ CTestServices::GetCdmResultInPackageClassName( void ) { WmipAssert(IsThisInitialized()); return(CdmResultInPackageClassName); } BSTR /* NOFREE */ CTestServices::GetCdmResultInPackageRelPath( void ) { WmipAssert(IsThisInitialized()); return(CdmResultInPackageRelPath); } CWbemObjectList::CWbemObjectList() { // // Constructor, init internal values // List = NULL; RelPaths = NULL; ListSize = 0xffffffff; } CWbemObjectList::~CWbemObjectList() { // // Destructor, free memory held by this class // if (List != NULL) { WmipFree(List); } List = NULL; if (RelPaths != NULL) { FreeTheBSTRArray(RelPaths, ListSize); RelPaths = NULL; } ListSize = 0xffffffff; } HRESULT CWbemObjectList::Initialize( ULONG NumberPointers ) { HRESULT hr; ULONG AllocSize; // // Initialize class by allocating internal list array // WmipAssert(List == NULL); if (NumberPointers != 0) { AllocSize = NumberPointers * sizeof(IWbemClassObject *); List = (IWbemClassObject **)WmipAlloc(AllocSize); if (List != NULL) { memset(List, 0, AllocSize); AllocSize = NumberPointers * sizeof(BSTR); RelPaths = (BSTR *)WmipAlloc(AllocSize); if (RelPaths != NULL) { memset(RelPaths, 0, AllocSize); ListSize = NumberPointers; hr = WBEM_S_NO_ERROR; } else { WmipDebugPrint(("CDMProv: Could not alloc memory for CWbemObjectList RelPaths\n")); hr = WBEM_E_OUT_OF_MEMORY; } } else { WmipDebugPrint(("CDMProv: Could not alloc memory for CWbemObjectList\n")); hr = WBEM_E_OUT_OF_MEMORY; } } else { ListSize = NumberPointers; hr = WBEM_S_NO_ERROR; } return(hr); } ULONG CWbemObjectList::GetListSize( void ) { // // Accessor for list size // WmipAssert(IsInitialized()); return(ListSize); } IWbemClassObject *CWbemObjectList::Get( ULONG Index ) { IWbemClassObject *Pointer; WmipAssert(Index < ListSize); WmipAssert(IsInitialized()); Pointer = List[Index]; return(Pointer); } HRESULT CWbemObjectList::Set( IN ULONG Index, IN IWbemClassObject *Pointer, IN BOOLEAN KeepRelPath ) { HRESULT hr; VARIANT v; WmipAssert(Index < ListSize); WmipAssert(IsInitialized()); if (Pointer != NULL) { hr = WmiGetProperty(Pointer, L"__RelPath", CIM_REFERENCE, &v); if (hr == WBEM_S_NO_ERROR) { RelPaths[Index] = v.bstrVal; List[Index] = Pointer; } else { if (! KeepRelPath) { RelPaths[Index] = NULL; List[Index] = Pointer; } } } else { if (RelPaths[Index] != NULL) { SysFreeString(RelPaths[Index]); RelPaths[Index] = NULL; hr = WBEM_S_NO_ERROR; } List[Index] = NULL; } return(hr); } BSTR /* NOFREE */ CWbemObjectList::GetRelPath( IN ULONG Index ) { WmipAssert(Index < ListSize); WmipAssert(IsInitialized()); return(RelPaths[Index]); } BOOLEAN CWbemObjectList::IsInitialized( ) { return((ListSize == 0) || ((List != NULL) && (RelPaths != NULL))); } // // Linked list management routines // CTestServices *CTestServices::GetNext( ) { return(Next); } CTestServices *CTestServices::GetPrev( ) { return(Prev); } void CTestServices::InsertSelf( CTestServices **Head ) { WmipAssert(Next == NULL); WmipAssert(Prev == NULL); if (*Head != NULL) { Next = (*Head); (*Head)->Prev = this; } *Head = this; } BOOLEAN CTestServices::ClaimCdmClassName( PWCHAR CdmClassName ) { if (_wcsicmp(CdmClassName, CdmTestClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmResultClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmSettingClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmTestForMSEClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmSettingForTestClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmResultForMSEClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmResultForTestClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmTestForSoftwareClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmTestInPackageClassName) == 0) { return(TRUE); } if (_wcsicmp(CdmClassName, CdmResultInPackageClassName) == 0) { return(TRUE); } return(FALSE); } CBstrArray::CBstrArray() { Array = NULL; ListSize = 0xffffffff; } CBstrArray::~CBstrArray() { ULONG i; if (Array != NULL) { for (i = 0; i < ListSize; i++) { if (Array[i] != NULL) { SysFreeString(Array[i]); } } WmipFree(Array); } ListSize = 0xffffffff; } HRESULT CBstrArray::Initialize( ULONG ListCount ) { HRESULT hr = WBEM_S_NO_ERROR; ULONG AllocSize; if (ListCount != 0) { AllocSize = ListCount * sizeof(BSTR *); Array = (BSTR *)WmipAlloc(AllocSize); if (Array != NULL) { memset(Array, 0, AllocSize); ListSize = ListCount; } else { hr = WBEM_E_OUT_OF_MEMORY; } } else { ListSize = ListCount; } return(hr); } BOOLEAN CBstrArray::IsInitialized( ) { return( (Array != NULL) || (ListSize == 0) ); } BSTR CBstrArray::Get( ULONG Index ) { WmipAssert(Index < ListSize); WmipAssert(IsInitialized()); return(Array[Index]); } void CBstrArray::Set( ULONG Index, BSTR s ) { WmipAssert(Index < ListSize); WmipAssert(IsInitialized()); Array[Index] = s; } ULONG CBstrArray::GetListSize( ) { WmipAssert(IsInitialized()); return(ListSize); } CResultList::CResultList() { ListSize = 0; ListEntries = 0; List = NULL; } CResultList::~CResultList() { ULONG i; Clear(); if (List != NULL) { WmipFree(List); } } void CResultList::Clear( void ) { ULONG i; PRESULTENTRY Entry; if (List != NULL) { for (i = 0; i < ListEntries; i++) { Entry = &List[i]; if (Entry->ResultInstance != NULL) { Entry->ResultInstance->Release(); Entry->ResultInstance = NULL; } if (Entry->ResultRelPath != NULL) { SysFreeString(Entry->ResultRelPath); Entry->ResultRelPath = NULL; } if (Entry->ResultForMSERelPath != NULL) { SysFreeString(Entry->ResultForMSERelPath); Entry->ResultForMSERelPath = NULL; } if (Entry->ResultForTestRelPath != NULL) { SysFreeString(Entry->ResultForTestRelPath); Entry->ResultForTestRelPath = NULL; } } } ListEntries = 0; } // // The result list will grow itself this many entries at a time // #define RESULTLISTGROWSIZE 4 HRESULT CResultList::Add( IWbemClassObject *CdmResultInstance, BSTR CdmResultRelPath, BSTR CdmResultForMSERelPath, BSTR CdmResultForTestRelPath ) { ULONG AllocSize; PRESULTENTRY NewList, Entry; ULONG CurrentSize; EnterCdmCritSection(); if (List == NULL) { // // We are starting with an empty list // AllocSize = RESULTLISTGROWSIZE * sizeof(RESULTENTRY); List = (PRESULTENTRY)WmipAlloc(AllocSize); if (List == NULL) { LeaveCdmCritSection(); return(WBEM_E_OUT_OF_MEMORY); } memset(List, 0, AllocSize); ListSize = RESULTLISTGROWSIZE; ListEntries = 0; } else if (ListEntries == ListSize) { // // The list needs to grow, so we allocate more memory and copy // over the current list // CurrentSize = ListSize * sizeof(RESULTENTRY); AllocSize = CurrentSize + (RESULTLISTGROWSIZE * sizeof(RESULTENTRY)); NewList = (PRESULTENTRY)WmipAlloc(AllocSize); if (NewList == NULL) { LeaveCdmCritSection(); return(WBEM_E_OUT_OF_MEMORY); } memset(NewList, 0, AllocSize); memcpy(NewList, List, CurrentSize); WmipFree(List); List = NewList; ListSize += RESULTLISTGROWSIZE; } // // We have room to add a new entry to the list // Entry = &List[ListEntries++]; Entry->ResultInstance = CdmResultInstance; Entry->ResultInstance->AddRef(); Entry->ResultRelPath = CdmResultRelPath; Entry->ResultForMSERelPath = CdmResultForMSERelPath; Entry->ResultForTestRelPath = CdmResultForTestRelPath; LeaveCdmCritSection(); return(WBEM_S_NO_ERROR); } HRESULT CResultList::GetResultsList( OUT ULONG *Count, OUT IWbemClassObject ***Objects ) { IWbemClassObject **Things; HRESULT hr; ULONG i; EnterCdmCritSection(); *Count = ListEntries; if (ListEntries != 0) { Things = (IWbemClassObject **)WmipAlloc( ListEntries * sizeof(IWbemClassObject *)); if (Things != NULL) { *Objects = Things; for (i = 0; i < ListEntries; i++) { Things[i] = List[i].ResultInstance; Things[i]->AddRef(); } hr = WBEM_S_NO_ERROR; } else { hr = WBEM_E_OUT_OF_MEMORY; } } else { *Objects = NULL; hr = WBEM_S_NO_ERROR; } LeaveCdmCritSection(); return(hr); } HRESULT CResultList::GetResultByResultRelPath( PWCHAR ObjectPath, IWbemClassObject **ppResult ) { HRESULT hr; ULONG i; hr = WBEM_E_NOT_FOUND; EnterCdmCritSection(); for (i = 0; i < ListEntries; i++) { if (_wcsicmp(ObjectPath, List[i].ResultRelPath) == 0) { *ppResult = List[i].ResultInstance; (*ppResult)->AddRef(); hr = WBEM_S_NO_ERROR; break; } } LeaveCdmCritSection(); return(hr); } HRESULT CResultList::GetResultByResultForMSERelPath( PWCHAR ObjectPath, IWbemClassObject **ppResult ) { HRESULT hr; ULONG i; hr = WBEM_E_NOT_FOUND; EnterCdmCritSection(); for (i = 0; i < ListEntries; i++) { if (_wcsicmp(ObjectPath, List[i].ResultForMSERelPath) == 0) { *ppResult = List[i].ResultInstance; (*ppResult)->AddRef(); hr = WBEM_S_NO_ERROR; break; } } LeaveCdmCritSection(); return(hr); } HRESULT CResultList::GetResultByResultForTestRelPath( PWCHAR ObjectPath, IWbemClassObject **ppResult ) { HRESULT hr; ULONG i; hr = WBEM_E_NOT_FOUND; EnterCdmCritSection(); for (i = 0; i < ListEntries; i++) { if (_wcsicmp(ObjectPath, List[i].ResultForTestRelPath) == 0) { *ppResult = List[i].ResultInstance; (*ppResult)->AddRef(); hr = WBEM_S_NO_ERROR; break; } } LeaveCdmCritSection(); return(hr); }