mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5765 lines
162 KiB
5765 lines
162 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|