//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 2000 // // File: wbemmisc.cpp // // Abstract: Misc routines useful for interfacing with WBEM // //-------------------------------------------------------------------------- #include #include #include #include #include #include #include #include "debug.h" #include "wbemmisc.h" HRESULT GetMethodInParamInstance( IN IWbemServices *pServices, IN PWCHAR ClassName, IN BSTR MethodName, OUT IWbemClassObject **ppInParamInstance ) /*+++ Routine Description: This routine will return an instance object for a methods in parameter. WBEM requires that we go through this dance to get an instance object. Arguments: pServices ClassName is the class containing the method MethodName is the name of the method *ppInParamInstance returns the instance object to fill with in parameters Return Value: HRESULT ---*/ { HRESULT hr; IWbemClassObject *pClass; IWbemClassObject *pInParamClass; WmipAssert(pServices != NULL); WmipAssert(ClassName != NULL); WmipAssert(MethodName != NULL); WmipAssert(ppInParamInstance != NULL); hr = pServices->GetObject(ClassName, 0, NULL, &pClass, NULL); if (hr == WBEM_S_NO_ERROR) { hr = pClass->GetMethod(MethodName, 0, &pInParamClass, NULL); if (hr == WBEM_S_NO_ERROR) { hr = pInParamClass->SpawnInstance(0, ppInParamInstance); pInParamClass->Release(); } pClass->Release(); } return(hr); } HRESULT WmiGetQualifier( IN IWbemQualifierSet *pIWbemQualifierSet, IN PWCHAR QualifierName, IN VARTYPE Type, OUT /* FREE */ VARIANT *Value ) /*+++ Routine Description: This routine will return the value for a specific qualifier Arguments: pIWbemQualifierSet is the qualifier set object QualifierName is the name of the qualifier Type is the type of qualifier expected *Value returns with the value of the qualifier. Caller must call VariantClear Return Value: HRESULT ---*/ { BSTR s; HRESULT hr; WmipAssert(pIWbemQualifierSet != NULL); WmipAssert(QualifierName != NULL); WmipAssert(Value != NULL); s = SysAllocString(QualifierName); if (s != NULL) { hr = pIWbemQualifierSet->Get(s, 0, Value, NULL); if ((Value->vt & ~CIM_FLAG_ARRAY) != Type) { hr = WBEM_E_FAILED; VariantClear(Value); } SysFreeString(s); } else { hr = WBEM_E_OUT_OF_MEMORY; } return(hr); } HRESULT WmiGetQualifierListByName( IN IWbemServices *pServices, IN PWCHAR ClassName, IN PWCHAR PropertyName, IN ULONG QualifierCount, IN PWCHAR *QualifierNames, IN VARTYPE *Types, OUT VARIANT /* FREE */ *Values ) /*+++ Routine Description: This routine will return the values for a list of qualifiers. If all qualifiers cannot be returned then none are. Arguments: pServices is the IWbemServices pointer ClassName is the name of the class with qualifiers PropertyName is the name of the property with qualfiers. If NULL then class qualifiers are returned QualifierCount is the count of qualifers to get QualifierNames is an array contaiing names of qualifiers to get Types is an array of expected value types for the qualifiers Values is an array of variants that return with the qualifer values Return Value: HRESULT ---*/ { HRESULT hr; IWbemClassObject *pClass; IWbemQualifierSet *pQualifiers; ULONG i, j; WmipAssert(pServices != NULL); WmipAssert(ClassName != NULL); WmipAssert(QualifierNames != NULL); WmipAssert(Types != NULL); WmipAssert(Values != NULL); // // Create the class so we can look at the properties // hr = pServices->GetObject(ClassName, WBEM_FLAG_USE_AMENDED_QUALIFIERS, NULL, &pClass, NULL); if (hr == WBEM_S_NO_ERROR) { if (PropertyName == NULL) { hr = pClass->GetQualifierSet(&pQualifiers); } else { hr = pClass->GetPropertyQualifierSet(PropertyName, &pQualifiers); } if (hr == WBEM_S_NO_ERROR) { for (i = 0; (i < QualifierCount) && (hr == WBEM_S_NO_ERROR); i++) { hr = WmiGetQualifier(pQualifiers, QualifierNames[i], Types[i], &Values[i]); } if (hr != WBEM_S_NO_ERROR) { for (j = 0; j < i; j++) { VariantClear(&Values[j]); } } pQualifiers->Release(); } pClass->Release(); } return(hr); } HRESULT WmiGetProperty( IN IWbemClassObject *pIWbemClassObject, IN PWCHAR PropertyName, IN CIMTYPE ExpectedCimType, OUT VARIANT /* FREE */ *Value ) /*+++ Routine Description: This routine will return the value for a specific property Arguments: pIWbemQualifierSet is the qualifier set object PropertyName is the name of the property Type is the type of property expected *Value returns with the value of the property Return Value: HRESULT ---*/ { HRESULT hr; CIMTYPE CimType; WmipAssert(pIWbemClassObject != NULL); WmipAssert(PropertyName != NULL); WmipAssert(Value != NULL); hr = pIWbemClassObject->Get(PropertyName, 0, Value, &CimType, NULL); // // Treat a NULL value for a property as an error // if (Value->vt == VT_NULL) { hr = WBEM_E_ILLEGAL_NULL; WmipDebugPrint(("CDMPROV: Property %ws is NULL\n", PropertyName)); } // // Treat CIM_REFERENCE and CIM_STRING as interchangable // if ((ExpectedCimType == CIM_REFERENCE) && (CimType == CIM_STRING)) { ExpectedCimType = CIM_STRING; } if ((ExpectedCimType == CIM_STRING) && (CimType == CIM_REFERENCE)) { ExpectedCimType = CIM_REFERENCE; } if ((hr == WBEM_S_NO_ERROR) && (ExpectedCimType != CimType)) { WmipDebugPrint(("CDMPROV: Property %ws was expected as %d but was got as %d\n", PropertyName, ExpectedCimType, CimType)); WmipAssert(FALSE); hr = WBEM_E_FAILED; VariantClear(Value); } return(hr); } HRESULT WmiGetPropertyList( IN IWbemClassObject *pIWbemClassObject, IN ULONG PropertyCount, IN PWCHAR *PropertyNames, IN CIMTYPE *ExpectedCimType, OUT VARIANT /* FREE */ *Value ) /*+++ Routine Description: This routine will return the value for a specific property Arguments: pIWbemQualifierSet is the qualifier set object PropertyNames is the name of the property Type is the type of property expected *Value returns with the value of the property Return Value: HRESULT ---*/ { ULONG i,j; HRESULT hr; WmipAssert(pIWbemClassObject != NULL); WmipAssert(PropertyNames != NULL); WmipAssert(ExpectedCimType != NULL); WmipAssert(Value != NULL); for (i = 0, hr = WBEM_S_NO_ERROR; (i < PropertyCount) && (hr == WBEM_S_NO_ERROR); i++) { hr = WmiGetProperty(pIWbemClassObject, PropertyNames[i], ExpectedCimType[i], &Value[i]); } if (hr != WBEM_S_NO_ERROR) { for (j = 0; j < i; j++) { VariantClear(&Value[i]); } } return(hr); } HRESULT WmiGetPropertyByName( IN IWbemServices *pServices, IN PWCHAR ClassName, IN PWCHAR PropertyName, IN CIMTYPE ExpectedCimType, OUT VARIANT /* FREE */ *Value ) /*+++ Routine Description: This routine will return the value for a specific property within a class Arguments: pServices is the IWbemServices for the namespace containing your class ClassName is the name of the class whose property you are interested in PropertyName is the name of the property Type is the type of property expected *Value returns with the value of the property Return Value: HRESULT ---*/ { HRESULT hr; IWbemClassObject *pClass; WmipAssert(pServices != NULL); WmipAssert(ClassName != NULL); WmipAssert(PropertyName != NULL); WmipAssert(Value != NULL); // // Create the class so we can look at the properties // hr = pServices->GetObject(ClassName, 0, NULL, &pClass, NULL); if (hr == WBEM_S_NO_ERROR) { hr = WmiGetProperty(pClass, PropertyName, ExpectedCimType, Value); pClass->Release(); } return(hr); } HRESULT WmiSetProperty( IN IWbemClassObject *pIWbemClassObject, IN PWCHAR PropertyName, IN VARIANT *Value ) /*+++ Routine Description: This routine will set the value of a property to something Arguments: pIWbemClassObject is the object whose property is being set PropertyName is the name of the property being set Value is the value that the property is being set to Return Value: HRESULT ---*/ { HRESULT hr; WmipAssert(pIWbemClassObject != NULL); WmipAssert(PropertyName != NULL); WmipAssert(Value != NULL); hr = pIWbemClassObject->Put(PropertyName, 0, Value, 0); if (hr == WBEM_E_TYPE_MISMATCH) { WmipDebugPrint(("CDMPROV: Put %ws has wrong type %d\n", PropertyName, Value->vt)); WmipAssert(FALSE); } return(hr); } HRESULT WmiSetPropertyList( IN IWbemClassObject *pIWbemClassObject, IN ULONG PropertyCount, IN PWCHAR *PropertyNames, IN VARIANT *Values ) /*+++ Routine Description: This routine will set the values of multiple properties to something Arguments: pIWbemClassObject is the object whose property is being set PropertyCount is the number of properties to set PropertyNames is the names of the property being set Values is the value that the property is being set to Return Value: HRESULT ---*/ { ULONG i; HRESULT hr = WBEM_S_NO_ERROR; WmipAssert(pIWbemClassObject != NULL); WmipAssert(PropertyNames != NULL); WmipAssert(Values != NULL); for (i = 0; (i < PropertyCount) && (hr == WBEM_S_NO_ERROR); i++) { hr = WmiSetProperty(pIWbemClassObject, PropertyNames[i], &Values[i]); } return(hr); } // @@BEGIN_DDKSPLIT #ifndef HEAP_DEBUG // @@END_DDKSPLIT PVOID WmipAlloc( IN ULONG Size ) /*+++ Routine Description: Internal memory allocator Arguments: Size is the number of bytes to allocate Return Value: pointer to alloced memory or NULL ---*/ { return(LocalAlloc(LPTR, Size)); } void WmipFree( IN PVOID Ptr ) /*+++ Routine Description: Internal memory deallocator Arguments: Pointer to freed memory Return Value: void ---*/ { WmipAssert(Ptr != NULL); LocalFree(Ptr); } // @@BEGIN_DDKSPLIT #endif // @@END_DDKSPLIT PWCHAR AddSlashesToStringW( OUT PWCHAR SlashedNamespace, IN PWCHAR Namespace ) /*+++ Routine Description: This routine will convert ever \ in the string into \\. It needs to do this since WBEM will collapse \\ into \ sometimes. Arguments: SlashedNamespace returns with string double slashed Namespace is the input string Return Value: pointer to SlashedNamespace ---*/ { PWCHAR Return = SlashedNamespace; WmipAssert(SlashedNamespace != NULL); WmipAssert(Namespace != NULL); // // MOF likes the namespace paths to be C-style, that is to have a // '\\' instad of a '\'. So whereever we see a '\', we insert a // second one // while (*Namespace != 0) { if (*Namespace == L'\\') { *SlashedNamespace++ = L'\\'; } *SlashedNamespace++ = *Namespace++; } *SlashedNamespace = 0; return(Return); } PWCHAR AddSlashesToStringExW( OUT PWCHAR SlashedNamespace, IN PWCHAR Namespace ) /*+++ Routine Description: This routine will convert ever \ in the string into \\ and " into \". It needs to do this since WBEM will collapse \\ into \ sometimes. Arguments: SlashedNamespace returns with string double slashed Namespace is the input string Return Value: pointer to SlashedNamespace ---*/ { PWCHAR Return = SlashedNamespace; WmipAssert(SlashedNamespace != NULL); WmipAssert(Namespace != NULL); // // MOF likes the namespace paths to be C-style, that is to have a // '\\' instad of a '\'. So whereever we see a '\', we insert a // second one. We also need to add a \ before any ". // while (*Namespace != 0) { if ((*Namespace == L'\\') || (*Namespace == L'"')) { *SlashedNamespace++ = L'\\'; } *SlashedNamespace++ = *Namespace++; } *SlashedNamespace = 0; return(Return); } HRESULT WmiConnectToWbem( IN PWCHAR Namespace, OUT IWbemServices **ppIWbemServices ) /*+++ Routine Description: This routine will establishes a connection to a WBEM namespace on the local machine. Arguments: Namespace is the namespace to which to connect *ppIWbemServices returns with a IWbemServices * for the namespace Return Value: HRESULT ---*/ { IWbemLocator *pIWbemLocator; DWORD hr; BSTR s; WmipAssert(Namespace != NULL); WmipAssert(ppIWbemServices != NULL); hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pIWbemLocator); if (hr == S_OK) { s = SysAllocString(Namespace); if (s != NULL) { *ppIWbemServices = NULL; hr = pIWbemLocator->ConnectServer(s, NULL, // Userid NULL, // PW NULL, // Locale 0, // flags NULL, // Authority NULL, // Context ppIWbemServices ); SysFreeString(s); } else { *ppIWbemServices = NULL; hr = WBEM_E_OUT_OF_MEMORY; } pIWbemLocator->Release(); } return(hr); } HRESULT CreateInst( IN IWbemServices * pNamespace, OUT /* FREE */ IWbemClassObject ** pNewInst, IN WCHAR * pwcClassName, IN IWbemContext *pCtx ) /*+++ Routine Description: This routine will create a new instance for the specified class Arguments: pNamespace is the IWbemServices * to the namespace in which the class lives *pNewinst returns with the new instance of the class pwcClassName has the name of the class whose instance is created pCtx is the context to use in creating the instance Return Value: HRESULT ---*/ { HRESULT hr; IWbemClassObject * pClass; hr = pNamespace->GetObject(pwcClassName, 0, pCtx, &pClass, NULL); if (hr != S_OK) { return WBEM_E_FAILED; } hr = pClass->SpawnInstance(0, pNewInst); pClass->Release(); WmipDebugPrint(("CDMProv:: Created %ws as %p\n", pwcClassName, *pNewInst)); return(hr); } /* FREE */ BSTR GetCurrentDateTime( void ) { SYSTEMTIME SystemTime; WBEMTime WbemTime; GetSystemTime(&SystemTime); WbemTime = SystemTime; return(WbemTime.GetBSTR()); } HRESULT WmiGetArraySize( IN SAFEARRAY *Array, OUT LONG *LBound, OUT LONG *UBound, OUT LONG *NumberElements ) /*+++ Routine Description: This routine will information about the size and bounds of a single dimensional safe array. Arguments: Array is the safe array *LBound returns with the lower bound of the array *UBound returns with the upper bound of the array *NumberElements returns with the number of elements in the array Return Value: TRUE if successful else FALSE ---*/ { HRESULT hr; WmipAssert(Array != NULL); WmipAssert(LBound != NULL); WmipAssert(UBound != NULL); WmipAssert(NumberElements != NULL); // // Only single dim arrays are supported // WmipAssert(SafeArrayGetDim(Array) == 1); hr = SafeArrayGetLBound(Array, 1, LBound); if (hr == WBEM_S_NO_ERROR) { hr = SafeArrayGetUBound(Array, 1, UBound); *NumberElements = (*UBound - *LBound) + 1; } return(hr); } BOOLEAN IsUlongAndStringEqual( IN ULONG Number, IN PWCHAR String ) /*+++ Routine Description: This routine will convert the passed string to an integer and compare it to the passed integer value Arguments: Number String Return Value: TRUE if equal else FALSE ---*/ { ULONG SNumber; SNumber = _wtoi(String); return ( (Number == SNumber) ? TRUE : FALSE ); } HRESULT LookupValueMap( IN IWbemServices *pServices, IN PWCHAR ClassName, IN PWCHAR PropertyName, IN ULONG Value, OUT /* FREE */ BSTR *MappedValue ) /*+++ Routine Description: This routine will lookup the string value corresponding to an integer valuemap Arguments: pServices is the pointer to the namespace in which the class is locaed ClassName is the name of the class PropertyName is the name of the property Value is the value of the property and is used to look up the string that corresponsds to it *MappedValue returns a string that contains the string which the value maps to Return Value: HRESULT ---*/ { PWCHAR Names[2]; VARIANT QualifierValues[2]; VARTYPE Types[2]; HRESULT hr; BSTR s; LONG ValuesLBound, ValuesUBound, ValuesElements; LONG ValueMapLBound, ValueMapUBound, ValueMapElements; LONG i, Index; WmipAssert(pServices != NULL); WmipAssert(ClassName != NULL); WmipAssert(PropertyName != NULL); WmipAssert(MappedValue != NULL); // // Get the Values and ValueMap qualifiers so we can do the mapping // Names[0] = L"Values"; Types[0] = VT_BSTR; Names[1] = L"ValueMap"; Types[1] = VT_BSTR; hr = WmiGetQualifierListByName(pServices, ClassName, PropertyName, 2, Names, Types, QualifierValues); if (hr == WBEM_S_NO_ERROR) { // // Now do a sanity check to make sure the values and valuemaps // have the same number of elements // if (QualifierValues[0].vt == QualifierValues[1].vt) { // // Values and ValueMap both agree that they are both // scalars or both arrays and are both strings // if (QualifierValues[0].vt & VT_ARRAY) { // // We have an array of thing to check for mapping. // First lets make sure that the arrays have identical // dimensions // hr = WmiGetArraySize(QualifierValues[0].parray, &ValuesLBound, &ValuesUBound, &ValuesElements); if (hr == WBEM_S_NO_ERROR) { hr = WmiGetArraySize(QualifierValues[1].parray, &ValueMapLBound, &ValueMapUBound, &ValueMapElements); if (hr == WBEM_S_NO_ERROR) { if ((ValuesLBound == ValueMapLBound) && (ValuesUBound == ValueMapUBound) && (ValuesElements == ValueMapElements)) { for (i = 0; i < ValueMapElements; i++) { Index = i + ValueMapLBound; hr = SafeArrayGetElement(QualifierValues[1].parray, &Index, &s); if (hr == WBEM_S_NO_ERROR) { if (IsUlongAndStringEqual(Value, s)) { hr = SafeArrayGetElement(QualifierValues[0].parray, &Index, MappedValue); // // Make sure loop will // terminate i = ValueMapElements; } SysFreeString(s); } } } else { hr = WBEM_E_NOT_FOUND; } } } } else { // // We have scalars so this should make a fairly simple // mapping // if (IsUlongAndStringEqual(Value, QualifierValues[1].bstrVal)) { *MappedValue = SysAllocString(QualifierValues[0].bstrVal); if (*MappedValue == NULL) { hr = WBEM_E_OUT_OF_MEMORY; } } else { hr = WBEM_E_NOT_FOUND; } } } else { hr = WBEM_E_NOT_FOUND; } VariantClear(&QualifierValues[0]); VariantClear(&QualifierValues[1]); } return(hr); } void FreeTheBSTRArray( BSTR *Array, ULONG Size ) /*+++ Routine Description: This routine will free the contents of an array of BSTR and then the array itself Arguments: Array is the array to be freed Size is the number of elements in the array Return Value: HRESULT ---*/ { ULONG i; if (Array != NULL) { for (i = 0; i < Size; i++) { if (Array[i] != NULL) { SysFreeString(Array[i]); } } WmipFree(Array); } }