windows-nt/Source/XPSP1/NT/base/wmi/proppage/wmiprop.cpp
2020-09-26 16:20:57 +08:00

5765 lines
162 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: wmiprop.c
//
//--------------------------------------------------------------------------
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <prsht.h>
#include <ole2.h>
extern "C" {
#include <commdlg.h>
#include <cfgmgr32.h>
#include <setupapi.h>
#include <regstr.h>
}
#include <wbemidl.h>
#include "wmiprop.h"
#include "resource.h"
HINSTANCE g_hInstance;
#if DBG
#define DEBUG_HEAP 1
#define WmiAssert(x) if (! (x) ) { \
DebugPrint((1, "WMI Assertion: "#x" at %s %d\n", __FILE__, __LINE__)); \
DebugBreak(); }
#else
#define WmiAssert(x)
#endif
#if DEBUG_HEAP
#undef LocalAlloc
#undef LocalFree
#define LocalAlloc(lptr, size) DebugAlloc(size)
#define LocalFree(p) DebugFree(p)
PVOID WmiPrivateHeap;
PVOID DebugAlloc(ULONG size)
{
PVOID p = NULL;
if (WmiPrivateHeap == NULL)
{
WmiPrivateHeap = RtlCreateHeap(HEAP_GROWABLE |
HEAP_TAIL_CHECKING_ENABLED |
HEAP_FREE_CHECKING_ENABLED |
HEAP_DISABLE_COALESCE_ON_FREE,
NULL,
0,
0,
NULL,
NULL);
}
if (WmiPrivateHeap != NULL)
{
p = RtlAllocateHeap(WmiPrivateHeap, 0, size);
if (p != NULL)
{
memset(p, 0, size);
}
}
return(p);
}
void DebugFree(PVOID p)
{
RtlFreeHeap(WmiPrivateHeap, 0, p);
}
#endif
#if DBG
PCHAR WmiGuidToString(
PCHAR s,
LPGUID piid
)
{
GUID XGuid = *piid;
sprintf(s, "%x-%x-%x-%x%x%x%x%x%x%x%x",
XGuid.Data1, XGuid.Data2,
XGuid.Data3,
XGuid.Data4[0], XGuid.Data4[1],
XGuid.Data4[2], XGuid.Data4[3],
XGuid.Data4[4], XGuid.Data4[5],
XGuid.Data4[6], XGuid.Data4[7]);
return(s);
}
#endif
TCHAR *WmiDuplicateString(
TCHAR *String
)
{
ULONG Len;
PTCHAR Copy;
Len = _tcslen(String);
Copy = (PTCHAR)LocalAlloc(LPTR,
(Len+1) * sizeof(TCHAR));
if (Copy != NULL)
{
_tcscpy(Copy, String);
}
return(Copy);
}
BOOLEAN WmiGetDataBlockDesc(
IN IWbemServices *pIWbemServices,
IN IWbemClassObject *pIWbemClassObject,
OUT PDATA_BLOCK_DESCRIPTION *DBD,
IN PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc,
IN BOOLEAN IsParentReadOnly
);
BOOLEAN WmiRefreshDataBlockFromWbem(
IWbemClassObject *pIWbemClassObject,
PDATA_BLOCK_DESCRIPTION DataBlockDesc
);
BOOLEAN WmiRefreshWbemFromDataBlock(
IN IWbemServices *pIWbemServices,
IN IWbemClassObject *pIWbemClassObject,
IN PDATA_BLOCK_DESCRIPTION DataBlockDesc,
IN BOOLEAN IsEmbeddedClass
);
BOOLEAN WmiBstrToTchar(
OUT PTCHAR *TString,
IN BSTR BString
)
/*+++
Routine Description:
This routine will convert a BSTR into a TCHAR *
Arguments:
BString is the BSTR to convert from
*TString returns with a pointer to a string containing the contents of
the BSTR. It should be freed with LocalFree.
Return Value:
TRUE if successful else FALSE
---*/
{
ULONG SizeNeeded;
BOOLEAN ReturnStatus;
WmiAssert(BString != NULL);
WmiAssert(TString != NULL);
SizeNeeded = (SysStringLen(BString)+1) * sizeof(TCHAR);
*TString = (PTCHAR)LocalAlloc(LPTR, SizeNeeded);
if (*TString != NULL)
{
_tcscpy(*TString, BString);
ReturnStatus = TRUE;
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiBstrToUlong64(
OUT PULONG64 Number,
IN BSTR BString
)
/*+++
Routine Description:
This routine will convert a BSTR into a ULONG64 number
Arguments:
BString is the BSTR to convert from
*Number returns with the value of the contents of BString converted to
a number
Return Value:
TRUE if successful else FALSE
---*/
{
WmiAssert(BString != NULL);
WmiAssert(Number != NULL);
*Number = _ttoi64(BString);
return(TRUE);
}
BOOLEAN 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;
BOOLEAN ReturnStatus;
WmiAssert(Array != NULL);
WmiAssert(LBound != NULL);
WmiAssert(UBound != NULL);
WmiAssert(NumberElements != NULL);
//
// Only single dim arrays are supported
//
WmiAssert(SafeArrayGetDim(Array) == 1);
hr = SafeArrayGetLBound(Array, 1, LBound);
if (hr == WBEM_S_NO_ERROR)
{
hr = SafeArrayGetUBound(Array, 1, UBound);
*NumberElements = (*UBound - *LBound) + 1;
ReturnStatus = (hr == WBEM_S_NO_ERROR);
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiConnectToWbem(
PTCHAR MachineName,
IWbemServices **pIWbemServices
)
/*+++
Routine Description:
This routine will establishes a connection to the WBEM service and
saves the global IWbemServices interface
Arguments:
MachineName is the name of the remote machine we should connect to.
If NULL then we connect to the local machine.
Return Value:
if this routine is successful then *pIWbemServices will have a valid
IWbemServices pointer, if not then it is NULL.
---*/
{
#define Namespace TEXT("root\\wmi")
IWbemLocator *pIWbemLocator;
DWORD hr;
SCODE sc;
BSTR s;
BOOLEAN ReturnStatus = FALSE;
PTCHAR NamespacePath;
WmiAssert(pIWbemServices != NULL);
if (MachineName == NULL)
{
NamespacePath = Namespace;
} else {
NamespacePath = (PTCHAR)LocalAlloc(LPTR, (_tcslen(Namespace) +
_tcslen(MachineName) +
2) * sizeof(TCHAR) );
if (NamespacePath != NULL)
{
_tcscpy(NamespacePath, MachineName);
_tcscat(NamespacePath, TEXT("\\"));
_tcscat(NamespacePath, Namespace);
} else {
DebugPrint((1, "WMIPROP: Could not alloc memory for NamespacePath\n"));
return(FALSE);
}
}
hr = CoCreateInstance(CLSID_WbemLocator,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
(LPVOID *) &pIWbemLocator);
if (hr == S_OK)
{
s = SysAllocString(NamespacePath);
if (s != NULL)
{
*pIWbemServices = NULL;
sc = pIWbemLocator->ConnectServer(s,
NULL, // Userid
NULL, // PW
NULL, // Locale
0, // flags
NULL, // Authority
NULL, // Context
pIWbemServices
);
SysFreeString(s);
if (sc != WBEM_NO_ERROR)
{
*pIWbemServices = NULL;
} else {
//
// Set security level to IMPERSONATE so that access
// to wbem objects will be granted
//
sc = CoSetProxyBlanket( (IUnknown *)*pIWbemServices,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
0);
if (sc == S_OK)
{
ReturnStatus = TRUE;
} else {
(*pIWbemServices)->Release();
*pIWbemServices = NULL;
}
}
pIWbemLocator->Release();
} else {
*pIWbemServices = NULL;
}
}
if (MachineName != NULL)
{
LocalFree(NamespacePath);
}
return(ReturnStatus);
}
#define IsWhiteSpace(c) ( (c == TEXT(' ')) || (c == TEXT('\t')) )
BOOLEAN WmiHexToUlong64(
IN PTCHAR Text,
OUT PULONG64 Number
)
/*+++
Routine Description:
This routine will convert a string with number in hex format into
a ULONG64
Arguments:
Text is the string
*Number returns with the hex value for string
Return Value:
TRUE if successful else FALSE
---*/
{
ULONG64 Value;
ULONG Count;
WmiAssert(Text != NULL);
WmiAssert(Number != NULL);
Value = 0;
Count = 0;
while ((*Text != 0) && (! IsWhiteSpace(*Text)))
{
if (Count == 16)
{
return(FALSE);
}
if (*Text >= '0' && *Text <= '9')
Value = (Value << 4) + *Text - '0';
else if (*Text >= 'A' && *Text <= 'F')
Value = (Value << 4) + *Text - 'A' + 10;
else if (*Text >= 'a' && *Text <= 'f')
Value = (Value << 4) + *Text - 'a' + 10;
else
return(FALSE);
Text++;
}
*Number = Value;
return(TRUE);
}
BOOLEAN WmiValidateRange(
IN struct _DATA_ITEM_DESCRIPTION *DataItemDesc,
OUT PULONG64 Number,
IN PTCHAR Text
)
/*+++
Routine Description:
This routine will validate that the value proposed for the property is
correct. It checks that the value is a well formed number and within
the appropriate range
Arguments:
DataItemDesc is the data item description for the property being validated
*Number returns with the value as a ULONG64
Text is the proposed value for the property. Note that hex values are
required to be preceeded with 0x
Return Value:
TRUE if Value is appropriate for the property
---*/
{
#define HexMarkerText TEXT("0x")
BOOLEAN ReturnStatus;
PTCHAR s;
PRANGELISTINFO RangeListInfo;
PRANGEINFO RangeInfo;
ULONG i;
WmiAssert(DataItemDesc != NULL);
WmiAssert(Number != NULL);
WmiAssert(Text != NULL);
//
// Skip over any leading spaces
//
s = Text;
while (IsWhiteSpace(*s) && (*s != 0))
{
s++;
}
if (*s != 0)
{
//
// If this is not an empty string then go parse the number
//
if (_tcsnicmp(s,
HexMarkerText,
(sizeof(HexMarkerText) / sizeof(TCHAR))-1) == 0)
{
//
// this is a hex number (starts with 0x), advance string ptr
// and setup to use hex digit validation
//
s += (sizeof(HexMarkerText) / sizeof(TCHAR)) - 1;
ReturnStatus = WmiHexToUlong64(s, Number);
} else {
*Number = _ttoi64(s);
ReturnStatus = TRUE;
while ((*s != 0) && ReturnStatus)
{
ReturnStatus = (_istdigit(*s) != 0);
s++;
}
}
//
// Make sure that all characters are digits
//
if (ReturnStatus)
{
//
// Now verify that the value is within the correct range
//
RangeListInfo = DataItemDesc->RangeListInfo;
WmiAssert(RangeListInfo != NULL);
ReturnStatus = FALSE;
for (i = 0; (i < RangeListInfo->Count) && (! ReturnStatus); i++)
{
RangeInfo = &RangeListInfo->Ranges[i];
ReturnStatus = ( (*Number >= RangeInfo->Minimum) &&
(*Number <= RangeInfo->Maximum) );
}
}
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiValidateDateTime(
IN struct _DATA_ITEM_DESCRIPTION *DataItemDesc,
IN PTCHAR Value
)
/*+++
Routine Description:
This routine will validate that the value proposed for the property is
correct. It will make sure that it is in a valid format for a
DATETIME with is of the form 19940525133015.000000-300
Arguments:
DataItemDesc is the data item description for the property being validated
Value is the proposed value for the property
Return Value:
TRUE if Value is appropriate for the property
---*/
{
#define DATETIME_LENGTH 25
ULONG Length;
BOOLEAN ReturnStatus;
ULONG i;
WmiAssert(DataItemDesc != NULL);
WmiAssert(Value != NULL);
//
// Validate that datetime is in correct format
// TODO: Validate that the component parts of the DATETIME are correct,
// for example that the month is between 1 and 12, the correct
// month doesn't have too many days, The time is ok (not 30:11)
//
Length = _tcslen(Value);
if (Length == DATETIME_LENGTH)
{
ReturnStatus = TRUE;
for (i = 0; (i < 14) && ReturnStatus; i++)
{
ReturnStatus = (_istdigit(Value[i]) != 0);
}
if (ReturnStatus)
{
ReturnStatus = (Value[14] == TEXT('.')) &&
((Value[21] == TEXT('-')) ||
(Value[21] == TEXT('+')) );
if (ReturnStatus)
{
for (i = 22; (i < DATETIME_LENGTH) && ReturnStatus; i++)
{
ReturnStatus = (_istdigit(Value[i]) != 0);
}
}
}
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiGet8bitFromVariant(
VARIANT *Value,
PVOID Result
)
{
BOOLEAN ReturnStatus;
ReturnStatus = TRUE;
//
// 8 bit values can come back as signed or unsigned
// or as 16 or 32 bit values
//
switch(Value->vt)
{
case VT_I1:
{
*((PCHAR)Result) = Value->cVal;
break;
}
case VT_UI1:
{
*((PUCHAR)Result) = Value->bVal;
break;
}
case VT_I2:
{
*((PCHAR)Result) = (CHAR)Value->iVal;
break;
}
case VT_I4:
{
*((PCHAR)Result) = (CHAR)Value->lVal;
break;
}
default:
{
ReturnStatus = FALSE;
}
}
return(ReturnStatus);
}
BOOLEAN WmiGet16bitFromVariant(
VARIANT *Value,
PVOID Result
)
{
BOOLEAN ReturnStatus;
ReturnStatus = TRUE;
//
// 16 bit values can come back as signed or unsigned
// or as 32 bit values
//
switch(Value->vt)
{
case VT_I2:
{
*((PSHORT)Result) = Value->iVal;
break;
}
case VT_UI2:
{
*((PUSHORT)Result) = Value->uiVal;
break;
}
case VT_I4:
{
*((PSHORT)Result) = (SHORT)Value->lVal;
break;
}
default:
{
ReturnStatus = FALSE;
}
}
return(ReturnStatus);
}
BOOLEAN WmiGet32bitFromVariant(
VARIANT *Value,
PVOID Result
)
{
BOOLEAN ReturnStatus;
ReturnStatus = TRUE;
//
// 32 bit values can come back as signed or unsigned
//
switch (Value->vt)
{
case VT_UI4:
{
*((PULONG)Result) = Value->ulVal;
break;
}
case VT_I4:
{
*((PLONG)Result) = Value->lVal;
break;
}
default:
{
ReturnStatus = FALSE;
}
}
return(ReturnStatus);
}
BOOLEAN WmiGetSint64FromVariant(
VARIANT *Value,
PVOID Result
)
{
BOOLEAN ReturnStatus;
ReturnStatus = TRUE;
//
// 64 bit numbers are returned in a BSTR with the
// number represented as a string. So we need to
// convert back to a 64bit number.
//
WmiAssert(Value->vt == VT_BSTR);
*((PLONGLONG)Result) = _ttoi64(Value->bstrVal);
return(ReturnStatus);
}
BOOLEAN WmiGetUint64FromVariant(
VARIANT *Value,
PVOID Result
)
{
BOOLEAN ReturnStatus;
ReturnStatus = TRUE;
//
// 64 bit numbers are returned in a BSTR with the
// number represented as a string. So we need to
// convert back to a 64bit number.
//
WmiAssert(Value->vt == VT_BSTR);
*((PULONGLONG)Result) = _ttoi64(Value->bstrVal);
return(ReturnStatus);
}
BOOLEAN WmiGetBooleanFromVariant(
VARIANT *Value,
PVOID Result
)
{
BOOLEAN ReturnStatus;
ReturnStatus = TRUE;
//
// BOOLEAN values are true or false
//
WmiAssert(Value->vt == VT_BOOL);
*((PBOOLEAN)Result) = (Value->boolVal != 0) ?
1 : 0;
return(ReturnStatus);
}
BOOLEAN WmiGetStringFromVariant(
VARIANT *Value,
PVOID Result
)
{
BOOLEAN ReturnStatus;
WmiAssert( *((PTCHAR)Result) == NULL);
ReturnStatus = WmiBstrToTchar((PTCHAR *)Result,
Value->bstrVal);
return(ReturnStatus);
}
BOOLEAN WmiGetObjectFromVariant(
VARIANT *Value,
PVOID Result
)
{
IUnknown *punk;
HRESULT hr;
punk = Value->punkVal;
hr = punk->QueryInterface(IID_IWbemClassObject,
(PVOID *)Result);
return(hr == WBEM_S_NO_ERROR);
}
ULONG WmiGetElementSize(
CIMTYPE CimType
)
{
ULONG Size;
switch(CimType)
{
case CIM_UINT8:
case CIM_SINT8:
{
Size = sizeof(CHAR);
break;
}
case CIM_CHAR16:
case CIM_UINT16:
case CIM_SINT16:
{
Size = sizeof(SHORT);
break;
}
case CIM_UINT32:
case CIM_SINT32:
{
Size = sizeof(LONG);
break;
}
case CIM_SINT64:
{
Size = sizeof(LONGLONG);
break;
}
case CIM_UINT64:
{
Size = sizeof(ULONGLONG);
break;
}
case CIM_BOOLEAN:
{
Size = sizeof(BOOLEAN);
break;
}
case CIM_DATETIME:
case CIM_STRING:
{
Size = sizeof(PTCHAR);
break;
}
case CIM_OBJECT:
{
Size = sizeof(IWbemClassObject *);
break;
}
//
// Floating point values not supported
//
case CIM_REAL32:
case CIM_REAL64:
default:
{
Size = 0;
break;
}
}
return(Size);
}
typedef BOOLEAN (*GETVALUEFROMVARIANTFUNC)(
VARIANT *Value,
PVOID Result
);
BOOLEAN WmiGetValueFunc(
CIMTYPE CimType,
GETVALUEFROMVARIANTFUNC *GetValueFunc
)
{
BOOLEAN ReturnStatus;
ReturnStatus = TRUE;
switch(CimType)
{
case CIM_UINT8:
case CIM_SINT8:
{
*GetValueFunc = WmiGet8bitFromVariant;
break;
}
case CIM_CHAR16:
case CIM_UINT16:
case CIM_SINT16:
{
*GetValueFunc = WmiGet16bitFromVariant;
break;
}
case CIM_UINT32:
case CIM_SINT32:
{
*GetValueFunc = WmiGet32bitFromVariant;
break;
}
case CIM_SINT64:
{
*GetValueFunc = WmiGetSint64FromVariant;
break;
}
case CIM_UINT64:
{
*GetValueFunc = WmiGetUint64FromVariant;
break;
}
case CIM_BOOLEAN:
{
*GetValueFunc = WmiGetBooleanFromVariant;
break;
}
case CIM_DATETIME:
case CIM_STRING:
{
*GetValueFunc = WmiGetStringFromVariant;
break;
}
case CIM_OBJECT:
{
*GetValueFunc = WmiGetObjectFromVariant;
break;
}
//
// Floating point values not supported
//
case CIM_REAL32:
case CIM_REAL64:
default:
{
*GetValueFunc = NULL;
ReturnStatus = FALSE;
break;
}
}
return(ReturnStatus);
}
BOOLEAN WmiRefreshDataItemFromWbem(
IN OUT PDATA_ITEM_DESCRIPTION DataItemDesc,
IN IWbemClassObject *pIWbemClassObject
)
/*+++
Routine Description:
This routine will call WBEM to get the latest value for the property
represented by the DataItemDesc
Arguments:
DataItemDesc is the data item description for the property
pIWbemClassObject is the instance class object interface for the class
Return Value:
TRUE if successful
---*/
{
ULONG i;
LONG i1;
BSTR s;
HRESULT hr;
VARIANT Value;
CIMTYPE ValueType;
BOOLEAN ReturnStatus;
ULONG ElementSize;
GETVALUEFROMVARIANTFUNC GetValueFunc;
WmiAssert(DataItemDesc != NULL);
WmiAssert(pIWbemClassObject != NULL);
DebugPrint((1,"WMI: Refreshing data item %ws\n", DataItemDesc->Name));
ReturnStatus = FALSE;
s = SysAllocString(DataItemDesc->Name);
if (s != NULL)
{
hr = pIWbemClassObject->Get(s,
0,
&Value,
&ValueType,
NULL);
if (hr == WBEM_S_NO_ERROR)
{
DebugPrint((1, "WMIPROP: Got value for %ws as variant type 0x%x, cim type 0x%x at variant %p\n",
s, Value.vt, ValueType, &Value));
WmiAssert((ValueType & ~CIM_FLAG_ARRAY) == DataItemDesc->DataType);
WmiCleanDataItemDescData(DataItemDesc);
if ( (ValueType & CIM_FLAG_ARRAY) == 0)
{
//
// Non Array value, just pull the value out of the variant
// and stash into DataItemDesc
//
WmiAssert(DataItemDesc->IsVariableArray == 0);
WmiAssert(DataItemDesc->IsFixedArray == 0);
//
// For all types we get the getvalue
// function and the pull the value out of the
// variant and into the DataItemDesc
//
if (WmiGetValueFunc(DataItemDesc->DataType,
&GetValueFunc))
{
//
// TODO: Keep track of data item position and
// padding within data block
//
ReturnStatus = (*GetValueFunc)(
&Value,
(PVOID)&DataItemDesc->Data);
#if DBG
if (ReturnStatus == FALSE)
{
DebugPrint((1, "WMIPROP: Property %ws is type %d, but got type %d variant %p\n",
DataItemDesc->Name,
DataItemDesc->DataType,
Value.vt, &Value));
WmiAssert(FALSE);
}
#endif
}
} else {
//
// Get all of the data for an array
//
LONG LBound, UBound, NumberElements;
PUCHAR Array;
LONG Index;
VARIANT Element;
ULONG ElementSize;
ULONG SizeNeeded;
VARTYPE vt;
WmiAssert((DataItemDesc->IsVariableArray != 0) ||
(DataItemDesc->IsFixedArray != 0));
WmiAssert(Value.vt & VT_ARRAY);
if (WmiGetArraySize(Value.parray,
&LBound,
&UBound,
&NumberElements))
{
if (WmiGetValueFunc(DataItemDesc->DataType,
&GetValueFunc))
{
//
// The size of each element is not allowed to
// change, but the number of elements are
//
WmiAssert(DataItemDesc->ArrayPtr == NULL);
ElementSize = DataItemDesc->DataSize;
SizeNeeded = NumberElements * ElementSize;
Array = (PUCHAR)LocalAlloc(LPTR, SizeNeeded);
DataItemDesc->ArrayElementCount = NumberElements;
DebugPrint((1,"WMIPROP: Alloc 0x%x bytes at %p\n", SizeNeeded, Array));
memset(Array, 0, SizeNeeded);
if (Array != NULL)
{
// CONSIDER: Use SafeArrayAccessData for number
// types
//
// Now that we have memory for the array data
// extract the data from the safe array and
// store it in the C array
//
DataItemDesc->ArrayPtr = (PVOID)Array;
hr = SafeArrayGetVartype(Value.parray,
&vt);
if (hr == WBEM_S_NO_ERROR)
{
ReturnStatus = TRUE;
for (i1 = 0, Index = LBound;
(i1 < NumberElements) && ReturnStatus;
i1++, Index++)
{
VariantInit(&Element);
Element.vt = vt;
hr = SafeArrayGetElement(Value.parray,
&Index,
&Element.boolVal);
if (hr == WBEM_S_NO_ERROR)
{
Element.vt = vt;
DebugPrint((1, "WMIPROP: GetValueFunc at %p\n", Array));
ReturnStatus = (*GetValueFunc)(
&Element,
(PVOID)Array);
Array += ElementSize;
} else {
ReturnStatus = FALSE;
}
}
}
}
} else {
DebugPrint((1, "WMIPROP: Property %ws is array of type %d, but got type %d variant %p\n",
DataItemDesc->Name,
DataItemDesc->DataType,
Value.vt, &Value));
WmiAssert(FALSE);
}
}
}
VariantClear(&Value);
}
SysFreeString(s);
}
return(ReturnStatus);
}
BOOLEAN WmiRefreshDataBlockFromWbem(
IN IWbemClassObject *pIWbemClassObject,
IN OUT PDATA_BLOCK_DESCRIPTION DataBlockDesc
)
/*+++
Routine Description:
This routine will call WBEM to get the latest values for all property
in data block represented by the DataBlockDesc
Arguments:
DataBlockDesc is the data item description for the class
pIWbemClassObject is the instance class object interface for the class
Return Value:
TRUE if successful
---*/
{
PDATA_ITEM_DESCRIPTION DataItemDesc;
BOOLEAN ReturnStatus;
ULONG i;
WmiAssert(DataBlockDesc != NULL);
WmiAssert(pIWbemClassObject != NULL);
ReturnStatus = TRUE;
for (i = 0; (i < DataBlockDesc->DataItemCount) && ReturnStatus; i++)
{
DataItemDesc = &DataBlockDesc->DataItems[i];
ReturnStatus = WmiRefreshDataItemFromWbem(DataItemDesc,
pIWbemClassObject);
}
return(ReturnStatus);
}
VARTYPE WmiVarTypeForCimType(
CIMTYPE CimType
)
{
VARTYPE vt;
//
// Most things match their CIM types, except those below
vt = (VARTYPE)CimType;
switch(CimType)
{
case CIM_UINT8:
case CIM_SINT8:
{
vt = VT_I4;
break;
}
case CIM_CHAR16:
case CIM_UINT16:
{
vt = VT_I2;
break;
}
case CIM_UINT32:
{
vt = VT_I4;
break;
}
case CIM_STRING:
case CIM_DATETIME:
case CIM_SINT64:
case CIM_UINT64:
{
vt = VT_BSTR;
break;
}
case CIM_OBJECT:
{
vt = VT_UNKNOWN;
break;
}
case CIM_BOOLEAN:
{
vt = VT_BOOL;
break;
}
}
return(vt);
}
typedef BOOLEAN (*SETVALUEFUNC)(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
);
BOOLEAN WmiSetBooleanValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
BOOLEAN Value;
//
// A boolean needs to ve expressed as a VARIANT_TRUE or VARIANT_FALSE
//
Value = *((PBOOLEAN)DataPtr);
*((VARIANT_BOOL *)DestPtr) = Value ? VARIANT_TRUE : VARIANT_FALSE;
*SetPtr = (PVOID)DestPtr;
return(TRUE);
}
BOOLEAN WmiSetStringValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
BSTR s;
PTCHAR String;
BOOLEAN ReturnStatus;
//
// Strings must be converted to BSTR
//
String = *((PTCHAR *)DataPtr);
WmiAssert(String != NULL);
s = SysAllocString(String);
if (s != NULL)
{
*((BSTR *)DestPtr) = s;
*SetPtr = (PVOID)s;
ReturnStatus = TRUE;
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiSetEmbeddedValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
IUnknown *pUnk;
IWbemClassObject *pIWbemClassObject;
HRESULT hr;
BOOLEAN ReturnStatus;
//
// QI for IUnknown since we are expected to put the IUnknown into
// the property.
//
pIWbemClassObject = *((IWbemClassObject **)DataPtr);
hr = pIWbemClassObject->QueryInterface(IID_IUnknown,
(PVOID *)&pUnk);
if (hr == WBEM_S_NO_ERROR)
{
*((IUnknown **)DestPtr) = pUnk;
*SetPtr = (PVOID)pUnk;
ReturnStatus = TRUE;
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiSetSint8ValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
//
// CHARs must be expressed as a LONG to keep WBEM happy
//
*((LONG *)DestPtr) = (LONG)(*((CHAR *)DataPtr));
*SetPtr = (PVOID)DestPtr;
return(TRUE);
}
BOOLEAN WmiSetUint8ValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
//
// UCHARs must be expressed as a LONG to keep WBEM happy
//
*((LONG *)DestPtr) = (LONG)(*((UCHAR *)DataPtr));
*SetPtr = (PVOID)DestPtr;
return(TRUE);
}
BOOLEAN WmiSetSint16ValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
//
// SHORTs must be expressed as a SHORT to keep WBEM happy
//
*((SHORT *)DestPtr) = (*((SHORT *)DataPtr));
*SetPtr = (PVOID)DestPtr;
return(TRUE);
}
BOOLEAN WmiSetUint16ValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
//
// USHORTs must be expressed as a SHORT to keep WBEM happy
//
*((SHORT *)DestPtr) = (SHORT)(*((USHORT *)DataPtr));
*SetPtr = (PVOID)DestPtr;
return(TRUE);
}
BOOLEAN WmiSetSint32ValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
//
// LONGs must be expressed as a LONG to keep WBEM happy
//
*((LONG *)DestPtr) = (*((LONG *)DataPtr));
*SetPtr = (PVOID)DestPtr;
return(TRUE);
}
BOOLEAN WmiSetUint32ValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
//
// ULONGs must be expressed as a LONG to keep WBEM happy
//
*((LONG *)DestPtr) = (ULONG)(*((ULONG *)DataPtr));
*SetPtr = (PVOID)DestPtr;
return(TRUE);
}
BOOLEAN WmiSetSint64ValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
TCHAR Text[MAX_PATH];
BSTR s;
BOOLEAN ReturnStatus;
//
// 64 bit values must be set via a BSTR
//
wsprintf(Text, TEXT("%ld"), *((LONGLONG *)DataPtr));
s = SysAllocString(Text);
if (s != NULL)
{
*((BSTR *)DestPtr) = s;
*SetPtr = (PVOID)s;
ReturnStatus = TRUE;
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiSetUint64ValueFunc(
PVOID DataPtr,
PVOID DestPtr,
PVOID *SetPtr
)
{
TCHAR Text[MAX_PATH];
BSTR s;
BOOLEAN ReturnStatus;
//
// 64 bit values must be set via a BSTR
//
wsprintf(Text, TEXT("%ld"), *((ULONGLONG *)DataPtr));
s = SysAllocString(Text);
if (s != NULL)
{
*((BSTR *)DestPtr) = s;
*SetPtr = (PVOID)s;
ReturnStatus = TRUE;
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
SETVALUEFUNC WmiGetSetValueFunc(
CIMTYPE CimType
)
{
SETVALUEFUNC SetValueFunc;
switch(CimType)
{
case CIM_SINT8:
{
SetValueFunc = WmiSetSint8ValueFunc;
break;
}
case CIM_UINT8:
{
SetValueFunc = WmiSetUint8ValueFunc;
break;
}
case CIM_CHAR16:
case CIM_SINT16:
{
SetValueFunc = WmiSetSint16ValueFunc;
break;
}
case CIM_UINT16:
{
SetValueFunc = WmiSetUint16ValueFunc;
break;
}
case CIM_SINT32:
{
SetValueFunc = WmiSetSint32ValueFunc;
break;
}
case CIM_UINT32:
{
SetValueFunc = WmiSetUint32ValueFunc;
break;
}
case CIM_SINT64:
{
SetValueFunc = WmiSetSint64ValueFunc;
break;
}
case CIM_UINT64:
{
SetValueFunc = WmiSetUint64ValueFunc;
break;
}
case CIM_BOOLEAN:
{
SetValueFunc = WmiSetBooleanValueFunc;
break;
}
case CIM_DATETIME:
case CIM_STRING:
{
SetValueFunc = WmiSetStringValueFunc;
break;
}
case CIM_OBJECT:
{
SetValueFunc = WmiSetEmbeddedValueFunc;
break;
}
default:
{
SetValueFunc = NULL;
break;
}
}
return(SetValueFunc);
}
BOOLEAN WmiAssignToVariantFromDataItem(
OUT VARIANT *NewValue,
IN PDATA_ITEM_DESCRIPTION DataItemDesc
)
/*+++
Routine Description:
This routine will assign the value for a property from the DataItemDesc
into an initied variant. It will figure out all of the strange rules
for what types of variants WBEM likes for different data types.
Arguments:
DataBlockDesc is the data item description for the class
pIWbemClassObject is the instance class object interface for the class
Return Value:
TRUE if successful
---*/
{
BOOLEAN ReturnStatus;
BSTR s;
TCHAR Text[MAX_PATH];
SETVALUEFUNC SetValueFunc;
VARTYPE vt;
PVOID SetPtr;
WmiAssert(NewValue != NULL);
WmiAssert(DataItemDesc != NULL);
SetValueFunc = WmiGetSetValueFunc(DataItemDesc->DataType);
if (SetValueFunc != NULL)
{
ReturnStatus = TRUE;
vt = WmiVarTypeForCimType(DataItemDesc->DataType);
if ((DataItemDesc->IsFixedArray == 0) &&
(DataItemDesc->IsVariableArray == 0))
{
//
// This is a non array case
//
NewValue->vt = vt;
ReturnStatus = (*SetValueFunc)((PVOID)&DataItemDesc->Data,
&NewValue->lVal,
&SetPtr);
} else {
//
// This is an array, so we need to create a safe array in order to
// call WBEM.
//
SAFEARRAY *SafeArray;
PUCHAR DataArray;
PVOID DataPtr;
PVOID Temp;
HRESULT hr;
ULONG i;
//
// We do not support arrays of embedded classes
//
SafeArray = SafeArrayCreateVector(vt,
0,
DataItemDesc->ArrayElementCount);
if (SafeArray != NULL)
{
DataArray = (PUCHAR)DataItemDesc->ArrayPtr;
WmiAssert(DataArray != NULL);
ReturnStatus = TRUE;
for (i = 0;
(i < DataItemDesc->ArrayElementCount) && ReturnStatus;
i++)
{
ReturnStatus = (*SetValueFunc)(DataArray, &Temp, &SetPtr);
if (ReturnStatus)
{
hr = SafeArrayPutElement(SafeArray,
(PLONG)&i,
SetPtr);
if (hr == WBEM_S_NO_ERROR)
{
DataArray += DataItemDesc->DataSize;
} else {
ReturnStatus = FALSE;
}
}
}
if (ReturnStatus == FALSE)
{
//
// if we failed to build the safearray we need to clean
// it up.
//
SafeArrayDestroy(SafeArray);
} else {
NewValue->vt = vt | VT_ARRAY;
NewValue->parray = SafeArray;
}
} else {
ReturnStatus = FALSE;
}
}
} else {
WmiAssert(FALSE);
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiRefreshWbemFromDataItem(
IN IWbemServices *pIWbemServices,
IN IWbemClassObject *pIWbemClassObject,
IN PDATA_ITEM_DESCRIPTION DataItemDesc
)
/*+++
Routine Description:
This routine will update the WBEM property with the value specified in
the DataItemDesc.
Arguments:
DataItemDesc is the data item description for the property
pIWbemClassObject is the instance class object interface for the class
Return Value:
TRUE if successful
---*/
{
VARIANT NewValue;
BOOLEAN ReturnStatus;
HRESULT hr;
BSTR s;
WmiAssert(pIWbemClassObject != NULL);
WmiAssert(DataItemDesc != NULL);
ReturnStatus = TRUE;
if (DataItemDesc->IsReadOnly == 0)
{
//
// Property is not read only so we want to try to update it
//
//
// Now build the value into a variant and call WBEM to get him
// to update it.
//
VariantInit(&NewValue);
ReturnStatus = WmiAssignToVariantFromDataItem(&NewValue,
DataItemDesc);
//
// if we need to update the value of the property do so and then
// free up the variant
//
if (ReturnStatus)
{
s = SysAllocString(DataItemDesc->Name);
if (s != NULL)
{
DebugPrint((1, "WMIPROP: Property %ws (%p) being updated to 0x%x (type 0x%x)\n",
DataItemDesc->Name,
DataItemDesc,
NewValue.ulVal,
NewValue.vt));
hr = pIWbemClassObject->Put(s,
0,
&NewValue,
0);
#if DBG
if (hr != WBEM_S_NO_ERROR)
{
DebugPrint((1, "WMIPROP: Property %ws (%p) Error %x from pIWbemClassObejct->Put\n",
DataItemDesc->Name,
DataItemDesc,
hr));
}
#endif
SysFreeString(s);
}
VariantClear(&NewValue);
}
}
return(ReturnStatus);
}
BOOLEAN WmiRefreshWbemFromDataBlock(
IN IWbemServices *pIWbemServices,
IN IWbemClassObject *pIWbemClassObject,
IN PDATA_BLOCK_DESCRIPTION DataBlockDesc,
IN BOOLEAN IsEmbeddedClass
)
/*+++
Routine Description:
This routine will update the WBEM class with the values specified in
the DataBlockDesc. If the class is not an embedded (ie, top level) then
it will put the instance which will update the values in the schema and
call the provider (ie, device driver).
Arguments:
pIWbemServices is the Wbem Service interface
pIWbemClassObject is the instance class object interface for the class
DataBlockDesc is the data block description for the class
IsEmbeddedClass is TRUE if the class is an embedeed class.
Return Value:
TRUE if successful
---*/
{
ULONG i;
PDATA_ITEM_DESCRIPTION DataItemDesc;
BOOLEAN ReturnStatus;
HRESULT hr;
WmiAssert(pIWbemServices != NULL);
WmiAssert(pIWbemClassObject != NULL);
WmiAssert(DataBlockDesc != NULL);
ReturnStatus = TRUE;
for (i = 0; (i < DataBlockDesc->DataItemCount) && ReturnStatus; i++)
{
DataItemDesc = &DataBlockDesc->DataItems[i];
ReturnStatus = WmiRefreshWbemFromDataItem(pIWbemServices,
pIWbemClassObject,
DataItemDesc);
}
if ((ReturnStatus) && (! IsEmbeddedClass))
{
//
// No need to do PutInsance on embedded classes, only top level ones
//
hr = pIWbemServices->PutInstance(pIWbemClassObject,
WBEM_FLAG_UPDATE_ONLY,
NULL,
NULL);
#if DBG
if (hr != WBEM_S_NO_ERROR)
{
DebugPrint((1, "WMIPROP: Error %x returned from PutInstance for %ws (%p)\n",
hr, DataBlockDesc->Name, DataBlockDesc));
}
#endif
ReturnStatus = (hr == WBEM_S_NO_ERROR);
}
return(ReturnStatus);
}
PTCHAR WmiGetDeviceInstanceId(
IN HDEVINFO deviceInfoSet,
IN PSP_DEVINFO_DATA deviceInfoData,
IN HANDLE MachineHandle
)
/*+++
Routine Description:
This routine will obtain the device instance id for the device that
we are working with.
Arguments:
deviceInfoSet
deviceInfoData
Return Value:
returns pointer to device instance id or NULL if unavailable
---*/
{
ULONG Status;
PTCHAR Id;
ULONG SizeNeeded;
WmiAssert(deviceInfoSet != NULL);
WmiAssert(deviceInfoData != NULL);
SizeNeeded = (MAX_DEVICE_ID_LEN + 1) * sizeof(TCHAR);
Id = (PTCHAR)LocalAlloc(LPTR, SizeNeeded);
if (Id != NULL)
{
Status = CM_Get_Device_ID_Ex(deviceInfoData->DevInst,
Id,
SizeNeeded / sizeof(TCHAR),
0,
MachineHandle);
if (Status != CR_SUCCESS)
{
DebugPrint((1, "WMIPROP: CM_Get_Device_ID_Ex returned %d\n",
Status));
LocalFree(Id);
Id = NULL;
}
} else {
DebugPrint((1, "WMIPROP: Could not alloc for device Id\n"));
}
return(Id);
}
PTCHAR WmiGetDeviceInstanceName(
IN HDEVINFO deviceInfoSet,
IN PSP_DEVINFO_DATA deviceInfoData,
IN HANDLE MachineHandle
)
/*+++
Routine Description:
This routine will obtain the WMI instance name id for the device that
we are working with.
Arguments:
deviceInfoSet
deviceInfoData
Return Value:
returns pointer to device instance name or NULL if unavailable
---*/
{
#define InstanceNumberText TEXT("_0")
PTCHAR Id, in, s;
PTCHAR InstanceName;
ULONG SizeNeeded;
WmiAssert(deviceInfoSet != NULL);
WmiAssert(deviceInfoData != NULL);
InstanceName = NULL;
Id = WmiGetDeviceInstanceId(deviceInfoSet,
deviceInfoData,
MachineHandle);
if (Id != NULL)
{
//
// We need to play some games with the device id to make it into
// a WMI instance name.
//
// 1. We need to convert any "\\" in the instance name to "\\\\".
// For some reason wbem likes it this way.
// 2. We need to append a "_0" to the end to indicate the instance
// number we are dealing with.
s = Id;
SizeNeeded = (_tcslen(Id) * sizeof(TCHAR)) +
sizeof(InstanceNumberText);
while (*s != 0)
{
if (*s++ == TEXT('\\'))
{
SizeNeeded += sizeof(TCHAR);
}
}
InstanceName = (PTCHAR)LocalAlloc(LPTR, SizeNeeded);
if (InstanceName != NULL)
{
in = InstanceName;
s = Id;
while (*s != 0)
{
*in++ = *s;
if (*s++ == TEXT('\\'))
{
*in++ = TEXT('\\');
}
}
_tcscat(InstanceName, InstanceNumberText);
}
LocalFree(Id);
}
return(InstanceName);
}
BOOLEAN WmiGetQualifier(
IN IWbemQualifierSet *pIWbemQualifierSet,
IN PTCHAR QualifierName,
IN VARTYPE Type,
OUT 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
Return Value:
returns pointer to device instance name or NULL if unavailable
---*/
{
BSTR s;
HRESULT hr;
BOOLEAN ReturnStatus;
WmiAssert(pIWbemQualifierSet != NULL);
WmiAssert(QualifierName != NULL);
WmiAssert(Value != NULL);
s = SysAllocString(QualifierName);
if (s != NULL)
{
hr = pIWbemQualifierSet->Get(s,
0,
Value,
NULL);
if (hr == WBEM_S_NO_ERROR)
{
ReturnStatus = ((Value->vt & ~CIM_FLAG_ARRAY) == Type);
} else {
ReturnStatus = FALSE;
}
SysFreeString(s);
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiParseRange(
OUT PRANGEINFO RangeInfo,
IN BSTR Range
)
/*+++
Routine Description:
This routine will parse a range specified in the for x or x - y. The
former means the value x and the latter means from x to y.
Arguments:
*RangeInfo returns with the range specified
Range is the text representation of the range
Return Value:
TRUE if successful else FALSE
---*/
{
#define RangeSeparator TEXT('-')
#define Space TEXT(' ')
#define MAX_RANGE_VALUE_LENGTH 64
LONG64 BeginValue, EndValue;
TCHAR *s;
TCHAR *d;
TCHAR ValueText[MAX_RANGE_VALUE_LENGTH];
ULONG i;
BOOLEAN ReturnStatus;
WmiAssert(RangeInfo != NULL);
WmiAssert(Range != NULL);
//
// Obtain the beginning value by copying up to the separator and
// then converting to a number
//
s = Range;
d = ValueText;
i = 0;
while ((*s != 0) && (*s != RangeSeparator) && (*s != Space) &&
(i < MAX_RANGE_VALUE_LENGTH))
{
*d++ = *s++;
i++;
}
*d = 0;
if (i < MAX_RANGE_VALUE_LENGTH)
{
BeginValue = _ttoi64(ValueText);
EndValue = BeginValue;
if (*s != 0)
{
//
// Skip to the beginning of the next number
//
while ( (*s != 0) &&
((*s == RangeSeparator) || (*s == Space)) )
{
s++;
}
if (*s != 0)
{
//
// We do have a second number, copy it out
//
d = ValueText;
i = 0;
while ((*s != 0) && (*s != Space) &&
(i < MAX_RANGE_VALUE_LENGTH))
{
*d++ = *s++;
i++;
}
*d = 0;
if (*s == 0)
{
EndValue = _ttoi64(ValueText);
}
}
}
//
// Fill out the output RangeInfo making sure that the smaller value
// is placed in the miniumum and larger in the maximum.
//
if (BeginValue < EndValue)
{
RangeInfo->Minimum = BeginValue;
RangeInfo->Maximum = EndValue;
} else {
RangeInfo->Minimum = EndValue;
RangeInfo->Maximum = BeginValue;
}
ReturnStatus = TRUE;
} else {
//
// if range text is too long then give up
//
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiRangeProperty(
IN IWbemQualifierSet *pIWbemQualifierSet,
OUT PDATA_ITEM_DESCRIPTION DataItemDesc
)
/*+++
Routine Description:
This routine will obtain information about the valid ranges of values
for the data item
Arguments:
pIWbemQualifierSet is the qualifier set object
DataItemDesc gets filled with info about ranges
Return Value:
TRUE if successful else FALSE
---*/
{
#define RangeText TEXT("Range")
VARIANT Range;
BSTR RangeData;
LONG RangeLBound, RangeUBound, RangeElements;
LONG i, Index;
HRESULT hr;
ULONG SizeNeeded;
PRANGELISTINFO RangeListInfo;
BOOLEAN ReturnStatus;
WmiAssert(pIWbemQualifierSet != NULL);
WmiAssert(DataItemDesc != NULL);
if (WmiGetQualifier(pIWbemQualifierSet,
RangeText,
VT_BSTR, // array
&Range))
{
if (Range.vt & CIM_FLAG_ARRAY)
{
//
// Array of ranges
//
if (WmiGetArraySize(Range.parray,
&RangeLBound,
&RangeUBound,
&RangeElements))
{
SizeNeeded = sizeof(RANGELISTINFO) +
(RangeElements * sizeof(RANGEINFO));
RangeListInfo = (PRANGELISTINFO)LocalAlloc(LPTR, SizeNeeded);
if (RangeListInfo != NULL)
{
ReturnStatus = TRUE;
DataItemDesc->RangeListInfo = RangeListInfo;
RangeListInfo->Count = RangeElements;
for (i = 0; (i < RangeElements) && ReturnStatus; i++)
{
Index = i + RangeLBound;
hr = SafeArrayGetElement(Range.parray,
&Index,
&RangeData);
if (hr == WBEM_S_NO_ERROR)
{
ReturnStatus = WmiParseRange(
&RangeListInfo->Ranges[i],
RangeData);
#if DBG
if (ReturnStatus == FALSE)
{
DebugPrint((1, "WMIPROP: Error parsing range %ws\n",
RangeData));
}
#endif
} else {
ReturnStatus = FALSE;
}
}
} else {
ReturnStatus = FALSE;
}
} else {
ReturnStatus = FALSE;
}
} else {
//
// Single range
//
RangeListInfo = (PRANGELISTINFO)LocalAlloc(LPTR, sizeof(RANGELISTINFO));
if (RangeListInfo != NULL)
{
DataItemDesc->RangeListInfo = RangeListInfo;
RangeListInfo->Count = 1;
ReturnStatus = WmiParseRange(&RangeListInfo->Ranges[0],
Range.bstrVal);
} else {
ReturnStatus = FALSE;
}
}
VariantClear(&Range);
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
BOOLEAN WmiValueMapProperty(
IN IWbemQualifierSet *pIWbemQualifierSet,
OUT PDATA_ITEM_DESCRIPTION DataItemDesc
)
/*+++
Routine Description:
This routine will obtain information about the enumeration values for
the data block
Arguments:
pIWbemQualifierSet is the qualifier set object
DataItemDesc gets filled with info about enumerations
Return Value:
TRUE if successful else FALSE
---*/
{
#define ValueMapText TEXT("ValueMap")
#define ValuesText TEXT("Values")
VARIANT Values, ValueMap;
BSTR ValuesData, ValueMapData;
BOOLEAN ReturnStatus = FALSE;
VARTYPE ValuesType, ValueMapType;
LONG ValuesUBound, ValuesLBound, ValuesSize;
LONG ValueMapUBound, ValueMapLBound, ValueMapSize;
ULONG SizeNeeded;
PENUMERATIONINFO EnumerationInfo;
LONG i;
LONG Index;
HRESULT hr;
WmiAssert(pIWbemQualifierSet != NULL);
WmiAssert(DataItemDesc != NULL);
//
// Get the Values and ValueMap qualifier values. These can be single
// strings or arrays of strings.
//
if ((WmiGetQualifier(pIWbemQualifierSet,
ValuesText,
VT_BSTR, // array
&Values)) &&
(WmiGetQualifier(pIWbemQualifierSet,
ValueMapText,
VT_BSTR, // array
&ValueMap)))
{
//
// if we've got both qualifiers then we can do value map, make sure
// that both of them are strings and are either scalar or arrays with
// the same length.
//
ValuesType = Values.vt & ~CIM_FLAG_ARRAY;
ValueMapType = ValueMap.vt & ~CIM_FLAG_ARRAY;
if ((ValuesType == CIM_STRING) &&
(ValueMapType == CIM_STRING) &&
(Values.vt == ValueMap.vt))
{
if (Values.vt & CIM_FLAG_ARRAY)
{
//
// We have sets of arrays for the value map, make sure
// both arrays are the same size
//
SAFEARRAY *ValuesArray = Values.parray;
SAFEARRAY *ValueMapArray = ValueMap.parray;
if ((WmiGetArraySize(ValuesArray,
&ValuesLBound,
&ValuesUBound,
&ValuesSize)) &&
(WmiGetArraySize(ValueMapArray,
&ValueMapLBound,
&ValueMapUBound,
&ValueMapSize)) &&
(ValueMapSize == ValuesSize))
{
//
// Everything checks out with the arrays, just need to
// copy the values and valuemap into data item desc
//
SizeNeeded = sizeof(ENUMERATIONINFO) +
ValuesSize * sizeof(ENUMERATIONITEM);
EnumerationInfo = (PENUMERATIONINFO)LocalAlloc(LPTR,
SizeNeeded);
if (EnumerationInfo != NULL)
{
//
// We have memory to store the enumeration info
// loop over all enumations and record the info
//
ReturnStatus = TRUE;
DataItemDesc->EnumerationInfo = EnumerationInfo;
EnumerationInfo->Count = ValuesSize;
for (i = 0; (i < ValuesSize) && ReturnStatus; i++)
{
Index = i + ValuesLBound;
hr = SafeArrayGetElement(ValuesArray,
&Index,
&ValuesData);
if (hr == WBEM_S_NO_ERROR)
{
Index = i + ValueMapLBound;
hr = SafeArrayGetElement(ValueMapArray,
&Index,
&ValueMapData);
if (hr == WBEM_S_NO_ERROR)
{
ReturnStatus =
(WmiBstrToTchar(&EnumerationInfo->List[i].Text,
ValuesData)) &&
(WmiBstrToUlong64(&EnumerationInfo->List[i].Value,
ValueMapData));
}
} else {
ReturnStatus = FALSE;
}
}
}
}
} else {
//
// Single value in ValueMap
//
EnumerationInfo = (PENUMERATIONINFO)LocalAlloc(LPTR,
sizeof(ENUMERATIONINFO));
if (EnumerationInfo != NULL)
{
DataItemDesc->EnumerationInfo = EnumerationInfo;
EnumerationInfo->Count = 1;
ReturnStatus =
(WmiBstrToTchar(&EnumerationInfo->List[0].Text,
Values.bstrVal)) &&
(WmiBstrToUlong64(&EnumerationInfo->List[0].Value,
ValueMap.bstrVal));
} else {
ReturnStatus = FALSE;
}
}
}
}
VariantClear(&Values);
VariantClear(&ValueMap);
return(ReturnStatus);
}
BOOLEAN WmiGetEmbeddedDataItem(
IN IWbemServices *pIWbemServices,
IN IWbemQualifierSet *pIWbemQualifierSet,
IN PDATA_BLOCK_DESCRIPTION DataBlockDesc,
IN OUT PDATA_ITEM_DESCRIPTION DataItemDesc
)
{
#define ObjectColonText TEXT("object:")
#define ObjectColonTextChars ((sizeof(ObjectColonText)/sizeof(TCHAR))-1)
#define CIMTYPEText TEXT("CIMTYPE")
IWbemClassObject *pIWbemClassObjectEmbedded;
VARIANT CimType;
BSTR s;
HRESULT hr;
BOOLEAN ReturnStatus;
//
// This is an embedded class, so we need to dig
// out the name of the embedded class from the CIMTYPE
// qualifier for the property and then go and get
// that class object (via IWbemServices) as if it
// were just another top level class.
//
ReturnStatus = FALSE;
if (WmiGetQualifier(pIWbemQualifierSet,
CIMTYPEText,
VT_BSTR,
&CimType))
{
//
// Make sure that CIMTYPE value starts with object:
//
if (_tcsnicmp(CimType.bstrVal,
ObjectColonText,
ObjectColonTextChars) == 0)
{
//
// and if so then the rest of the string is the embedded class
// name, so make that a bstr so we can get a class object to it.
//
s = SysAllocString(CimType.bstrVal + ObjectColonTextChars);
if (s != NULL)
{
pIWbemClassObjectEmbedded = NULL;
hr = pIWbemServices->GetObject(s,
WBEM_FLAG_USE_AMENDED_QUALIFIERS,
NULL,
&pIWbemClassObjectEmbedded,
NULL);
if (hr == WBEM_S_NO_ERROR)
{
DebugPrint((1, "WMIPROP: Parsing embedded class %ws for %ws \n",
s, DataItemDesc->Name));
ReturnStatus = WmiGetDataBlockDesc(
pIWbemServices,
pIWbemClassObjectEmbedded,
&DataItemDesc->DataBlockDesc,
DataBlockDesc,
(DataItemDesc->IsReadOnly == 1));
DebugPrint((1, "WMIPROP: Parsed embedded class %ws for %ws (%p) %ws\n",
s,
DataItemDesc->Name,
DataItemDesc->DataBlockDesc,
ReturnStatus ? L"ok" : L"failed"));
pIWbemClassObjectEmbedded->Release();
}
SysFreeString(s);
}
}
VariantClear(&CimType);
}
return(ReturnStatus);
}
BOOLEAN WmiGetDataItem(
IWbemServices *pIWbemServices,
IWbemClassObject *pIWbemClassObject,
BSTR PropertyName,
IWbemQualifierSet *pIWbemQualifierSet,
PDATA_ITEM_DESCRIPTION DataItemDesc,
PDATA_BLOCK_DESCRIPTION DataBlockDesc,
BOOLEAN IsParentReadOnly
)
{
#define DescriptionText TEXT("Description")
#define MaxText TEXT("max")
#define WmiSizeIsText TEXT("WmiSizeIs")
#define WriteText TEXT("Write")
#define WmiDisplayInHexText TEXT("WmiDisplayInHex")
#define WmiDisplayNameText TEXT("DisplayName")
HRESULT hr;
CIMTYPE PropertyType;
LONG PropertyFlavor;
VARIANT WriteValue;
VARIANT DisplayHexValue;
VARIANT MaxValue;
VARIANT WmiSizeIsValue;
BOOLEAN ReturnStatus;
VARIANT Description;
VARIANT DisplayName;
PRANGELISTINFO RangeListInfo;
PRANGEINFO RangeInfo;
VARIANT PropertyValue;
WmiAssert(pIWbemServices != NULL);
WmiAssert(pIWbemClassObject != NULL);
WmiAssert(PropertyName != NULL);
WmiAssert(pIWbemQualifierSet != NULL);
WmiAssert(DataItemDesc != NULL);
hr = pIWbemClassObject->Get(PropertyName,
0,
&PropertyValue,
&PropertyType,
&PropertyFlavor);
if (hr == WBEM_S_NO_ERROR)
{
DebugPrint((1, "Property %ws (%p) is Type %x\n",
PropertyName, DataItemDesc, PropertyType));
//
// Make sure this is not a system property
//
WmiAssert((PropertyFlavor & WBEM_FLAVOR_ORIGIN_SYSTEM) == 0);
//
// Gather up the important information about the data item and
// remember it
//
if (WmiBstrToTchar(&DataItemDesc->Name, PropertyName))
{
ReturnStatus = TRUE;
DataItemDesc->DataType = (PropertyType & ~CIM_FLAG_ARRAY);
//
// Get Description for data item
//
if (WmiGetQualifier(pIWbemQualifierSet,
DescriptionText,
VT_BSTR,
&Description))
{
WmiBstrToTchar(&DataItemDesc->Description,
Description.bstrVal);
DebugPrint((1, "Property %ws (%p) has description %ws\n",
PropertyName, DataItemDesc,
DataItemDesc->Description));
VariantClear(&Description);
}
//
// Get display name for data item
//
if (WmiGetQualifier(pIWbemQualifierSet,
WmiDisplayNameText,
VT_BSTR,
&DisplayName))
{
WmiBstrToTchar(&DataItemDesc->DisplayName,
DisplayName.bstrVal);
DebugPrint((1, "Property %ws (%p) has display name %ws\n",
PropertyName, DataItemDesc,
DataItemDesc->DisplayName));
VariantClear(&DisplayName);
}
//
// Lets see if this should be displayed in Hex
//
DataItemDesc->DisplayInHex = 0;
if (WmiGetQualifier(pIWbemQualifierSet,
WmiDisplayInHexText,
VT_BOOL,
&DisplayHexValue))
{
if (DisplayHexValue.boolVal != 0)
{
DataItemDesc->DisplayInHex = 1;
DebugPrint((1, "Property %ws (%p) is DisplayInHex\n",
DataItemDesc->Name, DataItemDesc));
}
VariantClear(&DisplayHexValue);
}
//
// Lets see if this is read only or not
//
DataItemDesc->IsReadOnly = 1;
if ( (IsParentReadOnly == FALSE) &&
(WmiGetQualifier(pIWbemQualifierSet,
WriteText,
VT_BOOL,
&WriteValue)) )
{
if (WriteValue.boolVal != 0)
{
DataItemDesc->IsReadOnly = 0;
DebugPrint((1, "Property %ws (%p) is Read/Write\n",
DataItemDesc->Name, DataItemDesc));
}
VariantClear(&WriteValue);
}
//
// See if this is an array and if so which kind
//
if (PropertyType & CIM_FLAG_ARRAY)
{
DataItemDesc->CurrentArrayIndex = 0;
if (WmiGetQualifier(pIWbemQualifierSet,
MaxText,
VT_I4,
&MaxValue))
{
//
// A fixed length array
//
DataItemDesc->IsFixedArray = 1;
DataItemDesc->ArrayElementCount = MaxValue.lVal;
} else if (WmiGetQualifier(pIWbemQualifierSet,
WmiSizeIsText,
VT_BSTR,
&WmiSizeIsValue)) {
//
// A VL arrays
//
DataItemDesc->IsVariableArray = 1;
} else {
//
// Arrays must be fixed or variable length
//
ReturnStatus = FALSE;
}
}
if (ReturnStatus)
{
//
// Now we know enough to assign the validation function
//
DataItemDesc->DataSize = WmiGetElementSize(DataItemDesc->DataType);
switch(DataItemDesc->DataType)
{
case CIM_SINT8:
case CIM_UINT8:
case CIM_SINT16:
case CIM_UINT16:
case CIM_SINT32:
case CIM_UINT32:
case CIM_SINT64:
case CIM_UINT64:
{
//
// Numbers can be validated by ranges or value maps
//
if (WmiValueMapProperty(pIWbemQualifierSet,
DataItemDesc))
{
//
// Validation is based upon value map
//
DataItemDesc->ValidationFunc = WmiValueMapValidation;
DebugPrint((1, "Property %ws (%p) is a ValueMap (%p)\n",
DataItemDesc->Name, DataItemDesc, DataItemDesc->EnumerationInfo));
} else if (WmiRangeProperty(pIWbemQualifierSet,
DataItemDesc)) {
//
// Validation is based upon ranges
//
DataItemDesc->ValidationFunc = WmiRangeValidation;
DebugPrint((1, "Property %ws (%p) is an explicit range (%p)\n",
DataItemDesc->Name, DataItemDesc, DataItemDesc->EnumerationInfo));
} else {
//
// No validation specified for number so create
// a range that corresponds to the minimum and
// maximum values for the data type
//
DataItemDesc->ValidationFunc = WmiRangeValidation;
RangeListInfo = (PRANGELISTINFO)LocalAlloc(LPTR,
sizeof(RANGELISTINFO));
if (RangeListInfo != NULL)
{
DebugPrint((1, "Property %ws (%p) is an implicit range (%p)\n",
DataItemDesc->Name, DataItemDesc, RangeListInfo));
DataItemDesc->RangeListInfo = RangeListInfo;
RangeListInfo->Count = 1;
RangeInfo = &RangeListInfo->Ranges[0];
RangeInfo->Minimum = 0;
DataItemDesc->IsSignedValue = 0;
switch(DataItemDesc->DataType)
{
case CIM_SINT8:
{
DataItemDesc->IsSignedValue = 1;
// Fall through
}
case CIM_UINT8:
{
RangeInfo->Maximum = 0xff;
break;
}
case CIM_SINT16:
{
DataItemDesc->IsSignedValue = 1;
// Fall through
}
case CIM_UINT16:
{
RangeInfo->Maximum = 0xffff;
break;
}
case CIM_SINT32:
{
DataItemDesc->IsSignedValue = 1;
// Fall through
}
case CIM_UINT32:
{
RangeInfo->Maximum = 0xffffffff;
break;
}
case CIM_SINT64:
{
DataItemDesc->IsSignedValue = 1;
// Fall through
}
case CIM_UINT64:
{
RangeInfo->Maximum = 0xffffffffffffffff;
break;
}
}
} else {
ReturnStatus = FALSE;
}
}
break;
}
case CIM_BOOLEAN:
{
ULONG SizeNeeded;
PENUMERATIONINFO EnumerationInfo;
//
// We create a Valuemap with TRUE being 1 and
// FALSE being 0
//
DebugPrint((1, "Property %ws (%p) uses boolean validation\n",
DataItemDesc->Name, DataItemDesc));
DataItemDesc->ValidationFunc = WmiValueMapValidation;
SizeNeeded = sizeof(ENUMERATIONINFO) +
2 * sizeof(ENUMERATIONITEM);
EnumerationInfo = (PENUMERATIONINFO)LocalAlloc(LPTR,
SizeNeeded);
if (EnumerationInfo != NULL)
{
DataItemDesc->EnumerationInfo = EnumerationInfo;
EnumerationInfo->Count = 2;
EnumerationInfo->List[0].Value = 0;
EnumerationInfo->List[0].Text = WmiDuplicateString(TEXT("FALSE"));
EnumerationInfo->List[1].Value = 1;
EnumerationInfo->List[1].Text = WmiDuplicateString(TEXT("TRUE"));
}
break;
}
case CIM_STRING:
{
//
// String values are also validated simply
//
DebugPrint((1, "Property %ws (%p) uses string validation\n",
DataItemDesc->Name, DataItemDesc));
DataItemDesc->ValidationFunc = WmiStringValidation;
break;
}
case CIM_DATETIME:
{
//
// Date time values are also validated simply
//
DebugPrint((1, "Property %ws (%p) uses datetime validation\n",
DataItemDesc->Name, DataItemDesc));
DataItemDesc->ValidationFunc = WmiDateTimeValidation;
break;
}
case CIM_REAL32:
case CIM_REAL64:
{
//
// Floating point are not supported
//
DebugPrint((1, "Property %ws (%p) is floating point - not supported\n",
DataItemDesc->Name, DataItemDesc));
ReturnStatus = FALSE;
break;
}
case CIM_OBJECT:
{
if (WmiGetEmbeddedDataItem(pIWbemServices,
pIWbemQualifierSet,
DataBlockDesc,
DataItemDesc))
{
DataItemDesc->ValidationFunc = WmiEmbeddedValidation;
} else {
ReturnStatus = FALSE;
}
break;
}
default:
{
DebugPrint((1, "Property %ws (%p) is unknoen type %d\n",
DataItemDesc->Name, DataItemDesc,
DataItemDesc->DataType));
ReturnStatus = FALSE;
break;
}
}
}
} else {
ReturnStatus = FALSE;
}
VariantClear(&PropertyValue);
} else {
ReturnStatus = FALSE;
}
return(ReturnStatus);
}
#if DBG
void WmiDumpQualifiers(
IWbemQualifierSet *pIWbemQualiferSet
)
{
HRESULT hr;
LONG UBound, LBound, Count, i;
BSTR s;
SAFEARRAY *Quals = NULL;
WmiAssert(pIWbemQualiferSet != NULL);
hr = pIWbemQualiferSet->GetNames(0,
&Quals);
hr = SafeArrayGetLBound(Quals, 1, &LBound);
hr = SafeArrayGetUBound(Quals, 1, &UBound);
Count = UBound - LBound + 1;
for (i = LBound; i < Count; i++)
{
hr = SafeArrayGetElement(Quals,
&i,
&s);
DebugPrint((1, "qual - %ws\n", s));
}
SafeArrayDestroy(Quals);
}
#endif
BOOLEAN WmiGetAllDataItems(
IWbemServices *pIWbemServices,
IWbemClassObject *pIWbemClassObject,
SAFEARRAY *Names,
LONG LBound,
LONG Count,
PDATA_BLOCK_DESCRIPTION DataBlockDesc,
BOOLEAN IsParentReadOnly
)
{
#define WmiDataIdText TEXT("WmiDataId")
BOOLEAN ReturnStatus = TRUE;
HRESULT hr;
BSTR s;
VARIANT DataIdIndex;
LONG Index;
LONG i;
BSTR PropertyName;
CIMTYPE PropertyType;
VARIANT PropertyValue;
LONG PropertyFlavor;
PDATA_ITEM_DESCRIPTION DataItemDesc;
IWbemQualifierSet *pIWbemQualifierSet;
WmiAssert(pIWbemServices != NULL);
WmiAssert(pIWbemClassObject != NULL);
WmiAssert(Names != NULL);
WmiAssert(DataBlockDesc != NULL);
//
// Loop over all of the WmiDataItem property
for (i = 0; (i < Count) && ReturnStatus; i++)
{
//
// Get the name of the first property
//
PropertyName = NULL;
Index = i + LBound;
hr = SafeArrayGetElement(Names,
&Index,
&PropertyName);
if (hr == WBEM_S_NO_ERROR)
{
//
// Now lets get the qualifier list so we can determine
// interesting things about the property
//
hr = pIWbemClassObject->GetPropertyQualifierSet(PropertyName,
&pIWbemQualifierSet);
if (hr == WBEM_S_NO_ERROR)
{
if (WmiGetQualifier(pIWbemQualifierSet,
WmiDataIdText,
VT_I4,
&DataIdIndex))
{
WmiAssert(DataIdIndex.vt == VT_I4);
Index = DataIdIndex.lVal - 1;
VariantClear(&DataIdIndex);
DataItemDesc = &DataBlockDesc->DataItems[Index];
DebugPrint((1, "Property %ws (%p) has WmiDataId %d\n",
PropertyName, DataItemDesc, Index));
ReturnStatus = WmiGetDataItem(pIWbemServices,
pIWbemClassObject,
PropertyName,
pIWbemQualifierSet,
DataItemDesc,
DataBlockDesc,
IsParentReadOnly);
#if DBG
if (! ReturnStatus)
{
DebugPrint((1, "Property %ws (%p) failed WmiGetDataItem\n",
PropertyName, DataItemDesc));
}
#endif
} else {
//
// Since our IWbemClassObject->GetNames call specified
// only retrieve those properties with WmiDataId qualifier
// we expect that it will be found
//
WmiAssert(FALSE);
}
pIWbemQualifierSet->Release();
} else {
ReturnStatus = FALSE;
}
} else {
ReturnStatus = FALSE;
}
SysFreeString(PropertyName);
}
return(ReturnStatus);
}
BOOLEAN WmiGetDataBlockDesc(
IN IWbemServices *pIWbemServices,
IN IWbemClassObject *pIWbemClassObject,
OUT PDATA_BLOCK_DESCRIPTION *DBD,
IN PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc,
IN BOOLEAN IsParentReadOnly
)
{
HRESULT hr;
BSTR s;
SAFEARRAY *Names = NULL;
BOOLEAN ReturnStatus = FALSE;
LONG LBound, UBound, Count;
PDATA_BLOCK_DESCRIPTION DataBlockDesc;
VARIANT DisplayName, Description;
IWbemQualifierSet *pIWbemQualifierSet;
ULONG SizeNeeded;
WmiAssert(pIWbemServices != NULL);
WmiAssert(pIWbemClassObject != NULL);
WmiAssert(DBD != NULL);
*DBD = NULL;
s = SysAllocString(WmiDataIdText);
if (s != NULL)
{
hr = pIWbemClassObject->GetNames(s,
WBEM_FLAG_ONLY_IF_TRUE | WBEM_FLAG_NONSYSTEM_ONLY,
NULL,
&Names);
if (hr == WBEM_S_NO_ERROR)
{
#if DBG
//
// Verify that the safe array of names has 1 dimension and is
// an array of BSTR.
//
{
HRESULT hr;
VARTYPE vt;
WmiAssert(SafeArrayGetDim(Names) == 1);
hr = SafeArrayGetVartype(Names, &vt);
WmiAssert( (hr == WBEM_S_NO_ERROR) &&
(vt == VT_BSTR) );
}
#endif
hr = SafeArrayGetLBound(Names, 1, &LBound);
if (hr == WBEM_S_NO_ERROR)
{
hr = SafeArrayGetUBound(Names, 1, &UBound);
if (hr == WBEM_S_NO_ERROR)
{
Count = (UBound - LBound) + 1;
DebugPrint((1, "WMIPROP: %d properties found for class\n",
Count));
if (Count > 0)
{
SizeNeeded = sizeof(DATA_BLOCK_DESCRIPTION) +
Count * sizeof(DATA_ITEM_DESCRIPTION);
DataBlockDesc = (PDATA_BLOCK_DESCRIPTION)LocalAlloc(LPTR,
SizeNeeded);
if (DataBlockDesc != NULL)
{
DataBlockDesc->ParentDataBlockDesc = ParentDataBlockDesc;
if (WmiGetAllDataItems(pIWbemServices,
pIWbemClassObject,
Names,
LBound,
Count,
DataBlockDesc,
IsParentReadOnly))
{
DataBlockDesc->DataItemCount = Count;
DataBlockDesc->CurrentDataItem = 0;
//
// Get display name and description for class
//
pIWbemQualifierSet = NULL;
hr = pIWbemClassObject->GetQualifierSet(
&pIWbemQualifierSet);
if (hr == WBEM_S_NO_ERROR)
{
if (WmiGetQualifier(pIWbemQualifierSet,
WmiDisplayNameText,
VT_BSTR,
&DisplayName))
{
WmiBstrToTchar(&DataBlockDesc->DisplayName,
DisplayName.bstrVal);
VariantClear(&DisplayName);
}
if (WmiGetQualifier(pIWbemQualifierSet,
DescriptionText,
VT_BSTR,
&Description))
{
WmiBstrToTchar(&DataBlockDesc->Description,
Description.bstrVal);
VariantClear(&Description);
}
pIWbemQualifierSet->Release();
} else {
DebugPrint((1, "WMIPROP: Error %x getting qualifier set from %ws\n",
hr, s));
}
*DBD = DataBlockDesc;
ReturnStatus = TRUE;
} else {
LocalFree(DataBlockDesc);
}
}
} else {
ReturnStatus = FALSE;
}
}
}
SafeArrayDestroy(Names);
}
SysFreeString(s);
}
return(ReturnStatus);
}
BOOLEAN WmiBuildConfigClass(
IN PTCHAR MachineName,
IN IWbemServices *pIWbemServices,
IN PTCHAR ClassName,
IN PTCHAR InstanceName,
OUT PCONFIGCLASS ConfigClass
)
/*+++
Routine Description:
This routine will try to get the wbem object corresponding to the
ClassName and InstanceName and then query the class to gather info
needed to fill the ConfigClass.
Arguments:
ClassName is the name of the class
InstanceName is the name of the instance
ConfigClass
Return Value:
TRUE if successful else FALSE
---*/
{
#define RelPathText1 TEXT(".InstanceName=\"")
#define RelPathText2 TEXT("\"")
ULONG RelPathSize;
PTCHAR RelPath;
HRESULT hr;
IWbemClassObject *pIWbemClassObject, *pInstance;
ULONG SizeNeeded, i;
BOOLEAN ReturnStatus = FALSE;
BSTR sRelPath, sClassName;
WmiAssert(pIWbemServices != NULL);
WmiAssert(ClassName != NULL);
WmiAssert(InstanceName != NULL);
WmiAssert(ConfigClass != NULL);
if (MachineName != NULL)
{
RelPathSize = (_tcslen(MachineName) + 1) * sizeof(TCHAR);
ConfigClass->MachineName = (PTCHAR)LocalAlloc(LPTR, RelPathSize);
if (ConfigClass->MachineName != NULL)
{
_tcscpy(ConfigClass->MachineName, MachineName);
} else {
return(FALSE);
}
}
//
// Build up the relative path to the object
//
RelPathSize =
(_tcslen(ClassName) * sizeof(TCHAR)) +
sizeof(RelPathText1) +
(_tcslen(InstanceName) * sizeof(TCHAR)) +
sizeof(RelPathText2) +
sizeof(TCHAR);
RelPath = (PTCHAR)LocalAlloc(LPTR, RelPathSize);
if (RelPath != NULL)
{
_tcscpy(RelPath, ClassName);
_tcscat(RelPath, RelPathText1);
_tcscat(RelPath, InstanceName);
_tcscat(RelPath, RelPathText2);
ConfigClass->RelPath = RelPath;
//
// CONSIDER: Use semisynchronous call
//
sRelPath = SysAllocString(RelPath);
if (sRelPath != NULL)
{
pInstance = NULL;
hr = pIWbemServices->GetObject(sRelPath,
WBEM_FLAG_USE_AMENDED_QUALIFIERS,
NULL,
&pInstance,
NULL);
if (hr == WBEM_S_NO_ERROR)
{
//
// Now we know that the instance of the class exists so
// we need to get a class object for the class only. We
// need to do this since the instance class object does
// not have any of the qualifiers, but the class only
// class object does.
//
sClassName = SysAllocString(ClassName);
if (sClassName != NULL)
{
pIWbemClassObject= NULL;
hr = pIWbemServices->GetObject(sClassName,
WBEM_FLAG_USE_AMENDED_QUALIFIERS,
NULL,
&pIWbemClassObject,
NULL);
if (hr == WBEM_S_NO_ERROR)
{
//
// Go and get the data block description for
// the class. Note that if we are on a remote
// machine we force the entire data block to be
// read only so that it is consistent with the
// rest of device manager
//
if (WmiGetDataBlockDesc(pIWbemServices,
pIWbemClassObject,
&ConfigClass->DataBlockDesc,
NULL,
(MachineName != NULL) ?
TRUE :
FALSE))
{
WmiBstrToTchar(&ConfigClass->DataBlockDesc->Name,
sClassName);
ReturnStatus = TRUE;
}
pIWbemClassObject->Release();
} else {
DebugPrint((1, "WMIPROP: Error %x getting %ws class \n", hr, sClassName));
}
SysFreeString(sClassName);
}
//
// we have to release the class object to the instance of the
// class. We cannot hang onto the interface since it is
// only valid in this thread. We will again get a new
// instnace interface later in the window message thread
//
pInstance->Release();
} else {
DebugPrint((1, "WMIPROP: Error %x getting %ws class instance\n", hr, sRelPath));
}
}
SysFreeString(sRelPath);
}
return(ReturnStatus);
}
void WmiCleanDataItemDescData(
PDATA_ITEM_DESCRIPTION DataItemDesc
)
{
ULONG j;
if ((DataItemDesc->IsVariableArray == 1) ||
(DataItemDesc->IsFixedArray == 1))
{
if (DataItemDesc->ArrayPtr != NULL)
{
if ((DataItemDesc->DataType == CIM_STRING) ||
(DataItemDesc->DataType == CIM_DATETIME))
{
for (j = 0; j < DataItemDesc->ArrayElementCount; j++)
{
if (DataItemDesc->StringArray[j] != NULL)
{
LocalFree(DataItemDesc->StringArray[j]);
DataItemDesc->StringArray[j] = NULL;
}
}
} else if (DataItemDesc->DataType == CIM_OBJECT) {
for (j = 0; j < DataItemDesc->ArrayElementCount; j++)
{
if (DataItemDesc->StringArray[j] != NULL)
{
DataItemDesc->pIWbemClassObjectArray[j]->Release();
DataItemDesc->pIWbemClassObjectArray[j] = NULL;
}
}
}
LocalFree(DataItemDesc->ArrayPtr);
DataItemDesc->ArrayPtr = NULL;
}
} else {
if ((DataItemDesc->DataType == CIM_STRING) ||
(DataItemDesc->DataType == CIM_DATETIME))
{
LocalFree(DataItemDesc->String);
DataItemDesc->String = NULL;
}
if (DataItemDesc->DataType == CIM_OBJECT)
{
if (DataItemDesc->pIWbemClassObject != NULL)
{
DataItemDesc->pIWbemClassObject->Release();
DataItemDesc->pIWbemClassObject = NULL;
}
}
}
}
void WmiFreeDataBlockDesc(
PDATA_BLOCK_DESCRIPTION DataBlockDesc
)
/*+++
Routine Description:
This routine will free all resources used by a data block description
Arguments:
Return Value:
---*/
{
ULONG i,j;
PDATA_ITEM_DESCRIPTION DataItemDesc;
PENUMERATIONINFO EnumerationInfo;
PRANGELISTINFO RangeListInfo;
if (DataBlockDesc != NULL)
{
//
// This is freed when walking the data item desc looking for
// embedded classes
//
DataBlockDesc->ParentDataBlockDesc = NULL;
if (DataBlockDesc->Name != NULL)
{
LocalFree(DataBlockDesc->Name);
DataBlockDesc->Name = NULL;
}
if (DataBlockDesc->DisplayName != NULL)
{
LocalFree(DataBlockDesc->DisplayName);
DataBlockDesc->DisplayName = NULL;
}
if (DataBlockDesc->Description != NULL)
{
LocalFree(DataBlockDesc->Description);
DataBlockDesc->Description = NULL;
}
if (DataBlockDesc->pInstance != NULL)
{
DataBlockDesc->pInstance->Release();
DataBlockDesc->pInstance = NULL;
}
for (i = 0; i < DataBlockDesc->DataItemCount; i++)
{
DataItemDesc = &DataBlockDesc->DataItems[i];
DebugPrint((1, "WMIPROP: Freeing %ws (%p) index %d\n",
DataItemDesc->Name,
DataItemDesc,
i));
WmiCleanDataItemDescData(DataItemDesc);
if (DataItemDesc->Name != NULL)
{
LocalFree(DataItemDesc->Name);
DataItemDesc->Name = NULL;
}
if (DataItemDesc->DisplayName != NULL)
{
LocalFree(DataItemDesc->DisplayName);
DataItemDesc->DisplayName = NULL;
}
if (DataItemDesc->Description != NULL)
{
LocalFree(DataItemDesc->Description);
DataItemDesc->Description = NULL;
}
if ((DataItemDesc->ValidationFunc == WmiValueMapValidation) &&
(DataItemDesc->EnumerationInfo))
{
EnumerationInfo = DataItemDesc->EnumerationInfo;
for (j = 0; j < EnumerationInfo->Count; j++)
{
if (EnumerationInfo->List[j].Text != NULL)
{
LocalFree(EnumerationInfo->List[j].Text);
EnumerationInfo->List[j].Text = NULL;
}
}
LocalFree(EnumerationInfo);
DataItemDesc->EnumerationInfo = NULL;
}
if ((DataItemDesc->ValidationFunc == WmiRangeValidation) &&
(DataItemDesc->RangeListInfo != NULL))
{
LocalFree(DataItemDesc->RangeListInfo);
DataItemDesc->RangeListInfo = NULL;
}
if (DataItemDesc->ValidationFunc == WmiEmbeddedValidation)
{
if (DataItemDesc->DataBlockDesc != NULL)
{
WmiFreeDataBlockDesc(DataItemDesc->DataBlockDesc);
DataItemDesc->DataBlockDesc = NULL;
}
}
}
LocalFree(DataBlockDesc);
}
}
void WmiFreePageInfo(
PPAGE_INFO PageInfo
)
/*+++
Routine Description:
This routine will free all resources used by a page info
Arguments:
Return Value:
---*/
{
ULONG i;
PCONFIGCLASS ConfigClass;
WmiAssert(PageInfo != NULL);
if (PageInfo->hKeyDev != (HKEY) INVALID_HANDLE_VALUE)
{
RegCloseKey(PageInfo->hKeyDev);
PageInfo->hKeyDev = (HKEY) INVALID_HANDLE_VALUE;
}
ConfigClass = &PageInfo->ConfigClass;
if (ConfigClass->RelPath != NULL)
{
LocalFree(ConfigClass->RelPath);
ConfigClass->RelPath = NULL;
}
if (ConfigClass->pIWbemServices != NULL)
{
ConfigClass->pIWbemServices->Release();
ConfigClass->pIWbemServices = NULL;
}
if (ConfigClass->MachineName != NULL)
{
LocalFree(ConfigClass->MachineName);
ConfigClass->MachineName = NULL;
}
WmiFreeDataBlockDesc(ConfigClass->DataBlockDesc);
LocalFree(PageInfo);
}
PPAGE_INFO WmiCreatePageInfo(
IN PTCHAR MachineName,
IN IWbemServices *pIWbemServices,
IN PTCHAR ClassName,
IN PTCHAR InstanceName,
IN HDEVINFO deviceInfoSet,
IN PSP_DEVINFO_DATA deviceInfoData
)
/*+++
Routine Description:
This routine will create a PAGE_INFO structure that is used to describe
property pages.
Arguments:
Return Value:
---*/
{
PPAGE_INFO PageInfo;
BOOLEAN ReturnStatus;
HKEY hKeyDev;
WmiAssert(pIWbemServices != NULL);
WmiAssert(ClassName != NULL);
WmiAssert(InstanceName != NULL);
WmiAssert(deviceInfoSet != NULL);
WmiAssert(deviceInfoData != NULL);
//
// Allocate room to store data for the property page
//
PageInfo = (PPAGE_INFO)LocalAlloc(LPTR, sizeof(PAGE_INFO));
if (PageInfo == NULL) {
return(NULL);
}
hKeyDev = SetupDiCreateDevRegKey(deviceInfoSet,
deviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
NULL,
NULL);
PageInfo->hKeyDev = hKeyDev;
PageInfo->deviceInfoSet = deviceInfoSet;
PageInfo->deviceInfoData = deviceInfoData;
ReturnStatus = WmiBuildConfigClass(MachineName,
pIWbemServices,
ClassName,
InstanceName,
&PageInfo->ConfigClass);
if (! ReturnStatus)
{
WmiFreePageInfo(PageInfo);
PageInfo = NULL;
}
return(PageInfo);
}
void
WmiDestroyPageInfo(PPAGE_INFO * ppPageInfo)
{
PPAGE_INFO ppi = *ppPageInfo;
WmiFreePageInfo(ppi);
*ppPageInfo = NULL;
}
HPROPSHEETPAGE
WmiCreatePropertyPage(PROPSHEETPAGE * ppsp,
PPAGE_INFO ppi,
PTCHAR ClassName)
{
WmiAssert(ppi != NULL);
WmiAssert(ppsp != NULL);
WmiAssert(ClassName != NULL);
//
// Add the Port Settings property page
//
ppsp->dwSize = sizeof(PROPSHEETPAGE);
ppsp->dwFlags = PSP_USECALLBACK | PSP_USETITLE; // | PSP_HASHELP;
ppsp->hInstance = g_hInstance;
ppsp->pszTemplate = MAKEINTRESOURCE(ID_WMI_PROPPAGE);
ppsp->pszTitle = ClassName;
//
// following points to the dlg window proc
//
ppsp->pfnDlgProc = WmiDlgProc;
ppsp->lParam = (LPARAM) ppi;
//
// Following points to the control callback of the dlg window proc.
// The callback gets called before creation/after destruction of the page
//
ppsp->pfnCallback = WmiDlgCallback;
//
// Allocate the actual page
//
return CreatePropertySheetPage(ppsp);
}
BOOLEAN WmiIsDuplicateClass(
PTCHAR ClassName,
PTCHAR ClassList,
PTCHAR ClassListEnd
)
{
BOOLEAN Found;
ULONG NameLen;
Found = FALSE;
NameLen = _tcslen(ClassName);
while (ClassList < ClassListEnd)
{
if (_tcsnicmp(ClassList, ClassName, NameLen) == 0)
{
//
// We found a duplicate name
//
return(TRUE);
}
while (*ClassList != ',')
{
if (ClassList >= ClassListEnd)
{
return(FALSE);
}
ClassList++;
}
ClassList++;
}
return(Found);
}
PTCHAR WmiGetNextClass(
PTCHAR *ClassList
)
{
PTCHAR s = *ClassList;
PTCHAR Class, ClassName;
ULONG Len;
//
// skip over any white space
//
while (IsWhiteSpace(*s) && (*s != 0))
{
s++;
}
//
// Search for separator or end of string
//
ClassName = s;
Len = 0;
while ((*s != TEXT(',')) && (*s != 0))
{
s++;
Len++;
}
if (*s != 0)
{
//
// If we have a string then alloc and copy it over
//
Class = (PTCHAR)LocalAlloc(LPTR, (Len+1)*sizeof(TCHAR));
if (Class != NULL)
{
_tcsncpy(Class, ClassName, Len);
DebugPrint((1,"WMIPROP: Class %ws is in list\n", Class));
}
s++;
} else {
//
// End of string, all done
//
Class = NULL;
}
*ClassList = s;
return(Class);
}
BOOL
WmiPropPageProvider(HDEVINFO deviceInfoSet,
PSP_DEVINFO_DATA deviceInfoData,
PSP_ADDPROPERTYPAGE_DATA AddPPageData,
PTCHAR MachineName,
HANDLE MachineHandle
)
{
#define WmiConfigClassesText TEXT("WmiConfigClasses")
PSP_PROPSHEETPAGE_REQUEST ppr;
PROPSHEETPAGE psp;
HPROPSHEETPAGE hpsp;
TCHAR ClassListStatic[MAX_PATH];
TCHAR *ClassList, *DeviceList;
ULONG Status, Size, ClassListSize, DeviceListSize;
ULONG RegType;
HKEY hKeyDev, hKeyClass;
BOOLEAN PageAdded;
PPAGE_INFO ppi;
TCHAR *s;
IWbemServices *pIWbemServices;
PTCHAR InstanceName;
PTCHAR ClassName;
ULONG PageIndex;
PUCHAR Ptr;
CHAR ss[MAX_PATH];
PTCHAR ClassListEnd;
DebugPrint((1, "WMI: Enter WmiPropPageProvider(%p, %p, %p) \n",
deviceInfoSet,
deviceInfoData,
AddPPageData));
WmiAssert(deviceInfoSet != NULL);
WmiAssert(deviceInfoData != NULL);
PageAdded = FALSE;
//
// Get List of classes from registry. It should be in the
// WmiConfigClasses value under class specific key
// HKLM\CurrentControlSet\Control\CLASS\<ClassGuid>
// key.
//
ClassList = ClassListStatic;
Size = sizeof(ClassListStatic);
*ClassList = 0;
hKeyClass = SetupDiOpenClassRegKeyEx(&deviceInfoData->ClassGuid,
KEY_READ,
DIOCR_INSTALLER,
MachineName,
NULL);
if (hKeyClass != NULL)
{
Status = RegQueryValueEx(hKeyClass,
WmiConfigClassesText,
NULL,
&RegType,
(PUCHAR)ClassList,
&Size);
if (Status == ERROR_MORE_DATA)
{
//
// The class list is bigger than we though so allocate room
// for the bigger class list and extra room for the device
// list
//
Size = 2*(Size + sizeof(WCHAR));
ClassList = (PTCHAR)LocalAlloc(LPTR, Size);
if (ClassList != NULL)
{
Status = RegQueryValueEx(hKeyClass,
WmiConfigClassesText,
NULL,
&RegType,
(PUCHAR)ClassList,
&Size);
} else {
//
// We couldn't alloc memory for the class list so we
// forget about it
//
Status = ERROR_NOT_ENOUGH_MEMORY;
ClassList = ClassListStatic;
Size = sizeof(ClassListStatic);
*ClassList = 0;
}
}
RegCloseKey(hKeyClass);
} else {
Status = ERROR_INVALID_PARAMETER;
DebugPrint((1, "WMIPROP: Could not open class key for %s --> %d\n",
WmiGuidToString(ss, &deviceInfoData->ClassGuid),
GetLastError()));
}
//
// Compute size and location of device list
//
if ((Status == ERROR_SUCCESS) && (RegType == REG_SZ))
{
if (*ClassList != 0)
{
//
// If there is a class be sure to add a , at the end to
// aid in parsing
//
_tcscat(ClassList, TEXT(","));
}
//
// Compute location to append the device class list
//
ClassListSize = _tcslen(ClassList) * sizeof(TCHAR);
DeviceList = (PTCHAR)((PUCHAR)ClassList + ClassListSize);
WmiAssert(*DeviceList == 0);
DeviceListSize = Size - ClassListSize;
} else {
ClassListSize = 0;
DeviceList = ClassList;
DeviceListSize = Size;
DebugPrint((1, "WMIPROP: Query for class list in class key %s failed %d\n",
WmiGuidToString(ss, &deviceInfoData->ClassGuid),
Status));
}
//
// Get List of classes from registry. It should be in the
// WmiConfigClasses value under device specific key
// HKLM\CurrentControlSet\Control\CLASS\<ClassGuid>\<inst id>
// key.
//
hKeyDev = SetupDiCreateDevRegKey(deviceInfoSet,
deviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
NULL,
NULL);
if (hKeyDev != (HKEY)INVALID_HANDLE_VALUE)
{
Size = DeviceListSize;
Status = RegQueryValueEx(hKeyDev,
WmiConfigClassesText,
NULL,
&RegType,
(PUCHAR)DeviceList,
&Size);
if (Status == ERROR_MORE_DATA)
{
//
// Not enough room for the device list so allocate enough
// memory for the class and device lists combined and copy
// the class list into the new buffer
//
Ptr = (PUCHAR)LocalAlloc(LPTR, Size+ClassListSize);
if (Ptr != NULL)
{
memcpy(Ptr, ClassList, ClassListSize);
if (ClassList != ClassListStatic)
{
LocalFree(ClassList);
}
ClassList = (PTCHAR)Ptr;
DeviceList = (PTCHAR)(Ptr + ClassListSize);
WmiAssert(*DeviceList == 0);
Status = RegQueryValueEx(hKeyDev,
WmiConfigClassesText,
NULL,
&RegType,
(PUCHAR)DeviceList,
&Size);
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
}
RegCloseKey(hKeyDev);
if ((Status != ERROR_SUCCESS) || (RegType != REG_SZ))
{
*DeviceList = 0;
DebugPrint((1, "WMIPROP: Query for class list in class key %s failed %d\n",
WmiGuidToString(ss, &deviceInfoData->ClassGuid),
Status));
}
}
if (*ClassList != 0)
{
//
// Establish connection to WBEM and obtain information
// about the class whose properties are being acted upon
//
if (WmiConnectToWbem(MachineName, &pIWbemServices))
{
WmiAssert(pIWbemServices != NULL);
//
// Get WMI InstanceName for device
//
InstanceName = WmiGetDeviceInstanceName(deviceInfoSet,
deviceInfoData,
MachineHandle);
if (InstanceName != NULL)
{
//
// Loop over all classes specified and create property
// page for each one
//
DebugPrint((1, "WMIPROP: Setup propsheets for %ws for classlist %ws\n",
InstanceName,
ClassList));
s = ClassList;
do
{
ClassListEnd = s;
ClassName = WmiGetNextClass(&s);
if (ClassName != NULL)
{
if (*ClassName != 0)
{
if (! WmiIsDuplicateClass(ClassName,
ClassList,
ClassListEnd))
{
//
// create property page data structure
// that corresponds to this class
//
DebugPrint((1, "WMIPROP: Parsing class %ws for instance %ws\n",
ClassName, InstanceName));
ppi = WmiCreatePageInfo(MachineName,
pIWbemServices,
ClassName,
InstanceName,
deviceInfoSet,
deviceInfoData);
if (ppi != NULL)
{
hpsp = WmiCreatePropertyPage(
&psp,
ppi,
ppi->ConfigClass.DataBlockDesc->DisplayName ?
ppi->ConfigClass.DataBlockDesc->DisplayName :
ClassName);
if (hpsp != NULL)
{
//
// Add the sheet into the list
//
PageIndex = AddPPageData->NumDynamicPages;
if (PageIndex < MAX_INSTALLWIZARD_DYNAPAGES)
{
AddPPageData->NumDynamicPages++;
AddPPageData->DynamicPages[PageIndex] = hpsp;
PageAdded = TRUE;
} else {
DebugPrint((1, "WMIPROP: Can add page, already %d pages",
PageIndex));
}
} else {
WmiFreePageInfo(ppi);
}
}
}
}
LocalFree(ClassName);
}
} while (ClassName != NULL);
LocalFree(InstanceName);
} else {
DebugPrint((1, "WMIPROP: Unable to get instance name\n"));
}
//
// We release the interface rather than holding it
// since it cannot be used in a different thread and
// we'll be running in a different thread later.
//
pIWbemServices->Release();
} else {
DebugPrint((1, "WMIPROP: Unable to connect to wbem\n"));
}
}
if (ClassList != ClassListStatic)
{
LocalFree(ClassList);
}
DebugPrint((1, "WMI: Leave %s WmiPropPageProvider(%p, %p, %p) \n",
PageAdded ? "TRUE" : "FALSE",
deviceInfoSet,
deviceInfoData,
AddPPageData));
return(PageAdded);
}
UINT CALLBACK
WmiDlgCallback(HWND hwnd,
UINT uMsg,
LPPROPSHEETPAGE ppsp)
{
PPAGE_INFO ppi;
DebugPrint((1, "WMI: Enter WniDlgCallback(%p, %d, 0x%x) \n",
hwnd, uMsg, ppsp));
switch (uMsg) {
case PSPCB_CREATE:
DebugPrint((1, "WMI: Leave TRUE WniDlgCallback(%p, %d, 0x%x) \n",
hwnd, uMsg, ppsp));
return TRUE; // return TRUE to continue with creation of page
case PSPCB_RELEASE:
ppi = (PPAGE_INFO) ppsp->lParam;
WmiDestroyPageInfo(&ppi);
DebugPrint((1, "WMI: Leave FALSE WniDlgCallback(%p, %d, 0x%x) \n",
hwnd, uMsg, ppsp));
return 0; // return value ignored
default:
break;
}
DebugPrint((1, "WMI: Leave TRUE WniDlgCallback(%p, %d, 0x%x) \n",
hwnd, uMsg, ppsp));
return TRUE;
}
BOOLEAN WmiGetDataItemValue(
IN PDATA_ITEM_DESCRIPTION DataItemDesc,
OUT ULONG64 *DataValue
)
{
ULONG64 ReturnValue;
BOOLEAN ReturnStatus = TRUE;
BOOLEAN IsArray;
ULONG Index;
IsArray = (DataItemDesc->IsVariableArray) || (DataItemDesc->IsFixedArray);
Index = DataItemDesc->CurrentArrayIndex;
switch(DataItemDesc->DataType)
{
case CIM_SINT8:
{
if (IsArray)
{
ReturnValue = DataItemDesc->sint8Array[Index];
} else {
ReturnValue = DataItemDesc->sint8;
}
break;
}
case CIM_UINT8:
{
if (IsArray)
{
ReturnValue = DataItemDesc->uint8Array[Index];
} else {
ReturnValue = DataItemDesc->uint8;
}
break;
}
case CIM_SINT16:
{
if (IsArray)
{
ReturnValue = DataItemDesc->sint16Array[Index];
} else {
ReturnValue = DataItemDesc->sint16;
}
break;
}
case CIM_UINT16:
{
if (IsArray)
{
ReturnValue = DataItemDesc->uint16Array[Index];
} else {
ReturnValue = DataItemDesc->uint16;
}
break;
}
case CIM_SINT32:
{
if (IsArray)
{
ReturnValue = DataItemDesc->sint32Array[Index];
} else {
ReturnValue = DataItemDesc->sint32;
}
break;
}
case CIM_UINT32:
{
if (IsArray)
{
ReturnValue = DataItemDesc->uint32Array[Index];
} else {
ReturnValue = DataItemDesc->uint32;
}
break;
}
case CIM_SINT64:
{
if (IsArray)
{
ReturnValue = DataItemDesc->sint64Array[Index];
} else {
ReturnValue = DataItemDesc->sint64;
}
break;
}
case CIM_UINT64:
{
if (IsArray)
{
ReturnValue = DataItemDesc->uint64Array[Index];
} else {
ReturnValue = DataItemDesc->uint64;
}
break;
}
case CIM_BOOLEAN:
{
if (IsArray)
{
ReturnValue = DataItemDesc->boolArray[Index] == 0 ? 0 : 1;
} else {
ReturnValue = DataItemDesc->boolval == 0 ? 0 : 1;
}
break;
}
case CIM_REAL32:
case CIM_REAL64:
default:
{
WmiAssert(FALSE);
ReturnStatus = FALSE;
ReturnValue = 0;
}
}
*DataValue = ReturnValue;
return(ReturnStatus);
}
BOOLEAN WmiSetDataItemValue(
IN PDATA_ITEM_DESCRIPTION DataItemDesc,
IN ULONG64 DataValue
)
{
BOOLEAN ReturnStatus = TRUE;
BOOLEAN IsArray;
ULONG Index;
WmiAssert(DataItemDesc != NULL);
IsArray = (DataItemDesc->IsVariableArray) || (DataItemDesc->IsFixedArray);
Index = DataItemDesc->CurrentArrayIndex;
switch(DataItemDesc->DataType)
{
case CIM_SINT8:
{
if (IsArray)
{
DataItemDesc->sint8Array[Index] = (CHAR)DataValue;
} else {
DataItemDesc->sint8 = (CHAR)DataValue;
}
break;
}
case CIM_UINT8:
{
if (IsArray)
{
DataItemDesc->uint8Array[Index] = (UCHAR)DataValue;
} else {
DataItemDesc->uint8 = (UCHAR)DataValue;
}
break;
}
case CIM_SINT16:
{
if (IsArray)
{
DataItemDesc->sint16Array[Index] = (SHORT)DataValue;
} else {
DataItemDesc->sint16 = (SHORT)DataValue;
}
break;
}
case CIM_UINT16:
{
if (IsArray)
{
DataItemDesc->uint16Array[Index] = (USHORT)DataValue;
} else {
DataItemDesc->uint16 = (USHORT)DataValue;
}
break;
}
case CIM_SINT32:
{
if (IsArray)
{
DataItemDesc->sint32Array[Index] = (LONG)DataValue;
} else {
DataItemDesc->sint32 = (LONG)DataValue;
}
break;
}
case CIM_UINT32:
{
if (IsArray)
{
DataItemDesc->uint32Array[Index] = (ULONG)DataValue;
} else {
DataItemDesc->uint32 = (ULONG)DataValue;
}
break;
}
case CIM_SINT64:
{
if (IsArray)
{
DataItemDesc->sint64Array[Index] = (LONG64)DataValue;
} else {
DataItemDesc->sint64 = (LONG64)DataValue;
}
break;
}
case CIM_UINT64:
{
if (IsArray)
{
DataItemDesc->uint64Array[Index] = DataValue;
} else {
DataItemDesc->uint64 = DataValue;
}
break;
}
case CIM_BOOLEAN:
{
if (IsArray)
{
DataItemDesc->boolArray[Index] = (DataValue == 0) ? 0 : 1;
} else {
DataItemDesc->boolval = (DataValue == 0) ? 0 : 1;
}
break;
}
case CIM_REAL32:
case CIM_REAL64:
default:
{
WmiAssert(FALSE);
ReturnStatus = FALSE;
}
}
return(ReturnStatus);
}
void WmiRefreshDataItemToControl(
HWND hDlg,
PDATA_ITEM_DESCRIPTION DataItemDesc,
BOOLEAN FullUpdate
)
{
HWND hWnd;
BOOLEAN IsReadOnly, IsArray;
PTCHAR v;
WmiAssert(hDlg != NULL);
WmiAssert(DataItemDesc != NULL);
IsArray = (DataItemDesc->IsVariableArray) || (DataItemDesc->IsFixedArray);
if (FullUpdate)
{
//
// This code is run when we switch from one property to another
// property
//
if (DataItemDesc->Description != NULL)
{
hWnd = GetDlgItem(hDlg, IDC_DESCRIPTION_TEXT);
if (hWnd != NULL)
{
SendMessage(hWnd,
WM_SETTEXT,
0,
(LPARAM)DataItemDesc->Description);
ShowWindow(hWnd, SW_SHOW);
}
}
}
if ((DataItemDesc->ValidationFunc == WmiStringValidation) ||
(DataItemDesc->ValidationFunc == WmiDateTimeValidation) )
{
ULONG64 DataItemValue;
TCHAR s[MAX_PATH];
hWnd = GetDlgItem(hDlg, IDC_DATA_EDIT);
ShowWindow(hWnd, SW_SHOW);
EnableWindow(hWnd, (DataItemDesc->IsReadOnly == 1) ? FALSE : TRUE);
if (IsArray)
{
v = DataItemDesc->StringArray[DataItemDesc->CurrentArrayIndex];
} else {
v = DataItemDesc->String;
}
if (hWnd != NULL)
{
WmiAssert(DataItemDesc->String != NULL);
SendMessage(hWnd,
WM_SETTEXT,
0,
(LPARAM)v);
} else {
WmiAssert(FALSE);
}
} else if (DataItemDesc->ValidationFunc == WmiRangeValidation) {
ULONG64 DataItemValue;
TCHAR s[MAX_PATH];
PTCHAR FormatString;
ULONG FormatStringIndex;
static PTCHAR FormatStringList[4] = { TEXT("%lu"),
TEXT("%ld"),
TEXT("0x%lx"),
TEXT("0x%lx") };
hWnd = GetDlgItem(hDlg, IDC_DATA_EDIT);
ShowWindow(hWnd, SW_SHOW);
EnableWindow(hWnd, (DataItemDesc->IsReadOnly == 1) ? FALSE : TRUE);
if (hWnd != NULL)
{
if (WmiGetDataItemValue(DataItemDesc, &DataItemValue))
{
FormatStringIndex = DataItemDesc->DisplayInHex * 2 +
DataItemDesc->IsSignedValue;
FormatString = FormatStringList[FormatStringIndex];
wsprintf(s,
FormatString,
DataItemValue);
SendMessage(hWnd,
WM_SETTEXT,
0,
(LPARAM)s);
}
} else {
WmiAssert(FALSE);
}
} else if (DataItemDesc->ValidationFunc == WmiValueMapValidation) {
PENUMERATIONINFO EnumerationInfo;
ULONG j;
ULONG64 DataItemValue;
hWnd = GetDlgItem(hDlg, IDC_DATA_COMBO);
if (hWnd != NULL)
{
EnumerationInfo = DataItemDesc->EnumerationInfo;
WmiAssert(EnumerationInfo != NULL);
SendMessage(hWnd,
CB_RESETCONTENT,
0,
0);
for (j = 0; j < EnumerationInfo->Count; j++)
{
WmiAssert(EnumerationInfo->List[j].Text != NULL);
SendMessage(hWnd,
CB_ADDSTRING,
0,
(LPARAM)EnumerationInfo->List[j].Text);
}
ShowWindow(hWnd, SW_SHOW);
EnableWindow(hWnd, (DataItemDesc->IsReadOnly == 1) ?
FALSE : TRUE);
if (WmiGetDataItemValue(DataItemDesc, &DataItemValue))
{
for (j = 0; j < EnumerationInfo->Count; j++)
{
if (DataItemValue == EnumerationInfo->List[j].Value)
{
SendMessage(hWnd,
CB_SETCURSEL,
(WPARAM)j,
0);
break;
}
}
}
} else {
WmiAssert(FALSE);
}
} else if (DataItemDesc->ValidationFunc == WmiEmbeddedValidation) {
hWnd = GetDlgItem(hDlg, IDC_DATA_BUTTON);
if (hWnd != NULL)
{
SendMessage(hWnd,
WM_SETTEXT,
0,
(LPARAM) (DataItemDesc->DisplayName ?
DataItemDesc->DisplayName :
DataItemDesc->Name));
ShowWindow(hWnd, SW_SHOW);
EnableWindow(hWnd, TRUE);
} else {
WmiAssert(FALSE);
}
} else {
WmiAssert(FALSE);
}
if (FullUpdate)
{
if (IsArray)
{
TCHAR s[MAX_PATH];
hWnd = GetDlgItem(hDlg, IDC_ARRAY_SPIN);
if (hWnd != NULL)
{
SendMessage(hWnd,
UDM_SETRANGE32,
(WPARAM)1,
(LPARAM)DataItemDesc->ArrayElementCount);
DebugPrint((1, "WMIPROP: SetPos32 -> %d\n",
DataItemDesc->CurrentArrayIndex+1));
SendMessage(hWnd,
UDM_SETPOS32,
(WPARAM)0,
(LPARAM)DataItemDesc->CurrentArrayIndex+1);
ShowWindow(hWnd, SW_SHOW);
}
hWnd = GetDlgItem(hDlg, IDC_ARRAY_TEXT);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_SHOW);
}
hWnd = GetDlgItem(hDlg, IDC_ARRAY_STATIC);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_SHOW);
}
}
}
}
void
WmiRefreshDataBlockToControls(
HWND hDlg,
PDATA_BLOCK_DESCRIPTION DataBlockDesc,
BOOLEAN FullUpdate
)
{
ULONG i;
WmiAssert(hDlg != NULL);
WmiAssert(DataBlockDesc != NULL);
WmiAssert(DataBlockDesc->CurrentDataItem < DataBlockDesc->DataItemCount);
WmiHideAllControls(hDlg, FALSE, FullUpdate);
WmiRefreshDataItemToControl(hDlg,
&DataBlockDesc->DataItems[DataBlockDesc->CurrentDataItem],
FullUpdate);
}
void
WmiInitializeControlsFromDataBlock(
HWND hDlg,
PDATA_BLOCK_DESCRIPTION DataBlockDesc,
BOOLEAN IsEmbeddedClass
)
{
HWND hWnd, hWndBuddy;
PDATA_ITEM_DESCRIPTION DataItemDesc;
ULONG i;
BSTR s;
int ShowOrHide;
BOOLEAN IsReadOnly;
WmiAssert(hDlg != NULL);
WmiAssert(DataBlockDesc != NULL);
WmiHideAllControls(hDlg, TRUE, TRUE);
hWnd = GetDlgItem(hDlg, IDC_PROPERTY_LISTBOX);
if (hWnd != NULL)
{
SendMessage(hWnd,
LB_RESETCONTENT,
0,
0);
for (i = 0; i < DataBlockDesc->DataItemCount; i++)
{
DataItemDesc = &DataBlockDesc->DataItems[i];
SendMessage(hWnd,
LB_ADDSTRING,
0,
(LPARAM) (DataItemDesc->DisplayName ?
DataItemDesc->DisplayName :
DataItemDesc->Name));
}
SendMessage(hWnd,
LB_SETCURSEL,
(WPARAM)DataBlockDesc->CurrentDataItem,
0);
ShowWindow(hWnd, SW_SHOW);
EnableWindow(hWnd, TRUE);
//
// Refresh data from wbem and if successful update the controls
//
WmiRefreshDataBlockToControls(hDlg,
DataBlockDesc,
TRUE);
}
ShowOrHide = IsEmbeddedClass ? SW_SHOW : SW_HIDE;
hWnd = GetDlgItem(hDlg, IDC_WMI_EMBEDDED_OK);
if (hWnd != NULL)
{
ShowWindow(hWnd, ShowOrHide);
}
hWnd = GetDlgItem(hDlg, IDC_WMI_EMBEDDED_CANCEL);
if (hWnd != NULL)
{
ShowWindow(hWnd, ShowOrHide);
}
hWnd = GetDlgItem(hDlg, IDC_ARRAY_SPIN);
if (hWnd != NULL)
{
hWndBuddy = GetDlgItem(hDlg, IDC_ARRAY_TEXT);
SendMessage(hWnd,
UDM_SETBUDDY,
(WPARAM)hWndBuddy,
0);
}
}
BOOLEAN WmiReconnectToWbem(
PCONFIGCLASS ConfigClass,
IWbemClassObject **pInstance
)
{
BOOLEAN ReturnStatus;
IWbemClassObject *pIWbemClassObject;
IWbemServices *pIWbemServices;
HRESULT hr;
BSTR s;
WmiAssert(ConfigClass != NULL);
//
// Reestablish our interfaces to WBEM now that we are on the
// window message thread
//
ReturnStatus = FALSE;
if (WmiConnectToWbem(ConfigClass->MachineName,
&pIWbemServices))
{
ConfigClass->pIWbemServices = pIWbemServices;
s = SysAllocString(ConfigClass->RelPath);
if (s != NULL)
{
pIWbemClassObject = NULL;
hr = pIWbemServices->GetObject(s,
WBEM_FLAG_USE_AMENDED_QUALIFIERS,
NULL,
&pIWbemClassObject,
NULL);
if (hr == WBEM_S_NO_ERROR)
{
*pInstance = pIWbemClassObject;
ReturnStatus = TRUE;
} else {
DebugPrint((1, "WMIPROP: Error %x reestablishing IWbemClassObject to instance for %ws\n",
hr, ConfigClass->RelPath));
}
SysFreeString(s);
}
}
return(ReturnStatus);
}
void WmiHideAllControls(
HWND hDlg,
BOOLEAN HideEmbeddedControls,
BOOLEAN HideArrayControls
)
{
HWND hWnd;
WmiAssert(hDlg != NULL);
hWnd = GetDlgItem(hDlg, IDC_DATA_EDIT);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
hWnd = GetDlgItem(hDlg, IDC_DATA_COMBO);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
hWnd = GetDlgItem(hDlg, IDC_DATA_CHECK);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
hWnd = GetDlgItem(hDlg, IDC_DATA_BUTTON);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
hWnd = GetDlgItem(hDlg, IDC_ARRAY_EDIT);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
if (HideArrayControls)
{
hWnd = GetDlgItem(hDlg, IDC_ARRAY_SPIN);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
hWnd = GetDlgItem(hDlg, IDC_ARRAY_STATIC);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
hWnd = GetDlgItem(hDlg, IDC_ARRAY_TEXT);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
}
if (HideEmbeddedControls)
{
hWnd = GetDlgItem(hDlg, IDC_WMI_EMBEDDED_OK);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
hWnd = GetDlgItem(hDlg, IDC_WMI_EMBEDDED_CANCEL);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
}
}
void
WmiInitializeDialog(
PPAGE_INFO ppi,
HWND hDlg
)
{
PCONFIGCLASS ConfigClass;
HWND hWnd;
BOOLEAN ReturnStatus;
WmiAssert(ppi != NULL);
WmiAssert(hDlg != NULL);
ConfigClass = &ppi->ConfigClass;
ReturnStatus = FALSE;
if (WmiReconnectToWbem(ConfigClass,
&ConfigClass->DataBlockDesc->pInstance))
{
if (WmiRefreshDataBlockFromWbem( ConfigClass->DataBlockDesc->pInstance,
ConfigClass->DataBlockDesc))
{
WmiInitializeControlsFromDataBlock(hDlg,
ConfigClass->DataBlockDesc,
FALSE);
hWnd = GetDlgItem(hDlg, IDC_WMI_CONNECT_ERR);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
ReturnStatus = TRUE;
}
}
if (! ReturnStatus)
{
//
// Hide all controls except for a static string that says we cannot
// connect to wbem.
//
hWnd = GetDlgItem(hDlg, IDC_PROPERTY_LISTBOX);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_HIDE);
}
WmiHideAllControls(hDlg, TRUE, TRUE);
hWnd = GetDlgItem(hDlg, IDC_WMI_CONNECT_ERR);
if (hWnd != NULL)
{
ShowWindow(hWnd, SW_SHOW);
}
}
}
BOOLEAN WmiGetControlText(
HWND hWnd,
PTCHAR *Text
)
{
ULONG SizeNeeded;
BOOLEAN ReturnStatus = FALSE;
ULONG CharNeeded, CharCopied;
WmiAssert(hWnd != NULL);
WmiAssert(Text != NULL);
CharNeeded = (ULONG)SendMessage(hWnd,
WM_GETTEXTLENGTH,
0,
0);
if (CharNeeded > 0)
{
SizeNeeded = (++CharNeeded) * sizeof(TCHAR);
*Text = (PTCHAR)LocalAlloc(LPTR, SizeNeeded);
if (*Text != NULL)
{
CharCopied = (ULONG)SendMessage(hWnd,
WM_GETTEXT,
CharNeeded,
(LPARAM)*Text);
ReturnStatus = TRUE;
}
}
return(ReturnStatus);
}
void WmiValidationError(
HWND hWnd,
PDATA_ITEM_DESCRIPTION DataItemDesc
)
{
TCHAR buf[MAX_PATH];
TCHAR buf2[MAX_PATH];
ULONG Bytes;
//
// TODO: Do a better job of informing the user
//
//
// Get the string template for the error message
//
Bytes = LoadString(g_hInstance,
IDS_WMI_VALIDATION_ERROR,
buf,
MAX_PATH);
wsprintf(buf2, buf, DataItemDesc->Name);
MessageBox(hWnd, buf2, NULL, MB_ICONWARNING);
}
BOOLEAN WmiRefreshDataItemFromControl(
HWND hDlg,
PDATA_ITEM_DESCRIPTION DataItemDesc,
PBOOLEAN UpdateValues
)
{
HWND hWnd;
BOOLEAN ReturnStatus;
WmiAssert(hDlg != NULL);
WmiAssert(DataItemDesc != NULL);
WmiAssert(UpdateValues != NULL);
ReturnStatus = TRUE;
*UpdateValues = FALSE;
if (DataItemDesc->IsReadOnly == 0)
{
//
// Property is not read only so see what we need to update
//
if (DataItemDesc->ValidationFunc == WmiValueMapValidation)
{
//
// if a value map or enumeration then we get the current
// location and then lookup the corresponding value to
// set
//
ULONG CurSel;
ULONG64 EnumValue;
hWnd = GetDlgItem(hDlg, IDC_DATA_COMBO);
if (hWnd != NULL)
{
CurSel = (ULONG)SendMessage(hWnd,
CB_GETCURSEL,
0,
0);
if (CurSel != CB_ERR)
{
if (CurSel < DataItemDesc->EnumerationInfo->Count)
{
EnumValue = DataItemDesc->EnumerationInfo->List[CurSel].Value;
WmiSetDataItemValue(DataItemDesc,
EnumValue);
*UpdateValues = TRUE;
} else {
WmiAssert(FALSE);
}
}
} else {
WmiAssert(FALSE);
}
} else {
//
// All of the rest of the validation types are based
// upon the contents of the edit box, so get the value
// from there
//
PTCHAR Text;
ULONG64 Number;
hWnd = GetDlgItem(hDlg, IDC_DATA_EDIT);
if (hWnd != NULL)
{
if (WmiGetControlText(hWnd,
&Text))
{
if (DataItemDesc->ValidationFunc == WmiRangeValidation) {
if (WmiValidateRange(DataItemDesc, &Number, Text))
{
WmiSetDataItemValue(DataItemDesc,
Number);
*UpdateValues = TRUE;
} else {
//
// Validation failed, go tell user
//
WmiValidationError(hDlg, DataItemDesc);
ReturnStatus = FALSE;
}
} else if (DataItemDesc->ValidationFunc == WmiDateTimeValidation) {
if (WmiValidateDateTime(DataItemDesc, Text))
{
DataItemDesc->DateTime = Text;
Text = NULL;
*UpdateValues = TRUE;
} else {
//
// Validation failed, go tell user
//
WmiValidationError(hDlg, DataItemDesc);
ReturnStatus = FALSE;
}
} else if (DataItemDesc->ValidationFunc == WmiStringValidation) {
DataItemDesc->String = Text;
Text = NULL;
*UpdateValues = TRUE;
}
if (Text != NULL)
{
LocalFree(Text);
}
}
} else {
WmiAssert(FALSE);
}
}
}
return(ReturnStatus);
}
BOOLEAN WmiRefreshDataBlockFromControls(
HWND hDlg,
PDATA_BLOCK_DESCRIPTION DataBlockDesc,
PBOOLEAN UpdateValues
)
{
ULONG i;
PDATA_ITEM_DESCRIPTION DataItemDesc;
BOOLEAN UpdateItem, ReturnStatus;
WmiAssert(hDlg != NULL);
WmiAssert(DataBlockDesc != NULL);
WmiAssert(UpdateValues != NULL);
*UpdateValues = FALSE;
DataItemDesc = &DataBlockDesc->DataItems[DataBlockDesc->CurrentDataItem];
//
// We are not going to worry about failures from this function
// so we'll just use the previous values in the function
//
ReturnStatus = WmiRefreshDataItemFromControl(hDlg,
DataItemDesc,
&UpdateItem);
if (ReturnStatus && UpdateItem)
{
*UpdateValues = TRUE;
DataBlockDesc->UpdateClass = TRUE;
}
return(ReturnStatus);
}
void WmiPushIntoEmbeddedClass(
HWND hDlg,
PPAGE_INFO ppi,
PDATA_BLOCK_DESCRIPTION DataBlockDesc
)
{
ULONG i;
PDATA_ITEM_DESCRIPTION DataItemDesc;
WmiAssert(ppi != NULL);
WmiAssert(DataBlockDesc != NULL);
DataItemDesc = &DataBlockDesc->DataItems[DataBlockDesc->CurrentDataItem];
if (DataItemDesc->ValidationFunc == WmiEmbeddedValidation)
{
//
// The property is an embedded class so all we need to do
// is to change the controls to our embededded class
//
DataBlockDesc = DataItemDesc->DataBlockDesc;
WmiAssert(DataBlockDesc != NULL);
DataBlockDesc->UpdateClass = FALSE;
if ((DataItemDesc->IsVariableArray) ||
(DataItemDesc->IsFixedArray))
{
DataBlockDesc->pInstance = DataItemDesc->pIWbemClassObjectArray[DataItemDesc->CurrentArrayIndex];
} else {
DataBlockDesc->pInstance = DataItemDesc->pIWbemClassObject;
}
DataBlockDesc->pInstance->AddRef();
WmiRefreshDataBlockFromWbem(DataBlockDesc->pInstance,
DataBlockDesc);
ppi->ConfigClass.DataBlockDesc = DataBlockDesc;
} else {
WmiAssert(FALSE);
}
}
void WmiPopOutEmbeddedClass(
HWND hDlg,
PPAGE_INFO ppi,
PDATA_BLOCK_DESCRIPTION DataBlockDesc,
BOOLEAN SaveChanges
)
{
PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc;
ParentDataBlockDesc = DataBlockDesc->ParentDataBlockDesc;
WmiAssert(ParentDataBlockDesc != NULL);
if ((SaveChanges) && (DataBlockDesc->UpdateClass))
{
//
// Copy the properties for the data block back into WBEM
//
WmiRefreshWbemFromDataBlock(ppi->ConfigClass.pIWbemServices,
DataBlockDesc->pInstance,
DataBlockDesc,
TRUE);
ParentDataBlockDesc->UpdateClass = TRUE;
}
DataBlockDesc->pInstance->Release();
DataBlockDesc->pInstance = NULL;
ppi->ConfigClass.DataBlockDesc = ParentDataBlockDesc;
}
void WmiButtonSelected(
HWND hDlg,
PPAGE_INFO ppi,
ULONG ControlId
)
{
BOOLEAN UpdateValues, ReturnStatus;
PDATA_BLOCK_DESCRIPTION DataBlockDesc;
WmiAssert(ppi != NULL);
if (ControlId == IDC_DATA_BUTTON)
{
DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
WmiAssert(DataBlockDesc != NULL);
ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
DataBlockDesc,
&UpdateValues);
if (ReturnStatus)
{
WmiPushIntoEmbeddedClass(hDlg,
ppi,
DataBlockDesc);
WmiInitializeControlsFromDataBlock(hDlg,
ppi->ConfigClass.DataBlockDesc,
TRUE);
} else {
WmiRefreshDataBlockToControls(hDlg,
DataBlockDesc,
FALSE);
}
}
}
void WmiButtonEmbeddedOk(
HWND hDlg,
PPAGE_INFO ppi
)
{
PDATA_BLOCK_DESCRIPTION DataBlockDesc;
PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc;
BOOLEAN UpdateValues, ReturnStatus;
WmiAssert(ppi != NULL);
WmiAssert(hDlg != NULL);
DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
WmiAssert(DataBlockDesc != NULL);
ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
DataBlockDesc,
&UpdateValues);
if (ReturnStatus)
{
WmiPopOutEmbeddedClass(hDlg,
ppi,
DataBlockDesc,
TRUE);
ParentDataBlockDesc = ppi->ConfigClass.DataBlockDesc;
WmiAssert(ParentDataBlockDesc != NULL);
WmiInitializeControlsFromDataBlock(hDlg,
ParentDataBlockDesc,
(ParentDataBlockDesc->ParentDataBlockDesc != NULL));
} else {
WmiRefreshDataBlockToControls(hDlg,
DataBlockDesc,
FALSE);
}
}
void WmiButtonEmbeddedCancel(
HWND hDlg,
PPAGE_INFO ppi
)
{
PDATA_BLOCK_DESCRIPTION DataBlockDesc;
PDATA_BLOCK_DESCRIPTION ParentDataBlockDesc;
BOOLEAN UpdateValues, ReturnStatus;
WmiAssert(ppi != NULL);
WmiAssert(hDlg != NULL);
DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
WmiAssert(DataBlockDesc != NULL);
WmiPopOutEmbeddedClass(hDlg,
ppi,
DataBlockDesc,
FALSE);
ParentDataBlockDesc = ppi->ConfigClass.DataBlockDesc;
WmiAssert(ParentDataBlockDesc != NULL);
WmiInitializeControlsFromDataBlock(hDlg,
ParentDataBlockDesc,
(ParentDataBlockDesc->ParentDataBlockDesc != NULL));
}
BOOLEAN
WmiApplyChanges(
PPAGE_INFO ppi,
HWND hDlg
)
{
PDATA_BLOCK_DESCRIPTION DataBlockDesc;
IWbemClassObject *pIWbemClassObject;
BOOLEAN UpdateClass, ReturnStatus;
IWbemServices *pIWbemServices;
WmiAssert(ppi != NULL);
WmiAssert(hDlg != NULL);
DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
pIWbemServices = ppi->ConfigClass.pIWbemServices;
ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
DataBlockDesc,
&UpdateClass);
if (ReturnStatus)
{
//
// Pop out of embedded classes to the root class
//
while (DataBlockDesc->ParentDataBlockDesc != NULL)
{
WmiPopOutEmbeddedClass(hDlg,
ppi,
DataBlockDesc,
TRUE);
DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
}
//
// Now we are at the root class so save that
//
if (DataBlockDesc->UpdateClass)
{
WmiRefreshWbemFromDataBlock(pIWbemServices,
DataBlockDesc->pInstance,
DataBlockDesc,
FALSE);
UpdateClass = TRUE;
}
DataBlockDesc->pInstance->Release();
DataBlockDesc->pInstance = NULL;
} else {
WmiRefreshDataBlockToControls(hDlg,
DataBlockDesc,
FALSE);
}
return(ReturnStatus);
}
INT_PTR WmipDataItemSelectionChange(
HWND hDlg,
PPAGE_INFO ppi
)
{
PDATA_BLOCK_DESCRIPTION DataBlockDesc;
HWND hWnd;
BOOLEAN UpdateClass, ReturnStatus;
WmiAssert(ppi != NULL);
WmiAssert(hDlg != NULL);
DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
WmiAssert(DataBlockDesc != NULL);
hWnd = GetDlgItem(hDlg, IDC_PROPERTY_LISTBOX);
if (hWnd != NULL)
{
ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
DataBlockDesc,
&UpdateClass);
if (UpdateClass)
{
DataBlockDesc->UpdateClass = TRUE;
}
//
// New value for data item is ok, refresh display with new
// data item
//
DataBlockDesc->CurrentDataItem = (ULONG)SendMessage(hWnd,
LB_GETCURSEL,
0,
0);
WmiRefreshDataBlockToControls(hDlg,
DataBlockDesc,
TRUE);
}
return(0);
}
void WmiSetArrayIndex(
HWND hDlg,
PPAGE_INFO ppi,
int NewIndex
)
{
PDATA_BLOCK_DESCRIPTION DataBlockDesc;
PDATA_ITEM_DESCRIPTION DataItemDesc;
HWND hWnd;
BOOLEAN UpdateClass, ReturnStatus;
WmiAssert(ppi != NULL);
WmiAssert(hDlg != NULL);
DebugPrint((1, "WMIPROP: Set index to %d\n", NewIndex));
DataBlockDesc = ppi->ConfigClass.DataBlockDesc;
WmiAssert(DataBlockDesc != NULL);
DataItemDesc = &DataBlockDesc->DataItems[DataBlockDesc->CurrentDataItem];
if ((ULONG)NewIndex < DataItemDesc->ArrayElementCount)
{
ReturnStatus = WmiRefreshDataBlockFromControls(hDlg,
DataBlockDesc,
&UpdateClass);
if (UpdateClass)
{
DataBlockDesc->UpdateClass = TRUE;
}
DataItemDesc->CurrentArrayIndex = NewIndex;
WmiRefreshDataBlockToControls(hDlg,
DataBlockDesc,
FALSE);
}
}
INT_PTR WmiControlColorStatic(
HDC DC,
HWND HStatic
)
{
UINT id = GetDlgCtrlID(HStatic);
UINT ControlType;
//
// WM_CTLCOLORSTATIC is sent for the edit controls because they are read
// only
//
if ((id == IDC_DATA_CHECK) ||
(id == IDC_DATA_BUTTON))
{
SetBkColor(DC, GetSysColor(COLOR_WINDOW));
return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
}
return FALSE;
}
INT_PTR APIENTRY
WmiDlgProc(IN HWND hDlg,
IN UINT uMessage,
IN WPARAM wParam,
IN LPARAM lParam)
{
PPAGE_INFO ppi;
BOOLEAN ReturnStatus;
DebugPrint((7, "WMI: Enter WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
hDlg, uMessage, wParam, lParam));
ppi = (PPAGE_INFO) GetWindowLongPtr(hDlg, DWLP_USER);
switch (uMessage) {
case WM_INITDIALOG:
//
// on WM_INITDIALOG call, lParam points to the property
// sheet page.
//
// The lParam field in the property sheet page struct is set by the
// caller. When I created the property sheet, I passed in a pointer
// to a struct containing information about the device. Save this in
// the user window long so I can access it on later messages.
//
ppi = (PPAGE_INFO) ((LPPROPSHEETPAGE)lParam)->lParam;
SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR) ppi);
//
// Initialize dlg controls
//
WmiInitializeDialog(ppi,
hDlg);
//
// Didn't set the focus to a particular control. If we wanted to,
// then return FALSE
//
DebugPrint((7, "WMI: Leave TRUE WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
hDlg, uMessage, wParam, lParam));
return TRUE;
case WM_COMMAND:
if (HIWORD(wParam) == LBN_SELCHANGE)
{
WmipDataItemSelectionChange(hDlg, ppi);
return(TRUE);
}
if (HIWORD(wParam) == CBN_SELCHANGE)
{
PropSheet_Changed(GetParent(hDlg), hDlg);
DebugPrint((7, "WMI: Leave TRUE WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
hDlg, uMessage, wParam, lParam));
return TRUE;
}
switch (wParam)
{
case IDC_DATA_BUTTON:
{
WmiButtonSelected(hDlg, ppi, (ULONG)wParam);
break;
}
case IDC_WMI_EMBEDDED_OK:
{
WmiButtonEmbeddedOk(hDlg, ppi);
break;
}
case IDC_WMI_EMBEDDED_CANCEL:
{
WmiButtonEmbeddedCancel(hDlg, ppi);
break;
}
}
#if 0
//
// Add this code back in if we will need it
//
switch(LOWORD(wParam)) {
default:
break;
}
#endif
break;
case WM_CONTEXTMENU:
DebugPrint((7, "WMI: Leave ? WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
hDlg, uMessage, wParam, lParam));
return WmiContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
case WM_HELP:
WmiHelp(hDlg, (LPHELPINFO) lParam);
break;
case WM_CTLCOLORSTATIC:
return WmiControlColorStatic((HDC)wParam, (HWND)lParam);
case WM_NOTIFY:
switch (((NMHDR *)lParam)->code) {
//
// Sent when the user clicks on Apply OR OK !!
//
case PSN_APPLY:
//
// Do what ever action is necessary
//
ReturnStatus = WmiApplyChanges(ppi,
hDlg);
if (ReturnStatus)
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
DebugPrint((7, "WMI: Leave TRUE WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
hDlg, uMessage, wParam, lParam));
}
SetWindowLong(hDlg,
DWLP_MSGRESULT, ReturnStatus ?
PSNRET_NOERROR : PSNRET_INVALID);
return(TRUE);
case UDN_DELTAPOS:
{
LPNMUPDOWN UpDown = (LPNMUPDOWN)lParam;
//
// Array spinner has changed. Note that it is biased +1 as
// compared with the array index
//
DebugPrint((1, "WMIPROP: iPos = %d, iDelta = %d\n",
UpDown->iPos, UpDown->iDelta));
WmiSetArrayIndex(hDlg,
ppi,
UpDown->iPos + UpDown->iDelta - 1);
return(TRUE);
}
default:
break;
}
break;
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
DebugPrint((7, "WMI: Leave FALSE WmiDlgProc(%p, %d, 0x%x, 0x%x\n",
hDlg, uMessage, wParam, lParam));
return FALSE;
}
void
WmiUpdate (PPAGE_INFO ppi,
HWND hDlg)
{
}
BOOL
WmiContextMenu(
HWND HwndControl,
WORD Xpos,
WORD Ypos
)
{
return FALSE;
}
void
WmiHelp(
HWND ParentHwnd,
LPHELPINFO HelpInfo
)
{
}
//
// Debug support
//
#if DBG
#include <stdio.h> // for _vsnprintf
ULONG WmiDebug = 0;
CHAR WmiBuffer[DEBUG_BUFFER_LENGTH];
VOID
WmiDebugPrint(
ULONG DebugPrintLevel,
PCHAR DebugMessage,
...
)
/*++
Routine Description:
Debug print for properties pages - stolen from classpnp\class.c
Arguments:
Debug print level between 0 and 3, with 3 being the most verbose.
Return Value:
None
--*/
{
va_list ap;
va_start(ap, DebugMessage);
if ((DebugPrintLevel <= (WmiDebug & 0x0000ffff)) ||
((1 << (DebugPrintLevel + 15)) & WmiDebug)) {
_vsnprintf(WmiBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
OutputDebugStringA(WmiBuffer);
}
va_end(ap);
} // end WmiDebugPrint()
#else
//
// WmiDebugPrint stub
//
VOID
WmiDebugPrint(
ULONG DebugPrintLevel,
PCHAR DebugMessage,
...
)
{
}
#endif // DBG
HRESULT DifAddPropertyPageAdvanced(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN PTCHAR MachineName,
IN HANDLE MachineHandle
)
{
SP_ADDPROPERTYPAGE_DATA AddPropertyPageData;
BOOL b, PageAdded;
memset(&AddPropertyPageData, 0, sizeof(SP_ADDPROPERTYPAGE_DATA));
AddPropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
b = SetupDiGetClassInstallParams(DeviceInfoSet, DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
sizeof(SP_ADDPROPERTYPAGE_DATA), NULL );
if (b)
{
if (AddPropertyPageData.NumDynamicPages < MAX_INSTALLWIZARD_DYNAPAGES)
{
PageAdded = WmiPropPageProvider(DeviceInfoSet,
DeviceInfoData,
&AddPropertyPageData,
MachineName,
MachineHandle);
if (PageAdded)
{
b = SetupDiSetClassInstallParams(
DeviceInfoSet,
DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&AddPropertyPageData,
sizeof(SP_ADDPROPERTYPAGE_DATA));
if (! b)
{
DebugPrint((1, "WMIPROP: SetupDiSetClassInstallParams(%p, %p) failed %d\n",
DeviceInfoSet, DeviceInfoData, GetLastError()));
}
}
} else {
DebugPrint((1, "WMIPROP: Already %d property sheets\n",
AddPropertyPageData.NumDynamicPages));
}
} else {
DebugPrint((1, "WMIPROP: SetupDiGetClassInstallParams(%p, %p) failed %d\n",
DeviceInfoSet, DeviceInfoData, GetLastError()));
}
return(NO_ERROR);
}
//+---------------------------------------------------------------------------
//
// Function: MyCoInstaller
//
// Purpose: Responds to co-installer messages
//
// Arguments:
// InstallFunction [in]
// DeviceInfoSet [in]
// DeviceInfoData [in]
// Context [inout]
//
// Returns: NO_ERROR, ERROR_DI_POSTPROCESSING_REQUIRED, or an error code.
//
HRESULT
WmiPropCoInstaller (
IN DI_FUNCTION InstallFunction,
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN OUT PCOINSTALLER_CONTEXT_DATA Context
)
{
if (DeviceInfoData != NULL)
{
//
// Only try to display property page for devices and not for
// the class
//
switch (InstallFunction)
{
case DIF_ADDPROPERTYPAGE_ADVANCED:
{
DifAddPropertyPageAdvanced(DeviceInfoSet,
DeviceInfoData,
NULL,
NULL);
break;
}
case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
{
SP_DEVINFO_LIST_DETAIL_DATA Detail;
Detail.cbSize = sizeof(SP_DEVINFO_LIST_DETAIL_DATA);
if (SetupDiGetDeviceInfoListDetail(DeviceInfoSet,
&Detail))
{
DebugPrint((1, "WMIPROP: Adding remote property pages for %ws\n",
Detail.RemoteMachineName));
DifAddPropertyPageAdvanced(DeviceInfoSet,
DeviceInfoData,
Detail.RemoteMachineName,
Detail.RemoteMachineHandle);
} else {
DebugPrint((1, "WMIPROP: SetupDiGetDeviceInfoListDetailA failed %d\n",
GetLastError()));
}
break;
}
default:
{
break;
}
}
}
return NO_ERROR;
}
BOOL WINAPI
DllMain(
HINSTANCE DllInstance,
DWORD Reason,
PVOID Reserved
)
{
switch(Reason) {
case DLL_PROCESS_ATTACH: {
g_hInstance = DllInstance;
DisableThreadLibraryCalls(DllInstance);
break;
}
case DLL_PROCESS_DETACH: {
g_hInstance = NULL;
break;
}
default: {
break;
}
}
return TRUE;
}