4908 lines
146 KiB
C
4908 lines
146 KiB
C
/*++
|
||
|
||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
||
Module Name:
|
||
|
||
regprop.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the API routines that reg and set registry
|
||
properties and operates on classes.
|
||
|
||
CM_Get_DevNode_Registry_Property
|
||
CM_Set_DevNode_Registry_Property
|
||
CM_Get_Class_Registry_Property
|
||
CM_Set_Class_Registry_Property
|
||
CM_Open_DevNode_Key
|
||
CM_Delete_DevNode_Key
|
||
CM_Open_Class_Key
|
||
CM_Enumerate_Classes
|
||
CM_Get_Class_Name
|
||
CM_Get_Class_Key_Name
|
||
CM_Delete_Class_Key
|
||
CM_Get_Device_Interface_Alias
|
||
CM_Get_Device_Interface_List
|
||
CM_Get_Device_Interface_List_Size
|
||
CM_Register_Device_Interface
|
||
CM_Unregister_Device_Interface
|
||
|
||
Author:
|
||
|
||
Paula Tomlinson (paulat) 6-22-1995
|
||
|
||
Environment:
|
||
|
||
User mode only.
|
||
|
||
Revision History:
|
||
|
||
22-Jun-1995 paulat
|
||
|
||
Creation and initial implementation.
|
||
|
||
--*/
|
||
|
||
|
||
//
|
||
// includes
|
||
//
|
||
#include "precomp.h"
|
||
#include "cfgi.h"
|
||
#include "setupapi.h"
|
||
#include "spapip.h"
|
||
#include "cmdat.h"
|
||
|
||
//
|
||
// Private prototypes
|
||
//
|
||
|
||
ULONG
|
||
GetPropertyDataType(
|
||
IN ULONG ulProperty
|
||
);
|
||
|
||
//
|
||
// use these from SetupAPI
|
||
//
|
||
PSECURITY_DESCRIPTOR
|
||
pSetupConvertTextToSD(
|
||
IN PCWSTR SDS,
|
||
OUT PULONG SecDescSize
|
||
);
|
||
|
||
PWSTR
|
||
pSetupConvertSDToText(
|
||
IN PSECURITY_DESCRIPTOR SD,
|
||
OUT PULONG pSDSSize
|
||
);
|
||
|
||
|
||
//
|
||
// global data
|
||
//
|
||
extern PVOID hLocalBindingHandle; // NOT MODIFIED BY THESE PROCEDURES
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_DevNode_Registry_Property_ExW(
|
||
IN DEVINST dnDevInst,
|
||
IN ULONG ulProperty,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves the specified value from the device instance's
|
||
registry storage key.
|
||
|
||
Parameters:
|
||
|
||
dnDevInst Supplies the handle of the device instance for which a
|
||
property is to be retrieved.
|
||
|
||
ulProperty Supplies an ordinal specifying the property to be retrieved.
|
||
(CM_DRP_*)
|
||
|
||
pulRegDataType Optionally, supplies the address of a variable that
|
||
will receive the registry data type for this property
|
||
(i.e., the REG_* constants).
|
||
|
||
Buffer Supplies the address of the buffer that receives the
|
||
registry data. Can be NULL when simply retrieving data size.
|
||
|
||
pulLength Supplies the address of the variable that contains the size,
|
||
in bytes, of the buffer. The API replaces the initial size
|
||
with the number of bytes of registry data copied to the buffer.
|
||
If the variable is initially zero, the API replaces it with
|
||
the buffer size needed to receive all the registry data. In
|
||
this case, the Buffer parameter is ignored.
|
||
|
||
ulFlags Must be zero.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_DEVINST,
|
||
CR_NO_SUCH_REGISTRY_KEY,
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_NO_SUCH_VALUE,
|
||
CR_REGISTRY_ERROR, or
|
||
CR_BUFFER_SMALL.
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR pDeviceID[MAX_DEVICE_ID_LEN];
|
||
ULONG ulSizeID = MAX_DEVICE_ID_LEN;
|
||
ULONG ulTempDataType=0, ulTransferLen=0;
|
||
ULONG ulGetProperty = ulProperty;
|
||
BYTE NullBuffer=0;
|
||
handle_t hBinding = NULL;
|
||
PVOID hStringTable = NULL;
|
||
BOOL Success;
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (dnDevInst == 0) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (!ARGUMENT_PRESENT(pulLength)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((!ARGUMENT_PRESENT(Buffer)) && (*pulLength != 0)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (ulProperty < CM_DRP_MIN || ulProperty > CM_DRP_MAX) {
|
||
Status = CR_INVALID_PROPERTY;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (ulProperty == CM_DRP_SECURITY_SDS) {
|
||
//
|
||
// translates operation
|
||
//
|
||
LPVOID tmpBuffer = NULL;
|
||
ULONG tmpBufferSize = 0;
|
||
ULONG datatype;
|
||
LPWSTR sds = NULL;
|
||
|
||
ulTempDataType = REG_SZ;
|
||
|
||
try {
|
||
Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
|
||
CM_DRP_SECURITY,
|
||
&datatype,
|
||
NULL,
|
||
&tmpBufferSize,
|
||
ulFlags,
|
||
hMachine);
|
||
if (Status != CR_SUCCESS && Status != CR_BUFFER_SMALL) {
|
||
leave;
|
||
}
|
||
tmpBuffer = pSetupMalloc(tmpBufferSize);
|
||
if (tmpBuffer == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
leave;
|
||
}
|
||
Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
|
||
CM_DRP_SECURITY,
|
||
&datatype,
|
||
tmpBuffer,
|
||
&tmpBufferSize,
|
||
ulFlags,
|
||
hMachine);
|
||
if (Status != CR_SUCCESS) {
|
||
leave;
|
||
}
|
||
|
||
//
|
||
// now translate
|
||
//
|
||
sds = pSetupConvertSDToText((PSECURITY_DESCRIPTOR)tmpBuffer,NULL);
|
||
if (sds == NULL) {
|
||
Status = CR_FAILURE;
|
||
leave;
|
||
}
|
||
ulTransferLen = (lstrlen(sds)+1) * sizeof(WCHAR); // required size
|
||
if (*pulLength == 0 || Buffer == NULL || *pulLength < ulTransferLen) {
|
||
//
|
||
// buffer too small, or buffer size wanted
|
||
// required buffer size
|
||
//
|
||
Status = CR_BUFFER_SMALL;
|
||
*pulLength = ulTransferLen;
|
||
ulTransferLen = 0;
|
||
} else {
|
||
//
|
||
// copy data
|
||
//
|
||
memcpy(Buffer,sds,ulTransferLen);
|
||
*pulLength = ulTransferLen;
|
||
}
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
if (tmpBuffer != NULL) {
|
||
pSetupFree(tmpBuffer);
|
||
}
|
||
if (sds != NULL) {
|
||
//
|
||
// must use LocalFree
|
||
//
|
||
LocalFree(sds);
|
||
}
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
} else {
|
||
//
|
||
// setup rpc binding handle and string table handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// retrieve the string form of the device id string
|
||
//
|
||
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulSizeID);
|
||
if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// NOTE: The ulTransferLen variable is just used to control
|
||
// how much data is marshalled via rpc between address spaces.
|
||
// ulTransferLen should be set on entry to the size of the Buffer.
|
||
// The last parameter should also be the size of the Buffer on entry
|
||
// and on exit contains either the amount transferred (if a transfer
|
||
// occured) or the amount required, this value should be passed back
|
||
// in the callers pulLength parameter.
|
||
//
|
||
ulTransferLen = *pulLength;
|
||
if (Buffer == NULL) {
|
||
Buffer = &NullBuffer;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_GetDeviceRegProp(
|
||
hBinding, // rpc binding handle
|
||
pDeviceID, // string representation of device instance
|
||
ulGetProperty, // id for the property
|
||
&ulTempDataType, // receives registry data type
|
||
Buffer, // receives registry data
|
||
&ulTransferLen, // input/output buffer size
|
||
pulLength, // bytes copied (or bytes required)
|
||
ulFlags); // not used
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_GetDeviceRegProp caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
}
|
||
|
||
if (pulRegDataType != NULL) {
|
||
//
|
||
// I pass a temp variable to the rpc stubs since they require the
|
||
// output param to always be valid, then if user did pass in a valid
|
||
// pointer to receive the info, do the assignment now
|
||
//
|
||
*pulRegDataType = ulTempDataType;
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_DevNode_Registry_Property_ExW
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Set_DevNode_Registry_Property_ExW(
|
||
IN DEVINST dnDevInst,
|
||
IN ULONG ulProperty,
|
||
IN PCVOID Buffer OPTIONAL,
|
||
IN OUT ULONG ulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the specified value in the device instance's registry
|
||
storage key.
|
||
|
||
Parameters:
|
||
|
||
dnDevInst Supplies the handle of the device instance for which a
|
||
property is to be retrieved.
|
||
|
||
ulProperty Supplies an ordinal specifying the property to be set.
|
||
(CM_DRP_*)
|
||
|
||
Buffer Supplies the address of the buffer that contains the
|
||
registry data. This data must be of the proper type
|
||
for that property.
|
||
|
||
ulLength Supplies the number of bytes of registry data to write.
|
||
|
||
ulFlags Must be zero.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_NO_SUCH_REGISTRY_KEY,
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_NO_SUCH_VALUE,
|
||
CR_REGISTRY_ERROR,
|
||
CR_OUT_OF_MEMORY,
|
||
CR_INVALID_DATA, or
|
||
CR_BUFFER_SMALL.
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR pDeviceID [MAX_DEVICE_ID_LEN];
|
||
ULONG ulRegDataType = 0, ulLen = MAX_DEVICE_ID_LEN;
|
||
BYTE NullBuffer = 0x0;
|
||
handle_t hBinding = NULL;
|
||
PVOID hStringTable = NULL;
|
||
BOOL Success;
|
||
PVOID Buffer2 = NULL;
|
||
PVOID Buffer3 = NULL;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (dnDevInst == 0) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((!ARGUMENT_PRESENT(Buffer)) && (ulLength != 0)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (ulProperty < CM_DRP_MIN || ulProperty > CM_DRP_MAX) {
|
||
Status = CR_INVALID_PROPERTY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup rpc binding handle and string table handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// retrieve the string form of the device id string
|
||
//
|
||
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pDeviceID,&ulLen);
|
||
if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
|
||
Status = CR_INVALID_DEVNODE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// we need to specify what registry data to use for storing this data
|
||
//
|
||
ulRegDataType = GetPropertyDataType(ulProperty);
|
||
|
||
//
|
||
// if data type is REG_DWORD, make sure size is right
|
||
//
|
||
if((ulRegDataType == REG_DWORD) && ulLength && (ulLength != sizeof(DWORD))) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// if the register is CM_DRP_SECURITY_SDS, convert it
|
||
//
|
||
if (ulProperty == CM_DRP_SECURITY_SDS) {
|
||
if (ulLength) {
|
||
//
|
||
// this form of CM_DRP_SECURITY provides a string that needs to be converted to binary
|
||
//
|
||
PCWSTR UnicodeSecDesc = (PCWSTR)Buffer;
|
||
|
||
Buffer2 = pSetupConvertTextToSD(UnicodeSecDesc,&ulLength);
|
||
if (Buffer2 == NULL) {
|
||
//
|
||
// If last error is ERROR_SCE_DISABLED, then the failure is
|
||
// due to SCE APIs being "turned off" on Embedded. Treat
|
||
// this as a (successful) no-op...
|
||
//
|
||
if(GetLastError() == ERROR_SCE_DISABLED) {
|
||
Status = CR_SUCCESS;
|
||
} else {
|
||
Status = CR_INVALID_DATA;
|
||
}
|
||
goto Clean0;
|
||
}
|
||
Buffer = Buffer2;
|
||
}
|
||
ulProperty = CM_DRP_SECURITY;
|
||
ulRegDataType = REG_BINARY;
|
||
}
|
||
|
||
//
|
||
// if data type is REG_MULTI_SZ, make sure it is double-NULL terminated
|
||
//
|
||
if ((ulRegDataType == REG_MULTI_SZ) && (ulLength != 0)) {
|
||
|
||
ULONG ulNewLength;
|
||
PWSTR tmpBuffer, bufferEnd;
|
||
|
||
ulLength &= ~(ULONG)1;
|
||
tmpBuffer = (PWSTR)Buffer;
|
||
bufferEnd = (PWSTR)((PUCHAR)tmpBuffer + ulLength);
|
||
ulNewLength = ulLength;
|
||
while (tmpBuffer < bufferEnd && *tmpBuffer != TEXT('\0')) {
|
||
|
||
while (tmpBuffer < bufferEnd && *tmpBuffer != TEXT('\0')) {
|
||
|
||
tmpBuffer++;
|
||
}
|
||
if (tmpBuffer >= bufferEnd) {
|
||
|
||
ulNewLength += sizeof(TEXT('\0'));;
|
||
} else {
|
||
|
||
tmpBuffer++;
|
||
}
|
||
}
|
||
if (tmpBuffer >= bufferEnd) {
|
||
|
||
ulNewLength += sizeof(TEXT('\0'));;
|
||
} else {
|
||
|
||
ulNewLength = ((ULONG)(tmpBuffer - (PWSTR)Buffer) + 1) * sizeof(WCHAR);
|
||
}
|
||
if (ulNewLength > ulLength) {
|
||
|
||
Buffer3 = pSetupMalloc(ulNewLength);
|
||
if (Buffer3 == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
memcpy(Buffer3, Buffer, ulLength);
|
||
memset((PUCHAR)Buffer3 + ulLength, 0, ulNewLength - ulLength);
|
||
Buffer = Buffer3;
|
||
}
|
||
ulLength = ulNewLength;
|
||
}
|
||
|
||
if (Buffer == NULL) {
|
||
Buffer = &NullBuffer;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_SetDeviceRegProp(
|
||
hBinding, // rpc binding handle
|
||
pDeviceID, // string representation of devinst
|
||
ulProperty, // string name for property
|
||
ulRegDataType, // specify registry data type
|
||
(LPBYTE)Buffer, // receives registry data
|
||
ulLength, // amount to return in Buffer
|
||
ulFlags); // not used
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_SetDeviceRegProp caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
if (Buffer3) {
|
||
|
||
pSetupFree(Buffer3);
|
||
}
|
||
|
||
if (Buffer2) {
|
||
//
|
||
// SceSvc requires LocalFree
|
||
//
|
||
LocalFree(Buffer2);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Set_DevNode_Registry_Property_ExW
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_Registry_PropertyW(
|
||
IN LPGUID ClassGUID,
|
||
IN ULONG ulProperty,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves the specified value from the classes's
|
||
registry storage key.
|
||
|
||
Parameters:
|
||
|
||
ClassGUID Supplies the Class GUID.
|
||
|
||
ulProperty Supplies an ordinal specifying the property to be retrieved.
|
||
(CM_DRP_*)
|
||
|
||
pulRegDataType Optionally, supplies the address of a variable that
|
||
will receive the registry data type for this property
|
||
(i.e., the REG_* constants).
|
||
|
||
Buffer Supplies the address of the buffer that receives the
|
||
registry data. Can be NULL when simply retrieving data size.
|
||
|
||
pulLength Supplies the address of the variable that contains the size,
|
||
in bytes, of the buffer. The API replaces the initial size
|
||
with the number of bytes of registry data copied to the buffer.
|
||
If the variable is initially zero, the API replaces it with
|
||
the buffer size needed to receive all the registry data. In
|
||
this case, the Buffer parameter is ignored.
|
||
|
||
ulFlags Must be zero.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_DEVINST,
|
||
CR_NO_SUCH_REGISTRY_KEY,
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_NO_SUCH_VALUE,
|
||
CR_REGISTRY_ERROR, or
|
||
CR_BUFFER_SMALL.
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
ULONG ulTempDataType=0, ulTransferLen=0;
|
||
BYTE NullBuffer=0;
|
||
handle_t hBinding = NULL;
|
||
BOOL Success;
|
||
WCHAR szStringGuid[MAX_GUID_STRING_LEN];
|
||
ULONG ulGetProperty = ulProperty;
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(ClassGUID)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (!ARGUMENT_PRESENT(pulLength)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((!ARGUMENT_PRESENT(Buffer)) && (*pulLength != 0)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// convert from guid to string
|
||
//
|
||
if (pSetupStringFromGuid(ClassGUID, szStringGuid,MAX_GUID_STRING_LEN) != NO_ERROR) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (ulProperty < CM_CRP_MIN || ulProperty > CM_CRP_MAX) {
|
||
Status = CR_INVALID_PROPERTY;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (ulProperty == CM_CRP_SECURITY_SDS) {
|
||
//
|
||
// translates operation
|
||
//
|
||
LPVOID tmpBuffer = NULL;
|
||
ULONG tmpBufferSize = 0;
|
||
ULONG datatype;
|
||
LPWSTR sds = NULL;
|
||
|
||
ulTempDataType = REG_SZ;
|
||
|
||
try {
|
||
Status = CM_Get_Class_Registry_PropertyW(ClassGUID,CM_CRP_SECURITY,&datatype,NULL,&tmpBufferSize,ulFlags,hMachine);
|
||
if (Status != CR_SUCCESS && Status != CR_BUFFER_SMALL) {
|
||
leave;
|
||
}
|
||
tmpBuffer = pSetupMalloc(tmpBufferSize);
|
||
if (tmpBuffer == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
leave;
|
||
}
|
||
Status = CM_Get_Class_Registry_PropertyW(ClassGUID,CM_CRP_SECURITY,&datatype,tmpBuffer,&tmpBufferSize,ulFlags,hMachine);
|
||
if (Status != CR_SUCCESS) {
|
||
leave;
|
||
}
|
||
|
||
//
|
||
// now translate
|
||
//
|
||
sds = pSetupConvertSDToText((PSECURITY_DESCRIPTOR)tmpBuffer,NULL);
|
||
if (sds == NULL) {
|
||
Status = CR_FAILURE;
|
||
leave;
|
||
}
|
||
ulTransferLen = (lstrlen(sds)+1) * sizeof(WCHAR); // required size
|
||
if (*pulLength == 0 || Buffer == NULL || *pulLength < ulTransferLen) {
|
||
//
|
||
// buffer too small, or buffer size wanted
|
||
// required buffer size
|
||
//
|
||
Status = CR_BUFFER_SMALL;
|
||
*pulLength = ulTransferLen;
|
||
ulTransferLen = 0;
|
||
} else {
|
||
//
|
||
// copy data
|
||
//
|
||
memcpy(Buffer,sds,ulTransferLen);
|
||
*pulLength = ulTransferLen;
|
||
}
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
if (tmpBuffer != NULL) {
|
||
pSetupFree(tmpBuffer);
|
||
}
|
||
if (sds != NULL) {
|
||
//
|
||
// must use LocalFree
|
||
//
|
||
LocalFree(sds);
|
||
}
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// setup rpc binding handle and string table handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// NOTE: The ulTransferLen variable is just used to control
|
||
// how much data is marshalled via rpc between address spaces.
|
||
// ulTransferLen should be set on entry to the size of the Buffer.
|
||
// The last parameter should also be the size of the Buffer on entry
|
||
// and on exit contains either the amount transferred (if a transfer
|
||
// occured) or the amount required, this value should be passed back
|
||
// in the callers pulLength parameter.
|
||
//
|
||
ulTransferLen = *pulLength;
|
||
if (Buffer == NULL) {
|
||
Buffer = &NullBuffer;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_GetClassRegProp(
|
||
hBinding, // rpc binding handle
|
||
szStringGuid, // string representation of class
|
||
ulGetProperty, // id for the property
|
||
&ulTempDataType, // receives registry data type
|
||
Buffer, // receives registry data
|
||
&ulTransferLen, // input/output buffer size
|
||
pulLength, // bytes copied (or bytes required)
|
||
ulFlags); // not used
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_GetClassRegProp caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
}
|
||
|
||
if (pulRegDataType != NULL) {
|
||
//
|
||
// I pass a temp variable to the rpc stubs since they require the
|
||
// output param to always be valid, then if user did pass in a valid
|
||
// pointer to receive the info, do the assignment now
|
||
//
|
||
*pulRegDataType = ulTempDataType;
|
||
}
|
||
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Class_Registry_PropertyW
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Set_Class_Registry_PropertyW(
|
||
IN LPGUID ClassGUID,
|
||
IN ULONG ulProperty,
|
||
IN PCVOID Buffer OPTIONAL,
|
||
IN ULONG ulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the specified value in the device instance's registry
|
||
storage key.
|
||
|
||
Parameters:
|
||
|
||
ClassGUID Supplies the Class GUID.
|
||
|
||
ulProperty Supplies an ordinal specifying the property to be set.
|
||
(CM_DRP_*)
|
||
|
||
Buffer Supplies the address of the buffer that contains the
|
||
registry data. This data must be of the proper type
|
||
for that property.
|
||
|
||
ulLength Supplies the number of bytes of registry data to write.
|
||
|
||
ulFlags Must be zero.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_NO_SUCH_REGISTRY_KEY,
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_NO_SUCH_VALUE,
|
||
CR_REGISTRY_ERROR,
|
||
CR_OUT_OF_MEMORY,
|
||
CR_INVALID_DATA, or
|
||
CR_BUFFER_SMALL.
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
ULONG ulRegDataType = 0, ulLen = MAX_DEVICE_ID_LEN;
|
||
BYTE NullBuffer = 0x0;
|
||
handle_t hBinding = NULL;
|
||
BOOL Success;
|
||
WCHAR szStringGuid[MAX_GUID_STRING_LEN];
|
||
PVOID Buffer2 = NULL;
|
||
PVOID Buffer3 = NULL;
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(ClassGUID)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((!ARGUMENT_PRESENT(Buffer)) && (ulLength != 0)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// convert from guid to string
|
||
//
|
||
if (pSetupStringFromGuid(ClassGUID, szStringGuid,MAX_GUID_STRING_LEN) != NO_ERROR) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (ulProperty < CM_CRP_MIN || ulProperty > CM_CRP_MAX) {
|
||
Status = CR_INVALID_PROPERTY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup rpc binding handle and string table handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// we need to specify what registry data to use for storing this data
|
||
//
|
||
ulRegDataType = GetPropertyDataType(ulProperty);
|
||
|
||
//
|
||
// if data type is REG_DWORD, make sure size is right
|
||
//
|
||
if((ulRegDataType == REG_DWORD) && ulLength && (ulLength != sizeof(DWORD))) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// if the register is CM_CRP_SECURITY_SDS, convert it
|
||
//
|
||
if (ulProperty == CM_CRP_SECURITY_SDS) {
|
||
if (ulLength) {
|
||
//
|
||
// this form of CM_CRP_SECURITY provides a string that needs to be converted to binary
|
||
//
|
||
PCWSTR UnicodeSecDesc = (PCWSTR)Buffer;
|
||
|
||
Buffer2 = pSetupConvertTextToSD(UnicodeSecDesc,&ulLength);
|
||
if (Buffer2 == NULL) {
|
||
//
|
||
// If last error is ERROR_SCE_DISABLED, then the failure is
|
||
// due to SCE APIs being "turned off" on Embedded. Treat
|
||
// this as a (successful) no-op...
|
||
//
|
||
if(GetLastError() == ERROR_SCE_DISABLED) {
|
||
Status = CR_SUCCESS;
|
||
} else {
|
||
Status = CR_INVALID_DATA;
|
||
}
|
||
goto Clean0;
|
||
}
|
||
Buffer = Buffer2;
|
||
}
|
||
ulProperty = CM_CRP_SECURITY;
|
||
ulRegDataType = REG_BINARY;
|
||
}
|
||
|
||
//
|
||
// if data type is REG_MULTI_SZ, make sure it is double-NULL terminated
|
||
//
|
||
if ((ulRegDataType == REG_MULTI_SZ) && (ulLength != 0)) {
|
||
|
||
ULONG ulNewLength;
|
||
PWSTR tmpBuffer, bufferEnd;
|
||
|
||
ulLength &= ~(ULONG)1;
|
||
tmpBuffer = (PWSTR)Buffer;
|
||
bufferEnd = (PWSTR)((PUCHAR)tmpBuffer + ulLength);
|
||
ulNewLength = ulLength;
|
||
while (tmpBuffer < bufferEnd && *tmpBuffer != TEXT('\0')) {
|
||
|
||
while (tmpBuffer < bufferEnd && *tmpBuffer != TEXT('\0')) {
|
||
|
||
tmpBuffer++;
|
||
}
|
||
if (tmpBuffer >= bufferEnd) {
|
||
|
||
ulNewLength += sizeof(TEXT('\0'));;
|
||
} else {
|
||
|
||
tmpBuffer++;
|
||
}
|
||
}
|
||
if (tmpBuffer >= bufferEnd) {
|
||
|
||
ulNewLength += sizeof(TEXT('\0'));;
|
||
} else {
|
||
|
||
ulNewLength = ((ULONG)(tmpBuffer - (PWSTR)Buffer) + 1) * sizeof(WCHAR);
|
||
}
|
||
if (ulNewLength > ulLength) {
|
||
|
||
Buffer3 = pSetupMalloc(ulNewLength);
|
||
if (Buffer3 == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
memcpy(Buffer3, Buffer, ulLength);
|
||
memset((PUCHAR)Buffer3 + ulLength, 0, ulNewLength - ulLength);
|
||
Buffer = Buffer3;
|
||
}
|
||
ulLength = ulNewLength;
|
||
}
|
||
|
||
if (Buffer == NULL) {
|
||
Buffer = &NullBuffer;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_SetClassRegProp(
|
||
hBinding, // rpc binding handle
|
||
szStringGuid, // string representation of class
|
||
ulProperty, // string name for property
|
||
ulRegDataType, // specify registry data type
|
||
(LPBYTE)Buffer, // receives registry data
|
||
ulLength, // amount to return in Buffer
|
||
ulFlags); // not used
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_SetClassRegProp caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
if (Buffer2) {
|
||
//
|
||
// SceSvc requires LocalFree
|
||
//
|
||
LocalFree(Buffer2);
|
||
}
|
||
|
||
if (Buffer3) {
|
||
pSetupFree(Buffer3);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Set_Class_Registry_Property_ExW
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Open_DevNode_Key_Ex(
|
||
IN DEVINST dnDevNode,
|
||
IN REGSAM samDesired,
|
||
IN ULONG ulHardwareProfile,
|
||
IN REGDISPOSITION Disposition,
|
||
OUT PHKEY phkDevice,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens the software storage registry key associated with a
|
||
device instance.
|
||
|
||
Parameters:
|
||
|
||
dnDevNode Handle of a device instance. This handle is typically
|
||
retrieved by a call to CM_Locate_DevNode or
|
||
CM_Create_DevNode.
|
||
|
||
samDesired Specifies an access mask that describes the desired
|
||
security access for the key. This parameter can be
|
||
a combination of the values used in calls to RegOpenKeyEx.
|
||
|
||
ulHardwareProfile Supplies the handle of the hardware profile to open the
|
||
storage key under. This parameter is only used if the
|
||
CM_REGISTRY_CONFIG flag is specified in ulFlags. If
|
||
this parameter is 0, the API uses the current hardware
|
||
profile.
|
||
|
||
Disposition Specifies how the registry key is to be opened. May be
|
||
one of the following values:
|
||
|
||
RegDisposition_OpenAlways - Open the key if it exists,
|
||
otherwise, create the key.
|
||
RegDisposition_OpenExisting - Open the key only if it
|
||
exists, otherwise fail with CR_NO_SUCH_REGISTRY_VALUE.
|
||
|
||
phkDevice Supplies the address of the variable that receives an
|
||
opened handle to the specified key. When access to this
|
||
key is completed, it must be closed via RegCloseKey.
|
||
|
||
ulFlags Specifies what type of storage key should be opened.
|
||
Can be a combination of these values:
|
||
|
||
CM_REGISTRY_HARDWARE (0x00000000)
|
||
Open a key for storing driver-independent information
|
||
relating to the device instance. On Windows NT, the
|
||
full path to such a storage key is of the form:
|
||
|
||
HKLM\System\CurrentControlSet\Enum\<enumerator>\
|
||
<DeviceID>\<InstanceID>\Device Parameters
|
||
|
||
CM_REGISTRY_SOFTWARE (0x00000001)
|
||
Open a key for storing driver-specific information
|
||
relating to the device instance. On Windows NT, the
|
||
full path to such a storage key is of the form:
|
||
|
||
HKLM\System\CurrentControlSet\Control\Class\
|
||
<DevNodeClass>\<ClassInstanceOrdinal>
|
||
|
||
CM_REGISTRY_USER (0x00000100)
|
||
Open a key under HKEY_CURRENT_USER instead of
|
||
HKEY_LOCAL_MACHINE. This flag may not be used with
|
||
CM_REGISTRY_CONFIG. There is no analagous kernel-mode
|
||
API on NT to get a per-user device configuration
|
||
storage, since this concept does not apply to device
|
||
drivers (no user may be logged on, etc). However,
|
||
this flag is provided for consistency with Win95, and
|
||
because it is foreseeable that it could be useful to
|
||
Win32 services that interact with Plug-and-Play model.
|
||
|
||
CM_REGISTRY_CONFIG (0x00000200)
|
||
Open the key under a hardware profile branch instead
|
||
of HKEY_LOCAL_MACHINE. If this flag is specified,
|
||
then ulHardwareProfile supplies the handle of the
|
||
hardware profile to be used. This flag may not be
|
||
used with CM_REGISTRY_USER.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_DEVICE_ID,
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER, or
|
||
CR_REGISTRY_ERROR
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
LONG RegStatus = ERROR_SUCCESS;
|
||
PWSTR pszMachineName = NULL;
|
||
WCHAR pDeviceID[MAX_DEVICE_ID_LEN];
|
||
HKEY hKey=NULL, hRemoteKey=NULL, hBranchKey=NULL;
|
||
PWSTR pszKey = NULL, pszPrivateKey = NULL;
|
||
PVOID hStringTable = NULL;
|
||
handle_t hBinding = NULL;
|
||
ULONG ulLen = MAX_DEVICE_ID_LEN;
|
||
BOOL Success;
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(phkDevice)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
*phkDevice = NULL;
|
||
|
||
if (dnDevNode == 0) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, CM_REGISTRY_BITS)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(Disposition, RegDisposition_Bits)) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((ulFlags & CM_REGISTRY_CONFIG) &&
|
||
(ulHardwareProfile > MAX_CONFIG_VALUE)) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup rpc binding handle and string table handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((hBinding != hLocalBindingHandle) && (ulFlags & CM_REGISTRY_USER)) {
|
||
Status = CR_ACCESS_DENIED; // current user key can't be remoted
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// retrieve the device id string and validate it
|
||
//
|
||
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevNode,pDeviceID,&ulLen);
|
||
if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
|
||
Status = CR_INVALID_DEVNODE;
|
||
goto Clean0;
|
||
}
|
||
|
||
|
||
//-------------------------------------------------------------
|
||
// determine the branch key to use; either HKLM or HKCU
|
||
//-------------------------------------------------------------
|
||
|
||
if (hBinding == hLocalBindingHandle) {
|
||
|
||
if (ulFlags & CM_REGISTRY_USER) {
|
||
hBranchKey = HKEY_CURRENT_USER;
|
||
}
|
||
else {
|
||
//
|
||
// all other cases go to HKLM (validate permission first?)
|
||
//
|
||
hBranchKey = HKEY_LOCAL_MACHINE;
|
||
}
|
||
}
|
||
else {
|
||
//
|
||
// retrieve machine name
|
||
//
|
||
pszMachineName = pSetupMalloc((MAX_PATH + 3)*sizeof(WCHAR));
|
||
if (pszMachineName == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
PnPRetrieveMachineName(hMachine, pszMachineName);
|
||
|
||
//
|
||
// use remote HKLM branch (we only support connect to
|
||
// HKEY_LOCAL_MACHINE on the remote machine, not HKEY_CURRENT_USER)
|
||
//
|
||
RegStatus = RegConnectRegistry(pszMachineName, HKEY_LOCAL_MACHINE,
|
||
&hRemoteKey);
|
||
|
||
pSetupFree(pszMachineName);
|
||
pszMachineName = NULL;
|
||
|
||
if (RegStatus != ERROR_SUCCESS) {
|
||
Status = CR_REGISTRY_ERROR;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// hBranchKey is either a predefined key or assigned to by
|
||
// another key, I never attempt to close it. If hRemoteKey is
|
||
// non-NULL I will attempt to close it during cleanup since
|
||
// it is explicitly opened.
|
||
//
|
||
hBranchKey = hRemoteKey;
|
||
}
|
||
|
||
//
|
||
// allocate some buffer space to work with
|
||
//
|
||
pszKey = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
|
||
if (pszKey == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
pszPrivateKey = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
|
||
if (pszPrivateKey == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// form the registry path based on the device id and the flags.
|
||
//
|
||
Status = GetDevNodeKeyPath(hBinding, pDeviceID, ulFlags,
|
||
ulHardwareProfile, pszKey, pszPrivateKey);
|
||
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
|
||
lstrcat(pszKey, TEXT("\\"));
|
||
lstrcat(pszKey, pszPrivateKey);
|
||
|
||
pSetupFree(pszPrivateKey);
|
||
pszPrivateKey = NULL;
|
||
|
||
//
|
||
// open the registry key (method of open is based on flags)
|
||
//
|
||
if (Disposition == RegDisposition_OpenAlways) {
|
||
|
||
//-----------------------------------------------------
|
||
// open the registry key always
|
||
//-----------------------------------------------------
|
||
|
||
//
|
||
// Only the main Enum subtree under HKLM has strict security
|
||
// that requires me to first create the key on the server
|
||
// side and then open it here on the client side. This
|
||
// condition currently only occurs if the flags have
|
||
// CM_REGISTRY_HARDWARE set but no other flags set.
|
||
//
|
||
if (ulFlags == CM_REGISTRY_HARDWARE) {
|
||
//
|
||
// first try to open it (in case it already exists). If it
|
||
// doesn't exist, then I'll have to have the protected server
|
||
// side create the key. I still need to open it from here, the
|
||
// client-side, so that the registry handle will be in the
|
||
// caller's address space.
|
||
//
|
||
RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
pszKey,
|
||
0,
|
||
samDesired,
|
||
phkDevice);
|
||
|
||
if (RegStatus != ERROR_SUCCESS) {
|
||
|
||
//
|
||
// call server side to create the key
|
||
//
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_CreateKey(
|
||
hBinding,
|
||
pDeviceID,
|
||
samDesired,
|
||
0);
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_CreateKey caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (Status != CR_SUCCESS) {
|
||
*phkDevice = NULL;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// the key was created successfully, so open it now
|
||
//
|
||
RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
pszKey,
|
||
0,
|
||
samDesired,
|
||
phkDevice);
|
||
|
||
if (RegStatus == ERROR_ACCESS_DENIED) {
|
||
*phkDevice = NULL;
|
||
Status = CR_ACCESS_DENIED;
|
||
goto Clean0;
|
||
}
|
||
else if (RegStatus != ERROR_SUCCESS) {
|
||
//
|
||
// if we still can't open the key, I give up
|
||
//
|
||
*phkDevice = NULL;
|
||
Status = CR_REGISTRY_ERROR;
|
||
goto Clean0;
|
||
}
|
||
}
|
||
}
|
||
|
||
else {
|
||
//
|
||
// these keys have admin-full privilege so try to open
|
||
// from the client-side and just let the security of the
|
||
// key judge whether the caller can access it.
|
||
//
|
||
RegStatus = RegCreateKeyEx(hBranchKey,
|
||
pszKey,
|
||
0,
|
||
NULL,
|
||
REG_OPTION_NON_VOLATILE,
|
||
samDesired,
|
||
NULL,
|
||
phkDevice,
|
||
NULL);
|
||
|
||
if (RegStatus == ERROR_ACCESS_DENIED) {
|
||
*phkDevice = NULL;
|
||
Status = CR_ACCESS_DENIED;
|
||
goto Clean0;
|
||
}
|
||
else if (RegStatus != ERROR_SUCCESS) {
|
||
*phkDevice = NULL;
|
||
Status = CR_REGISTRY_ERROR;
|
||
goto Clean0;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
|
||
//-----------------------------------------------------
|
||
// open only if it already exists
|
||
//-----------------------------------------------------
|
||
|
||
//
|
||
// the actual open always occurs on the client side so I can
|
||
// pass back a handle that's valid for the calling process.
|
||
// Only creates need to happen on the server side
|
||
//
|
||
RegStatus = RegOpenKeyEx(hBranchKey,
|
||
pszKey,
|
||
0,
|
||
samDesired,
|
||
phkDevice);
|
||
|
||
if (RegStatus == ERROR_ACCESS_DENIED) {
|
||
*phkDevice = NULL;
|
||
Status = CR_ACCESS_DENIED;
|
||
goto Clean0;
|
||
}
|
||
else if (RegStatus != ERROR_SUCCESS) {
|
||
*phkDevice = NULL;
|
||
Status = CR_NO_SUCH_REGISTRY_KEY;
|
||
}
|
||
}
|
||
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
|
||
//
|
||
// Reference the following variables so the compiler will respect
|
||
// statement ordering w.r.t. their assignment.
|
||
//
|
||
pszMachineName = pszMachineName;
|
||
pszPrivateKey = pszPrivateKey;
|
||
pszKey = pszKey;
|
||
}
|
||
|
||
if (pszMachineName) {
|
||
pSetupFree(pszMachineName);
|
||
}
|
||
|
||
if (pszPrivateKey) {
|
||
pSetupFree(pszPrivateKey);
|
||
}
|
||
|
||
if (pszKey) {
|
||
pSetupFree(pszKey);
|
||
}
|
||
|
||
if (hKey != NULL) {
|
||
RegCloseKey(hKey);
|
||
}
|
||
if (hRemoteKey != NULL) {
|
||
RegCloseKey(hRemoteKey);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Open_DevNode_Key_ExW
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Delete_DevNode_Key_Ex(
|
||
IN DEVNODE dnDevNode,
|
||
IN ULONG ulHardwareProfile,
|
||
IN ULONG ulFlags,
|
||
IN HANDLE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes a registry storage key associated with a device
|
||
instance.
|
||
|
||
dnDevNode Handle of a device instance. This handle is typically
|
||
retrieved by a call to CM_Locate_DevNode or CM_Create_DevNode.
|
||
|
||
ulHardwareProfile Supplies the handle of the hardware profile to delete
|
||
the storage key under. This parameter is only used if the
|
||
CM_REGISTRY_CONFIG flag is specified in ulFlags. If this
|
||
parameter is 0, the API uses the current hardware profile.
|
||
If this parameter is 0xFFFFFFFF, then the specified storage
|
||
key(s) for all hardware profiles is (are) deleted.
|
||
|
||
ulFlags Specifies what type(s) of storage key(s) should be deleted.
|
||
Can be a combination of these values:
|
||
|
||
CM_REGISTRY_HARDWARE - Delete the key for storing driver-
|
||
independent information relating to the device instance.
|
||
This may be combined with CM_REGISTRY_SOFTWARE to delete
|
||
both device and driver keys simultaneously.
|
||
CM_REGISTRY_SOFTWARE - Delete the key for storing driver-
|
||
specific information relating to the device instance.
|
||
This may be combined with CM_REGISTRY_HARDWARE to
|
||
delete both driver and device keys simultaneously.
|
||
CM_REGISTRY_USER - Delete the specified key(s) under
|
||
HKEY_CURRENT_USER instead of HKEY_LOCAL_MACHINE.
|
||
This flag may not be used with CM_REGISTRY_CONFIG.
|
||
CM_REGISTRY_CONFIG - Delete the specified keys(s) under a
|
||
hardware profile branch instead of HKEY_LOCAL_MACHINE.
|
||
If this flag is specified, then ulHardwareProfile
|
||
supplies the handle to the hardware profile to be used.
|
||
This flag may not be used with CM_REGISTRY_USER.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG,
|
||
CR_REGISTRY_ERROR
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
LONG RegStatus = ERROR_SUCCESS;
|
||
PVOID hStringTable = NULL;
|
||
handle_t hBinding = NULL;
|
||
HKEY hKey = NULL;
|
||
PWSTR pszParentKey = NULL, pszChildKey = NULL, pszRegStr = NULL;
|
||
WCHAR pDeviceID[MAX_DEVICE_ID_LEN], szProfile[MAX_PROFILE_ID_LEN];
|
||
ULONG ulIndex = 0, ulSize = 0,ulLen = MAX_DEVICE_ID_LEN;
|
||
BOOL Success;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (dnDevNode == 0) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, CM_REGISTRY_BITS)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((ulFlags & CM_REGISTRY_USER) && (ulFlags & CM_REGISTRY_CONFIG)) {
|
||
Status = CR_INVALID_FLAG; // can't specify both
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup string table handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// retrieve the device id string and validate it
|
||
//
|
||
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevNode,pDeviceID,&ulLen);
|
||
if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
|
||
Status = CR_INVALID_DEVNODE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// allocate some buffer space to work with
|
||
//
|
||
pszParentKey = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
|
||
if (pszParentKey == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
pszChildKey = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
|
||
if (pszChildKey == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
pszRegStr = pSetupMalloc(MAX_CM_PATH*sizeof(WCHAR));
|
||
if (pszRegStr == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// form the registry path based on the device id and the flags.
|
||
//
|
||
Status = GetDevNodeKeyPath(hBinding, pDeviceID, ulFlags,
|
||
ulHardwareProfile, pszParentKey, pszChildKey);
|
||
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
|
||
|
||
//------------------------------------------------------------------
|
||
// For either hw and sw user keys, the client side is privileged
|
||
// enough to do the delete (if the caller doesn't have admin, it
|
||
// will be denied but that is the desired behaviour). Also, the
|
||
// service-side cannot access the HKEY_CURRENT_USER key unless it
|
||
// does some sort of impersonation.
|
||
//------------------------------------------------------------------
|
||
|
||
if (ulFlags & CM_REGISTRY_USER) {
|
||
//
|
||
// handle the special config-specific case when the profile
|
||
// specified is -1, then need to delete the private key
|
||
// for all profiles
|
||
//
|
||
if ((ulFlags & CM_REGISTRY_CONFIG) &&
|
||
(ulHardwareProfile == 0xFFFFFFFF)) {
|
||
|
||
wsprintf(pszRegStr, TEXT("%s\\%s"),
|
||
pszRegPathIDConfigDB,
|
||
pszRegKeyKnownDockingStates);
|
||
|
||
RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
pszRegStr,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&hKey);
|
||
|
||
//
|
||
// enumerate the hardware profile keys
|
||
//
|
||
for (ulIndex = 0; RegStatus == ERROR_SUCCESS; ulIndex++) {
|
||
|
||
ulSize = MAX_PROFILE_ID_LEN * sizeof(WCHAR);
|
||
RegStatus = RegEnumKeyEx(hKey, ulIndex, szProfile, &ulSize,
|
||
NULL, NULL, NULL, NULL);
|
||
|
||
if (RegStatus == ERROR_SUCCESS) {
|
||
//
|
||
// pszParentKey contains replacement symbol for the
|
||
// profile id
|
||
//
|
||
wsprintf(pszRegStr, pszParentKey, szProfile);
|
||
|
||
Status = DeletePrivateKey(HKEY_CURRENT_USER,
|
||
pszRegStr,
|
||
pszChildKey);
|
||
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
else {
|
||
//
|
||
// not for all profiles, so just delete the specified key
|
||
//
|
||
Status = DeletePrivateKey(HKEY_CURRENT_USER,
|
||
pszParentKey,
|
||
pszChildKey);
|
||
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//------------------------------------------------------------------
|
||
// For the remaining cases (no user keys), do the work on the
|
||
// server side, sense that side has the code to make the key
|
||
// volatile if necessary instead of deleting. Also, access to
|
||
// some of these registry keys requires system privilege.
|
||
//------------------------------------------------------------------
|
||
|
||
else {
|
||
if (!(ulFlags & CM_REGISTRY_CONFIG)) {
|
||
ulHardwareProfile = 0;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_DeleteRegistryKey(
|
||
hBinding, // rpc binding handle
|
||
pDeviceID, // device id
|
||
pszParentKey, // parent of key to delete
|
||
pszChildKey, // key to delete
|
||
ulHardwareProfile); // flags, not used
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_DeleteRegistryKey caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
}
|
||
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
|
||
//
|
||
// Reference the following variables so the compiler will respect
|
||
// statement ordering w.r.t. their assignment.
|
||
//
|
||
pszRegStr = pszRegStr;
|
||
pszChildKey = pszChildKey;
|
||
pszParentKey = pszParentKey;
|
||
}
|
||
|
||
if (hKey != NULL) {
|
||
RegCloseKey(hKey);
|
||
}
|
||
|
||
if (pszRegStr) {
|
||
pSetupFree(pszRegStr);
|
||
}
|
||
|
||
if (pszChildKey) {
|
||
pSetupFree(pszChildKey);
|
||
}
|
||
|
||
if (pszParentKey) {
|
||
pSetupFree(pszParentKey);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Delete_DevNode_Key_Ex
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Open_Class_Key_ExW(
|
||
IN LPGUID ClassGuid OPTIONAL,
|
||
IN LPCWSTR pszClassName OPTIONAL,
|
||
IN REGSAM samDesired,
|
||
IN REGDISPOSITION Disposition,
|
||
OUT PHKEY phkClass,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens the class registry key, and optionally, a specific
|
||
class's subkey.
|
||
|
||
Parameters:
|
||
|
||
ClassGuid Optionally, supplies the address of a class GUID representing
|
||
the class subkey to be opened.
|
||
|
||
pszClassName Specifies the string form of the class name for the class
|
||
represented by ClassGuid. This parameter is only valid if
|
||
the CM_OPEN_CLASS_KEY_INSTALLER flag is set in the ulFlags
|
||
parameter. If specified, this string will replace any existing
|
||
class name associated with this setup class GUID.
|
||
|
||
This parameter must be set to NULL if the
|
||
CM_OPEN_CLASS_KEY_INTERFACE bit is set in the ulFlags parameter.
|
||
|
||
samDesired Specifies an access mask that describes the desired security
|
||
access for the new key. This parameter can be a combination
|
||
of the values used in calls to RegOpenKeyEx.
|
||
|
||
Disposition Specifies how the registry key is to be opened. May be one
|
||
of the following values:
|
||
RegDisposition_OpenAlways - Open the key if it exists,
|
||
otherwise, create the key.
|
||
RegDisposition_OpenExisting - Open the key f it exists,
|
||
otherwise, fail with CR_NO_SUCH_REGISTRY_KEY.
|
||
|
||
phkClass Supplies the address of the variable that receives an opened
|
||
handle to the specified key. When access to this key is
|
||
completed, it must be closed via RegCloseKey.
|
||
|
||
ulFlags May be one of the following values:
|
||
|
||
CM_OPEN_CLASS_KEY_INSTALLER - open/create a setup class key for
|
||
the specified GUID under
|
||
HKLM\System\CurrentControlSet\Control\Class.
|
||
|
||
CM_OPEN_CLASS_KEY_INTERFACE - open/create a device interface
|
||
class key for the specified GUID under
|
||
HKLM\System\CurrentControlSet\Control\DeviceClasses.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER, or
|
||
CR_REGISTRY_ERROR
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
LONG RegStatus = ERROR_SUCCESS;
|
||
HKEY hRootKey = NULL, hRemoteKey = NULL;
|
||
PWSTR pszMachineName = NULL, pszRegStr = NULL;
|
||
PVOID hStringTable = NULL;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(phkClass)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
*phkClass = NULL;
|
||
|
||
if (INVALID_FLAGS(Disposition, RegDisposition_Bits)) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, CM_OPEN_CLASS_KEY_BITS)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// If ulFlags == CM_OPEN_CLASS_KEY_INTERFACE then pszClassName had
|
||
// better be NULL.
|
||
//
|
||
if((ulFlags == CM_OPEN_CLASS_KEY_INTERFACE) && pszClassName) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// get reg key for HKEY_LOCAL_MACHINE
|
||
//
|
||
if (hMachine == NULL) {
|
||
//
|
||
// local call
|
||
//
|
||
hRootKey = HKEY_LOCAL_MACHINE;
|
||
}
|
||
else {
|
||
//
|
||
// setup string table handle and retreive machine name
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, &hStringTable, NULL)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
pszMachineName = pSetupMalloc((MAX_PATH + 3)*sizeof(WCHAR));
|
||
if (pszMachineName == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
PnPRetrieveMachineName(hMachine, pszMachineName);
|
||
|
||
//
|
||
// connect to HKEY_LOCAL_MACHINE on remote machine
|
||
//
|
||
RegStatus = RegConnectRegistry(pszMachineName, HKEY_LOCAL_MACHINE,
|
||
&hRemoteKey);
|
||
|
||
pSetupFree(pszMachineName);
|
||
pszMachineName = NULL;
|
||
|
||
if (RegStatus != ERROR_SUCCESS) {
|
||
Status = CR_REGISTRY_ERROR;
|
||
goto Clean0;
|
||
}
|
||
|
||
hRootKey = hRemoteKey;
|
||
}
|
||
|
||
//
|
||
// allocate some buffer space to work with
|
||
//
|
||
pszRegStr = pSetupMalloc(MAX_PATH*sizeof(WCHAR));
|
||
if (pszRegStr == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Form the registry path
|
||
//
|
||
if (ulFlags == CM_OPEN_CLASS_KEY_INTERFACE) {
|
||
lstrcpy(pszRegStr, pszRegPathDeviceClass);
|
||
} else {
|
||
lstrcpy(pszRegStr, pszRegPathClass);
|
||
}
|
||
|
||
if (ClassGuid != NULL) { // optional class guid was specified
|
||
|
||
WCHAR szStringGuid[MAX_GUID_STRING_LEN];
|
||
|
||
if (pSetupStringFromGuid(ClassGuid, szStringGuid,MAX_GUID_STRING_LEN) == NO_ERROR) {
|
||
lstrcat(pszRegStr, TEXT("\\"));
|
||
lstrcat(pszRegStr, szStringGuid);
|
||
}
|
||
}
|
||
|
||
//
|
||
// attempt to open/create that key
|
||
//
|
||
if (Disposition == RegDisposition_OpenAlways) {
|
||
|
||
ULONG ulDisposition;
|
||
|
||
RegStatus = RegCreateKeyEx(hRootKey, pszRegStr, 0, NULL,
|
||
REG_OPTION_NON_VOLATILE, samDesired,
|
||
NULL, phkClass, &ulDisposition);
|
||
|
||
} else {
|
||
RegStatus = RegOpenKeyEx(hRootKey, pszRegStr, 0, samDesired,
|
||
phkClass);
|
||
}
|
||
|
||
if((pszClassName != NULL) && (RegStatus == ERROR_SUCCESS)) {
|
||
RegSetValueEx(*phkClass, pszRegValueClass, 0, REG_SZ,
|
||
(LPBYTE)pszClassName,
|
||
(lstrlen(pszClassName) + 1) * sizeof(WCHAR));
|
||
}
|
||
|
||
if (RegStatus != ERROR_SUCCESS) {
|
||
*phkClass = NULL;
|
||
Status = CR_NO_SUCH_REGISTRY_KEY;
|
||
goto Clean0;
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
|
||
//
|
||
// Reference the following variables so the compiler will respect
|
||
// statement ordering w.r.t. their assignment.
|
||
//
|
||
pszMachineName = pszMachineName;
|
||
pszRegStr = pszRegStr;
|
||
}
|
||
|
||
if (pszMachineName != NULL) {
|
||
pSetupFree(pszMachineName);
|
||
}
|
||
|
||
if (pszRegStr != NULL) {
|
||
pSetupFree(pszRegStr);
|
||
}
|
||
|
||
if (hRemoteKey != NULL) {
|
||
RegCloseKey(hRemoteKey);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Open_Class_Key_ExW
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Enumerate_Classes_Ex(
|
||
IN ULONG ulClassIndex,
|
||
OUT LPGUID ClassGuid,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine enumerates the installed classes in the system. It
|
||
retrieves the GUID string for a single class each time it is called.
|
||
To enumerate installed classes, an application should initially call the
|
||
CM_Enumerate_Classes function with the ulClassIndex parameter set to
|
||
zero. The application should then increment the ulClassIndex parameter
|
||
and call CM_Enumerate_Classes until there are no more classes (until the
|
||
function returns CR_NO_SUCH_VALUE).
|
||
|
||
It is possible to receive a CR_INVALID_DATA error while enumerating
|
||
installed classes. This may happen if the registry key represented by
|
||
the specified index is determined to be an invalid class key. Such keys
|
||
should be ignored during enumeration.
|
||
|
||
Parameters:
|
||
|
||
ulClassIndex Supplies the index of the class to retrieve the class
|
||
GUID string for.
|
||
|
||
ClassGuid Supplies the address of a variable that receives the GUID
|
||
for the class whose index is specified by ulClassIndex.
|
||
|
||
ulFlags Must be zero.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_NO_SUCH_VALUE,
|
||
CR_REGISTRY_ERROR,
|
||
CR_REMOTE_COMM_FAILURE,
|
||
CR_MACHINE_UNAVAILABLE,
|
||
CR_FAILURE.
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR szClassGuid[MAX_GUID_STRING_LEN];
|
||
ULONG ulLength = MAX_GUID_STRING_LEN;
|
||
handle_t hBinding = NULL;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(ClassGuid)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// initialize guid struct
|
||
//
|
||
ZeroMemory(ClassGuid, sizeof(GUID));
|
||
|
||
//
|
||
// setup rpc binding handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_EnumerateSubKeys(
|
||
hBinding, // rpc binding handle
|
||
PNP_CLASS_SUBKEYS, // subkeys of class branch
|
||
ulClassIndex, // index of class key to enumerate
|
||
szClassGuid, // will contain class name
|
||
ulLength, // length of Buffer in chars,
|
||
&ulLength, // size copied (or size required)
|
||
ulFlags); // currently unused
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_EnumerateSubKeys caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (Status == CR_SUCCESS) {
|
||
if (pSetupGuidFromString(szClassGuid, ClassGuid) != NO_ERROR) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Enumerate_Classes_Ex
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_Name_ExW(
|
||
IN LPGUID ClassGuid,
|
||
OUT PTCHAR Buffer,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves the class name associated with the specified
|
||
class GUID string.
|
||
|
||
Parameters:
|
||
|
||
ClassGuid Supplies a pointer to the class GUID whose name
|
||
is to be retrieved.
|
||
|
||
Buffer Supplies the address of the character buffer that receives
|
||
the class name corresponding to the specified GUID.
|
||
|
||
pulLength Supplies the address of the variable that contains the
|
||
length, in characters, of the Buffer. Upon return, this
|
||
variable will contain the number of characters (including
|
||
terminating NULL) written to Buffer (if the supplied buffer
|
||
isn't large enough, then the routine will fail with
|
||
CR_BUFFER_SMALL, and this value will indicate how large the
|
||
buffer needs to be in order to succeed).
|
||
|
||
ulFlags Must be zero.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_BUFFER_SMALL, or
|
||
CR_REGISTRY_ERROR
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR szStringGuid[MAX_GUID_STRING_LEN];
|
||
handle_t hBinding = NULL;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if ((!ARGUMENT_PRESENT(ClassGuid)) ||
|
||
(!ARGUMENT_PRESENT(Buffer)) ||
|
||
(!ARGUMENT_PRESENT(pulLength))) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// convert from guid to string
|
||
//
|
||
if (pSetupStringFromGuid(ClassGuid, szStringGuid,MAX_GUID_STRING_LEN) != NO_ERROR) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup rpc binding handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_GetClassName(
|
||
hBinding, // rpc binding handle
|
||
szStringGuid,
|
||
Buffer,
|
||
pulLength, // returns count of keys under Class
|
||
ulFlags); // not used
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_GetClassName caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Class_Name_ExW
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_Key_Name_ExW(
|
||
IN LPGUID ClassGuid,
|
||
OUT LPWSTR pszKeyName,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves the class name associated with the specified
|
||
class GUID string.
|
||
|
||
Parameters:
|
||
|
||
ClassGuid Supplies a pointer to the class GUID whose name
|
||
is to be retrieved.
|
||
|
||
pszKeyName Returns the name of the class key in the registry that
|
||
corresponds to the specified ClassGuid. The returned key
|
||
name is relative to
|
||
HKLM\System\CurrentControlSet\Control\Class.
|
||
|
||
pulLength Supplies the address of the variable that contains the
|
||
length, in characters, of the Buffer. Upon return, this
|
||
variable will contain the number of characters (including
|
||
terminating NULL) written to Buffer (if the supplied buffer
|
||
isn't large enough, then the routine will fail with
|
||
CR_BUFFER_SMALL, and this value will indicate how large the
|
||
buffer needs to be in order to succeed).
|
||
|
||
ulFlags Must be zero.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_BUFFER_SMALL, or
|
||
CR_REGISTRY_ERROR
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
handle_t hBinding = NULL;
|
||
|
||
//
|
||
// NOTE: the supplied machine handle is never referenced by this routine,
|
||
// since it is known/assumed that the key name of the class key requested is
|
||
// always just the string representation of the supplied class GUID.
|
||
// there is no corresponding UMPNPMGR server-side routine.
|
||
//
|
||
UNREFERENCED_PARAMETER(hMachine);
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(pulLength)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((!ARGUMENT_PRESENT(ClassGuid)) ||
|
||
(!ARGUMENT_PRESENT(pszKeyName))) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (*pulLength < MAX_GUID_STRING_LEN) {
|
||
*pulLength = MAX_GUID_STRING_LEN;
|
||
Status = CR_BUFFER_SMALL;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// convert from guid to string
|
||
//
|
||
if (pSetupStringFromGuid(ClassGuid, pszKeyName,MAX_GUID_STRING_LEN) == NO_ERROR) {
|
||
*pulLength = MAX_GUID_STRING_LEN;
|
||
} else {
|
||
Status = CR_INVALID_DATA;
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Class_Key_Name_ExW
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Delete_Class_Key_Ex(
|
||
IN LPGUID ClassGuid,
|
||
IN ULONG ulFlags,
|
||
IN HANDLE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes the specified class key from the registry.
|
||
|
||
Parameters:
|
||
|
||
ClassGuid Supplies a pointer to the class GUID to delete.
|
||
|
||
ulFlags Must be one of the following values:
|
||
CM_DELETE_CLASS_ONLY - only deletes the class key if it
|
||
doesn't have any subkeys.
|
||
CM_DELETE_CLASS_SUBKEYS - deletes the class key and any
|
||
subkeys of the class key.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_BUFFER_SMALL, or
|
||
CR_REGISTRY_ERROR
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR szStringGuid[MAX_GUID_STRING_LEN];
|
||
handle_t hBinding = NULL;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(ClassGuid)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, CM_DELETE_CLASS_BITS)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// convert from guid to string
|
||
//
|
||
if (pSetupStringFromGuid(ClassGuid, szStringGuid,MAX_GUID_STRING_LEN) != NO_ERROR) {
|
||
Status = CR_INVALID_DATA;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup rpc binding handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_DeleteClassKey(
|
||
hBinding, // rpc binding handle
|
||
szStringGuid,
|
||
ulFlags);
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_DeleteClassKey caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Delete_Class_Key_Ex
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_Alias_ExW(
|
||
IN LPCWSTR pszDeviceInterface,
|
||
IN LPGUID AliasInterfaceGuid,
|
||
OUT LPWSTR pszAliasDeviceInterface,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
handle_t hBinding = NULL;
|
||
ULONG ulTransferLen = 0;
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if ((!ARGUMENT_PRESENT(pszDeviceInterface)) ||
|
||
(!ARGUMENT_PRESENT(AliasInterfaceGuid)) ||
|
||
(!ARGUMENT_PRESENT(pszAliasDeviceInterface)) ||
|
||
(!ARGUMENT_PRESENT(pulLength))) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// initialize output parameters
|
||
//
|
||
*pszAliasDeviceInterface = '\0';
|
||
ulTransferLen = *pulLength;
|
||
|
||
//
|
||
// setup rpc binding handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_GetInterfaceDeviceAlias(
|
||
hBinding,
|
||
pszDeviceInterface,
|
||
AliasInterfaceGuid,
|
||
pszAliasDeviceInterface,
|
||
pulLength,
|
||
&ulTransferLen,
|
||
ulFlags);
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_GetInterfaceDeviceAlias caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Device_Interface_Alias_ExW
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_List_ExW(
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN DEVINSTID_W pDeviceID OPTIONAL,
|
||
OUT PWCHAR Buffer,
|
||
IN ULONG BufferLen,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns a list of interface devices of the specified interface
|
||
class. You can optionally filter the list of returned interface devices
|
||
based on only those created by a particular devinst. Typically the
|
||
CM_Get_Interface_Device_List routine is called first to determine how big
|
||
a buffer must be allocated to hold the interface device list.
|
||
|
||
Parameters:
|
||
|
||
InterfaceClassGuid This GUID specifies which interface devices to return (only
|
||
those interface devices that belong to this interface class).
|
||
|
||
pDeviceID Optional devinst to filter the list of returned interface
|
||
devices (if non-zero, only the interfaces devices associated
|
||
with this devinst will be returned).
|
||
|
||
Buffer Supplies the buffer that will contain the returned multi_sz
|
||
list of interface devices.
|
||
|
||
BufferLen Specifies how big the Buffer parameter is in characters.
|
||
|
||
ulFlags Must be one of the following values:
|
||
|
||
CM_GET_DEVICE_INTERFACE_LIST_PRESENT -
|
||
only currently 'live' devices
|
||
CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES 0x00000001 -
|
||
all registered devices, live or not
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_BUFFER_SMALL, or
|
||
CR_REGISTRY_ERROR
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
handle_t hBinding = NULL;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if ((!ARGUMENT_PRESENT(Buffer)) || (BufferLen == 0)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, CM_GET_DEVICE_INTERFACE_LIST_BITS)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// initialize output parameters
|
||
//
|
||
*Buffer = '\0';
|
||
|
||
//
|
||
// setup rpc binding handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_GetInterfaceDeviceList(
|
||
hBinding, // RPC Binding Handle
|
||
InterfaceClassGuid, // Device interface GUID
|
||
pDeviceID, // filter string, optional
|
||
Buffer, // will contain device list
|
||
&BufferLen, // in/out size of Buffer
|
||
ulFlags); // filter flag
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_GetInterfaceDeviceList caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Device_Interface_List_ExW
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_List_Size_ExW(
|
||
IN PULONG pulLen,
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN DEVINSTID_W pDeviceID OPTIONAL,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the size (in characters) of buffer required to hold a
|
||
multi_sz list of interface devices of the specified interface class. You
|
||
can optionally filter the list of returned interface devices based on only
|
||
those created by a particular devinst. This routine is typically called before
|
||
a call to the CM_Get_Interface_Device_List routine.
|
||
|
||
Parameters:
|
||
|
||
pulLen On a successful return from this routine, this parameter
|
||
will contain the size (in characters) required to hold the
|
||
multi_sz list of returned interface devices.
|
||
|
||
InterfaceClassGuid This GUID specifies which interface devices to include (only
|
||
those interface devices that belong to this interface class).
|
||
|
||
pDeviceID Optional devinst to filter the list of returned interface
|
||
devices (if non-zero, only the interfaces devices associated
|
||
with this devinst will be returned).
|
||
|
||
ulFlags Must be one of the following values:
|
||
|
||
CM_GET_DEVICE_INTERFACE_LIST_PRESENT -
|
||
only currently 'live' devices
|
||
CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES -
|
||
all registered devices, live or not
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_BUFFER_SMALL, or
|
||
CR_REGISTRY_ERROR
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
handle_t hBinding = NULL;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(pulLen)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, CM_GET_DEVICE_INTERFACE_LIST_BITS)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// initialize output parameters
|
||
//
|
||
*pulLen = 0;
|
||
|
||
//
|
||
// setup rpc binding handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_GetInterfaceDeviceListSize(
|
||
hBinding, // RPC Binding Handle
|
||
pulLen, // Size of buffer required (in chars)
|
||
InterfaceClassGuid, // Device interface GUID
|
||
pDeviceID, // filter string, optional
|
||
ulFlags); // filter flag
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_GetInterfaceDeviceListSize caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Device_Interface_List_Size_Ex
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Register_Device_Interface_ExW(
|
||
IN DEVINST dnDevInst,
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN LPCWSTR pszReference OPTIONAL,
|
||
OUT LPWSTR pszDeviceInterface,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parameters:
|
||
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_BUFFER_SMALL, or
|
||
CR_REGISTRY_ERROR
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR pszDeviceID [MAX_DEVICE_ID_LEN];
|
||
ULONG ulTransferLen,ulLen = MAX_DEVICE_ID_LEN;
|
||
PVOID hStringTable = NULL;
|
||
handle_t hBinding = NULL;
|
||
BOOL Success;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if ((!ARGUMENT_PRESENT(pulLength)) ||
|
||
(!ARGUMENT_PRESENT(pszDeviceInterface)) ||
|
||
(!ARGUMENT_PRESENT(InterfaceClassGuid))) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (dnDevInst == 0) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup rpc binding handle and string table handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// retreive device instance string that corresponds to dnParent
|
||
// (note that this is not optional, even a first level device instance
|
||
// has a parent (the root device instance)
|
||
//
|
||
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,pszDeviceID,&ulLen);
|
||
if (Success == FALSE || INVALID_DEVINST(pszDeviceID)) {
|
||
Status = CR_INVALID_DEVNODE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// ulTransferLen is just used to control how many bytes in the
|
||
// pszInterfaceDevice buffer must be marshalled. We need two
|
||
// length params, since pulLength may contained the required bytes
|
||
// (if the passed in buffer was too small) which may differ from
|
||
// how many types are actually available to marshall (in the buffer
|
||
// too small case, we'll marshall zero so ulTransferLen will be zero
|
||
// but pulLength will describe how many bytes are required to hold
|
||
// the Interface Device string.
|
||
//
|
||
ulTransferLen = *pulLength;
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_RegisterDeviceClassAssociation(
|
||
hBinding, // RPC Binding Handle
|
||
pszDeviceID, // device instance
|
||
InterfaceClassGuid, // Device interface GUID
|
||
pszReference, // reference string, optional
|
||
pszDeviceInterface, // returns interface device name
|
||
pulLength, // pszInterfaceDevice buffer required in chars
|
||
&ulTransferLen, // how many chars to marshall back
|
||
ulFlags); // filter flag
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_RegisterDeviceClassAssociation caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Register_Device_Interface
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Unregister_Device_Interface_ExW(
|
||
IN LPCWSTR pszDeviceInterface,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parameters:
|
||
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_BUFFER_SMALL, or
|
||
CR_REGISTRY_ERROR
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
handle_t hBinding = NULL;
|
||
|
||
|
||
try {
|
||
//
|
||
// validate input parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(pszDeviceInterface)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, 0)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup rpc binding handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_UnregisterDeviceClassAssociation(
|
||
hBinding, // RPC Binding Handle
|
||
pszDeviceInterface, // interface device
|
||
ulFlags); // unused
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_UnregisterDeviceClassAssociation caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Unregister_Device_Interface_ExW
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_DevNode_Custom_Property_ExW(
|
||
IN DEVINST dnDevInst,
|
||
IN PCWSTR pszCustomPropertyName,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves the specified property, either from the devnode's
|
||
device (aka, hardware) key, or from the most-specific per-hardware-id
|
||
storage key for that devnode.
|
||
|
||
Parameters:
|
||
|
||
dnDevInst Supplies the handle of the device instance for which a
|
||
custom property is to be retrieved.
|
||
|
||
pszCustomPropertyName Supplies a string identifying the name of the
|
||
property (registry value entry name) to be retrieved.
|
||
|
||
pulRegDataType Optionally, supplies the address of a variable that
|
||
will receive the registry data type for this property
|
||
(i.e., the REG_* constants).
|
||
|
||
Buffer Supplies the address of the buffer that receives the
|
||
registry data. Can be NULL when simply retrieving data size.
|
||
|
||
pulLength Supplies the address of the variable that contains the size,
|
||
in bytes, of the buffer. The API replaces the initial size
|
||
with the number of bytes of registry data copied to the buffer.
|
||
If the variable is initially zero, the API replaces it with
|
||
the buffer size needed to receive all the registry data. In
|
||
this case, the Buffer parameter is ignored.
|
||
|
||
ulFlags May be a combination of the following values:
|
||
|
||
CM_CUSTOMDEVPROP_MERGE_MULTISZ : merge the devnode-specific
|
||
REG_SZ or REG_MULTI_SZ property (if present) with the
|
||
per-hardware-id REG_SZ or REG_MULTI_SZ property (if
|
||
present). The result will always be a REG_MULTI_SZ.
|
||
|
||
hMachine Machine handle returned from CM_Connect_Machine or NULL.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
|
||
If the function fails, the return value indicates the cause of failure, and
|
||
is typically one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER,
|
||
CR_REGISTRY_ERROR,
|
||
CR_BUFFER_SMALL,
|
||
CR_NO_SUCH_VALUE, or
|
||
CR_FAILURE.
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR pDeviceID[MAX_DEVICE_ID_LEN];
|
||
ULONG ulSizeID, ulTempDataType, ulTransferLen;
|
||
BYTE NullBuffer = 0;
|
||
handle_t hBinding;
|
||
PVOID hStringTable;
|
||
BOOL Success;
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if(!dnDevInst) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(!pszCustomPropertyName) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(!pulLength) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(!Buffer && *pulLength) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(INVALID_FLAGS(ulFlags, CM_CUSTOMDEVPROP_BITS)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// setup rpc binding handle and string table handle
|
||
//
|
||
if(!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// retrieve the string form of the device id string
|
||
//
|
||
ulSizeID = SIZECHARS(pDeviceID);
|
||
Success = pSetupStringTableStringFromIdEx(hStringTable,
|
||
dnDevInst,
|
||
pDeviceID,
|
||
&ulSizeID
|
||
);
|
||
|
||
if(!Success || INVALID_DEVINST(pDeviceID)) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(!Buffer) {
|
||
Buffer = &NullBuffer;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_GetCustomDevProp(
|
||
hBinding, // rpc binding handle
|
||
pDeviceID, // string representation of device instance
|
||
pszCustomPropertyName, // name of the property
|
||
&ulTempDataType, // receives registry data type
|
||
Buffer, // receives registry data
|
||
&ulTransferLen, // input/output buffer size
|
||
pulLength, // bytes copied (or bytes required)
|
||
ulFlags); // flags (e.g., merge-multi-sz?)
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_GetCustomDevProp caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
if(pulRegDataType) {
|
||
//
|
||
// I pass a temp variable to the rpc stubs since they require the
|
||
// output param to always be valid, then if user did pass in a valid
|
||
// pointer to receive the info, do the assignment now
|
||
//
|
||
*pulRegDataType = ulTempDataType;
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_DevNode_Custom_Property_ExW
|
||
|
||
|
||
|
||
//-------------------------------------------------------------------
|
||
// Local Stubs
|
||
//-------------------------------------------------------------------
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_DevNode_Registry_PropertyW(
|
||
IN DEVINST dnDevInst,
|
||
IN ULONG ulProperty,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_DevNode_Registry_Property_ExW(dnDevInst, ulProperty,
|
||
pulRegDataType, Buffer,
|
||
pulLength, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_DevNode_Registry_PropertyA(
|
||
IN DEVINST dnDevInst,
|
||
IN ULONG ulProperty,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_DevNode_Registry_Property_ExA(dnDevInst, ulProperty,
|
||
pulRegDataType, Buffer,
|
||
pulLength, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Set_DevNode_Registry_PropertyW(
|
||
IN DEVINST dnDevInst,
|
||
IN ULONG ulProperty,
|
||
IN PCVOID Buffer OPTIONAL,
|
||
IN OUT ULONG ulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Set_DevNode_Registry_Property_ExW(dnDevInst, ulProperty, Buffer,
|
||
ulLength, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Set_DevNode_Registry_PropertyA(
|
||
IN DEVINST dnDevInst,
|
||
IN ULONG ulProperty,
|
||
IN PCVOID Buffer OPTIONAL,
|
||
IN OUT ULONG ulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Set_DevNode_Registry_Property_ExA(dnDevInst, ulProperty, Buffer,
|
||
ulLength, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Open_DevNode_Key(
|
||
IN DEVINST dnDevNode,
|
||
IN REGSAM samDesired,
|
||
IN ULONG ulHardwareProfile,
|
||
IN REGDISPOSITION Disposition,
|
||
OUT PHKEY phkDevice,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Open_DevNode_Key_Ex(dnDevNode, samDesired, ulHardwareProfile,
|
||
Disposition, phkDevice, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Delete_DevNode_Key(
|
||
IN DEVNODE dnDevNode,
|
||
IN ULONG ulHardwareProfile,
|
||
IN ULONG ulFlags
|
||
)
|
||
|
||
{
|
||
return CM_Delete_DevNode_Key_Ex(dnDevNode, ulHardwareProfile,
|
||
ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Open_Class_KeyW(
|
||
IN LPGUID ClassGuid OPTIONAL,
|
||
IN LPCWSTR pszClassName OPTIONAL,
|
||
IN REGSAM samDesired,
|
||
IN REGDISPOSITION Disposition,
|
||
OUT PHKEY phkClass,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Open_Class_Key_ExW(ClassGuid, pszClassName, samDesired,
|
||
Disposition, phkClass, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Open_Class_KeyA(
|
||
IN LPGUID ClassGuid OPTIONAL,
|
||
IN LPCSTR pszClassName OPTIONAL,
|
||
IN REGSAM samDesired,
|
||
IN REGDISPOSITION Disposition,
|
||
OUT PHKEY phkClass,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Open_Class_Key_ExA(ClassGuid, pszClassName, samDesired,
|
||
Disposition, phkClass, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Enumerate_Classes(
|
||
IN ULONG ulClassIndex,
|
||
OUT LPGUID ClassGuid,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Enumerate_Classes_Ex(ulClassIndex, ClassGuid, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_NameW(
|
||
IN LPGUID ClassGuid,
|
||
OUT PWCHAR Buffer,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Class_Name_ExW(ClassGuid, Buffer, pulLength, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_NameA(
|
||
IN LPGUID ClassGuid,
|
||
OUT PCHAR Buffer,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Class_Name_ExA(ClassGuid, Buffer, pulLength, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_Key_NameA(
|
||
IN LPGUID ClassGuid,
|
||
OUT LPSTR pszKeyName,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Class_Key_Name_ExA(ClassGuid, pszKeyName, pulLength,
|
||
ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_Key_NameW(
|
||
IN LPGUID ClassGuid,
|
||
OUT LPWSTR pszKeyName,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Class_Key_Name_ExW(ClassGuid, pszKeyName, pulLength,
|
||
ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CONFIGRET
|
||
CM_Delete_Class_Key(
|
||
IN LPGUID ClassGuid,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Delete_Class_Key_Ex(ClassGuid, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_AliasA(
|
||
IN LPCSTR pszDeviceInterface,
|
||
IN LPGUID AliasInterfaceGuid,
|
||
OUT LPSTR pszAliasDeviceInterface,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Device_Interface_Alias_ExA(pszDeviceInterface, AliasInterfaceGuid,
|
||
pszAliasDeviceInterface, pulLength,
|
||
ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_AliasW(
|
||
IN LPCWSTR pszDeviceInterface,
|
||
IN LPGUID AliasInterfaceGuid,
|
||
OUT LPWSTR pszAliasDeviceInterface,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Device_Interface_Alias_ExW(pszDeviceInterface, AliasInterfaceGuid,
|
||
pszAliasDeviceInterface, pulLength,
|
||
ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_ListA(
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN DEVINSTID_A pDeviceID OPTIONAL,
|
||
OUT PCHAR Buffer,
|
||
IN ULONG BufferLen,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Device_Interface_List_ExA(InterfaceClassGuid, pDeviceID, Buffer,
|
||
BufferLen, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_ListW(
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN DEVINSTID_W pDeviceID OPTIONAL,
|
||
OUT PWCHAR Buffer,
|
||
IN ULONG BufferLen,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Device_Interface_List_ExW(InterfaceClassGuid, pDeviceID, Buffer,
|
||
BufferLen, ulFlags, NULL);
|
||
}
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_List_SizeA(
|
||
IN PULONG pulLen,
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN DEVINSTID_A pDeviceID OPTIONAL,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Device_Interface_List_Size_ExA(pulLen, InterfaceClassGuid,
|
||
pDeviceID, ulFlags, NULL);
|
||
}
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_List_SizeW(
|
||
IN PULONG pulLen,
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN DEVINSTID_W pDeviceID OPTIONAL,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_Device_Interface_List_Size_ExW(pulLen, InterfaceClassGuid,
|
||
pDeviceID, ulFlags, NULL);
|
||
}
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Register_Device_InterfaceA(
|
||
IN DEVINST dnDevInst,
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN LPCSTR pszReference OPTIONAL,
|
||
OUT LPSTR pszDeviceInterface,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Register_Device_Interface_ExA(dnDevInst, InterfaceClassGuid,
|
||
pszReference, pszDeviceInterface,
|
||
pulLength, ulFlags, NULL);
|
||
}
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Register_Device_InterfaceW(
|
||
IN DEVINST dnDevInst,
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN LPCWSTR pszReference OPTIONAL,
|
||
OUT LPWSTR pszDeviceInterface,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Register_Device_Interface_ExW(dnDevInst, InterfaceClassGuid,
|
||
pszReference, pszDeviceInterface,
|
||
pulLength, ulFlags, NULL);
|
||
}
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Unregister_Device_InterfaceA(
|
||
IN LPCSTR pszDeviceInterface,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Unregister_Device_Interface_ExA(pszDeviceInterface, ulFlags, NULL);
|
||
}
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Unregister_Device_InterfaceW(
|
||
IN LPCWSTR pszDeviceInterface,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Unregister_Device_Interface_ExW(pszDeviceInterface, ulFlags, NULL);
|
||
}
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_DevNode_Custom_PropertyW(
|
||
IN DEVINST dnDevInst,
|
||
IN PCWSTR pszCustomPropertyName,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_DevNode_Custom_Property_ExW(dnDevInst,
|
||
pszCustomPropertyName,
|
||
pulRegDataType,
|
||
Buffer,
|
||
pulLength,
|
||
ulFlags,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_DevNode_Custom_PropertyA(
|
||
IN DEVINST dnDevInst,
|
||
IN PCSTR pszCustomPropertyName,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags
|
||
)
|
||
{
|
||
return CM_Get_DevNode_Custom_Property_ExA(dnDevInst,
|
||
pszCustomPropertyName,
|
||
pulRegDataType,
|
||
Buffer,
|
||
pulLength,
|
||
ulFlags,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
|
||
|
||
//-------------------------------------------------------------------
|
||
// ANSI STUBS
|
||
//-------------------------------------------------------------------
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_DevNode_Registry_Property_ExA(
|
||
IN DEVINST dnDevInst,
|
||
IN ULONG ulProperty,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
ULONG ulDataType, UniLen;
|
||
PWSTR pUniBuffer;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if (!ARGUMENT_PRESENT(pulLength)) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
//
|
||
// examine datatype to see if need to convert return data
|
||
//
|
||
ulDataType = GetPropertyDataType(ulProperty);
|
||
|
||
//
|
||
// for all string type registry properties, we pass a Unicode buffer and
|
||
// convert back to caller's ANSI buffer on return. since the Unicode ->
|
||
// ANSI conversion may involve DBCS chars, we can't make any assumptions
|
||
// about the size of the required ANSI buffer relative to the size of the
|
||
// require Unicode buffer, so we must always get the Unicode string buffer
|
||
// and convert it whether a buffer was actually supplied by the caller or
|
||
// not.
|
||
//
|
||
if (ulDataType == REG_SZ ||
|
||
ulDataType == REG_MULTI_SZ ||
|
||
ulDataType == REG_EXPAND_SZ) {
|
||
|
||
//
|
||
// first, call the Wide version with a zero-length buffer to retrieve
|
||
// the size required for the Unicode property.
|
||
//
|
||
UniLen = 0;
|
||
Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
|
||
ulProperty,
|
||
pulRegDataType,
|
||
NULL,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
if (Status != CR_BUFFER_SMALL) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// allocate the required buffer.
|
||
//
|
||
pUniBuffer = pSetupMalloc(UniLen);
|
||
if (pUniBuffer == NULL) {
|
||
return CR_OUT_OF_MEMORY;
|
||
}
|
||
|
||
//
|
||
// call the Wide version to retrieve the Unicode property.
|
||
//
|
||
Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
|
||
ulProperty,
|
||
pulRegDataType,
|
||
pUniBuffer,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
//
|
||
// We specifically allocated the buffer of the required size, so it
|
||
// should always be large enough.
|
||
//
|
||
ASSERT(Status != CR_BUFFER_SMALL);
|
||
|
||
if (Status == CR_SUCCESS) {
|
||
//
|
||
// do the ANSI conversion or retrieve the ANSI buffer size required.
|
||
// this may be a single-sz or multi-sz string, so we pass in the
|
||
// length, and let PnPUnicodeToMultiByte convert the entire buffer.
|
||
//
|
||
Status = PnPUnicodeToMultiByte(pUniBuffer,
|
||
UniLen,
|
||
Buffer,
|
||
pulLength);
|
||
|
||
}
|
||
|
||
pSetupFree(pUniBuffer);
|
||
|
||
} else {
|
||
//
|
||
// for the non-string registry data types, just pass call on through to
|
||
// the Wide version
|
||
//
|
||
Status = CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
|
||
ulProperty,
|
||
pulRegDataType,
|
||
Buffer,
|
||
pulLength,
|
||
ulFlags,
|
||
hMachine);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_DevNode_Registry_Property_ExA
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Set_DevNode_Registry_Property_ExA(
|
||
IN DEVINST dnDevInst,
|
||
IN ULONG ulProperty,
|
||
IN PCVOID Buffer OPTIONAL,
|
||
IN ULONG ulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
ULONG ulDataType = 0, UniSize = 0, UniBufferSize = 0;
|
||
PWSTR pUniBuffer = NULL, pUniString = NULL, pUniNext = NULL;
|
||
PSTR pAnsiString = NULL;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if ((!ARGUMENT_PRESENT(Buffer)) && (ulLength != 0)) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
if (!ARGUMENT_PRESENT(Buffer)) {
|
||
//
|
||
// No need to convert the parameter
|
||
//
|
||
return CM_Set_DevNode_Registry_Property_ExW(dnDevInst,
|
||
ulProperty,
|
||
Buffer,
|
||
ulLength,
|
||
ulFlags,
|
||
hMachine);
|
||
}
|
||
|
||
//
|
||
// examine datatype to see if need to convert input buffer
|
||
//
|
||
ulDataType = GetPropertyDataType(ulProperty);
|
||
|
||
if (ulDataType == REG_SZ || ulDataType == REG_EXPAND_SZ) {
|
||
//
|
||
// convert buffer string data to unicode and pass to wide version
|
||
//
|
||
if (pSetupCaptureAndConvertAnsiArg(Buffer, &pUniBuffer) == NO_ERROR) {
|
||
|
||
UniSize = (lstrlen(pUniBuffer)+1) * sizeof(WCHAR);
|
||
|
||
Status = CM_Set_DevNode_Registry_Property_ExW(dnDevInst,
|
||
ulProperty,
|
||
pUniBuffer,
|
||
UniSize,
|
||
ulFlags,
|
||
hMachine);
|
||
pSetupFree(pUniBuffer);
|
||
} else {
|
||
Status = CR_INVALID_DATA;
|
||
}
|
||
|
||
} else if (ulDataType == REG_MULTI_SZ) {
|
||
//
|
||
// must convert the multi_sz list to unicode first
|
||
//
|
||
UniBufferSize = ulLength * sizeof(WCHAR);
|
||
pUniBuffer = pSetupMalloc(UniBufferSize);
|
||
if (pUniBuffer == NULL) {
|
||
return CR_OUT_OF_MEMORY;
|
||
}
|
||
|
||
for (pAnsiString = (PSTR)Buffer, pUniNext = pUniBuffer;
|
||
*pAnsiString;
|
||
pAnsiString += lstrlenA(pAnsiString) + 1) {
|
||
|
||
if (pSetupCaptureAndConvertAnsiArg(pAnsiString, &pUniString) == NO_ERROR) {
|
||
|
||
UniSize += (lstrlen(pUniString)+1) * sizeof(WCHAR);
|
||
|
||
if (UniSize >= UniBufferSize) {
|
||
pSetupFree(pUniString);
|
||
pSetupFree(pUniBuffer);
|
||
return CR_INVALID_DATA;
|
||
}
|
||
|
||
lstrcpy(pUniNext, pUniString);
|
||
pUniNext += lstrlen(pUniNext) + 1;
|
||
|
||
pSetupFree(pUniString);
|
||
} else {
|
||
pSetupFree(pUniBuffer);
|
||
return CR_INVALID_DATA;
|
||
}
|
||
}
|
||
*(pUniNext++) = L'\0'; // add second null term
|
||
|
||
Status = CM_Set_DevNode_Registry_Property_ExW(dnDevInst,
|
||
ulProperty,
|
||
pUniBuffer,
|
||
UniBufferSize,
|
||
ulFlags,
|
||
hMachine);
|
||
pSetupFree(pUniBuffer);
|
||
|
||
} else {
|
||
|
||
Status = CM_Set_DevNode_Registry_Property_ExW(dnDevInst,
|
||
ulProperty,
|
||
Buffer,
|
||
ulLength,
|
||
ulFlags,
|
||
hMachine);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Set_DevNode_Registry_Property_ExA
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_Registry_PropertyA(
|
||
IN LPGUID pClassGuid,
|
||
IN ULONG ulProperty,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
ULONG ulDataType, UniLen;
|
||
PWSTR pUniBuffer;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if (!ARGUMENT_PRESENT(pulLength)) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
//
|
||
// examine datatype to see if need to convert return data
|
||
//
|
||
ulDataType = GetPropertyDataType(ulProperty);
|
||
|
||
//
|
||
// for all string type registry properties, we pass a Unicode buffer and
|
||
// convert back to caller's ANSI buffer on return. since the Unicode ->
|
||
// ANSI conversion may involve DBCS chars, we can't make any assumptions
|
||
// about the size of the required ANSI buffer relative to the size of the
|
||
// require Unicode buffer, so we must always get the Unicode string buffer
|
||
// and convert it whether a buffer was actually supplied by the caller or
|
||
// not.
|
||
//
|
||
if (ulDataType == REG_SZ ||
|
||
ulDataType == REG_MULTI_SZ ||
|
||
ulDataType == REG_EXPAND_SZ) {
|
||
|
||
//
|
||
// first, call the Wide version with a zero-length buffer to retrieve
|
||
// the size required for the Unicode property.
|
||
//
|
||
UniLen = 0;
|
||
Status = CM_Get_Class_Registry_PropertyW(pClassGuid,
|
||
ulProperty,
|
||
pulRegDataType,
|
||
NULL,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
if (Status != CR_BUFFER_SMALL) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// allocate the required buffer.
|
||
//
|
||
pUniBuffer = pSetupMalloc(UniLen);
|
||
if (pUniBuffer == NULL) {
|
||
return CR_OUT_OF_MEMORY;
|
||
}
|
||
|
||
//
|
||
// call the Wide version to retrieve the Unicode property.
|
||
//
|
||
Status = CM_Get_Class_Registry_PropertyW(pClassGuid,
|
||
ulProperty,
|
||
pulRegDataType,
|
||
pUniBuffer,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
//
|
||
// We specifically allocated the buffer of the required size, so it
|
||
// should always be large enough.
|
||
//
|
||
ASSERT(Status != CR_BUFFER_SMALL);
|
||
|
||
if (Status == CR_SUCCESS) {
|
||
//
|
||
// do the ANSI conversion or retrieve the ANSI buffer size required.
|
||
// this may be a single-sz or multi-sz string, so we pass in the
|
||
// length, and let PnPUnicodeToMultiByte convert the entire buffer.
|
||
//
|
||
Status = PnPUnicodeToMultiByte(pUniBuffer,
|
||
UniLen,
|
||
Buffer,
|
||
pulLength);
|
||
}
|
||
|
||
pSetupFree(pUniBuffer);
|
||
|
||
} else {
|
||
//
|
||
// for the non-string registry data types, just pass call
|
||
// on through to the Wide version
|
||
//
|
||
Status = CM_Get_Class_Registry_PropertyW(pClassGuid,
|
||
ulProperty,
|
||
pulRegDataType,
|
||
Buffer,
|
||
pulLength,
|
||
ulFlags,
|
||
hMachine);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Class_Registry_PropertyA
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Set_Class_Registry_PropertyA(
|
||
IN LPGUID pClassGuid,
|
||
IN ULONG ulProperty,
|
||
IN PCVOID Buffer OPTIONAL,
|
||
IN ULONG ulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
ULONG ulDataType = 0, UniSize = 0, UniBufferSize = 0;
|
||
PWSTR pUniBuffer = NULL, pUniString = NULL, pUniNext = NULL;
|
||
PSTR pAnsiString = NULL;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if ((!ARGUMENT_PRESENT(Buffer)) && (ulLength != 0)) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
if (!ARGUMENT_PRESENT(Buffer)) {
|
||
//
|
||
// No need to convert the parameter
|
||
//
|
||
return CM_Set_Class_Registry_PropertyW(pClassGuid,
|
||
ulProperty,
|
||
Buffer,
|
||
ulLength,
|
||
ulFlags,
|
||
hMachine);
|
||
}
|
||
|
||
//
|
||
// examine datatype to see if need to convert input buffer
|
||
//
|
||
ulDataType = GetPropertyDataType(ulProperty);
|
||
|
||
if (ulDataType == REG_SZ || ulDataType == REG_EXPAND_SZ) {
|
||
//
|
||
// convert buffer string data to unicode and pass to wide version
|
||
//
|
||
if (pSetupCaptureAndConvertAnsiArg(Buffer, &pUniBuffer) == NO_ERROR) {
|
||
|
||
UniSize = (lstrlen(pUniBuffer)+1) * sizeof(WCHAR);
|
||
|
||
Status = CM_Set_Class_Registry_PropertyW(pClassGuid,
|
||
ulProperty,
|
||
pUniBuffer,
|
||
UniSize,
|
||
ulFlags,
|
||
hMachine);
|
||
pSetupFree(pUniBuffer);
|
||
} else {
|
||
Status = CR_INVALID_DATA;
|
||
}
|
||
|
||
} else if (ulDataType == REG_MULTI_SZ) {
|
||
//
|
||
// must convert the multi_sz list to unicode first
|
||
//
|
||
UniBufferSize = ulLength * sizeof(WCHAR);
|
||
pUniBuffer = pSetupMalloc(UniBufferSize);
|
||
if (pUniBuffer == NULL) {
|
||
return CR_OUT_OF_MEMORY;
|
||
}
|
||
|
||
for (pAnsiString = (PSTR)Buffer, pUniNext = pUniBuffer;
|
||
*pAnsiString;
|
||
pAnsiString += lstrlenA(pAnsiString) + 1) {
|
||
|
||
if (pSetupCaptureAndConvertAnsiArg(pAnsiString, &pUniString) == NO_ERROR) {
|
||
|
||
UniSize += (lstrlen(pUniString)+1) * sizeof(WCHAR);
|
||
|
||
if (UniSize >= UniBufferSize) {
|
||
pSetupFree(pUniString);
|
||
pSetupFree(pUniBuffer);
|
||
return CR_INVALID_DATA;
|
||
}
|
||
|
||
lstrcpy(pUniNext, pUniString);
|
||
pUniNext += lstrlen(pUniNext) + 1;
|
||
|
||
pSetupFree(pUniString);
|
||
} else {
|
||
pSetupFree(pUniBuffer);
|
||
return CR_INVALID_DATA;
|
||
}
|
||
}
|
||
*(pUniNext++) = L'\0'; // add second null term
|
||
|
||
Status = CM_Set_Class_Registry_PropertyW(pClassGuid,
|
||
ulProperty,
|
||
pUniBuffer,
|
||
UniBufferSize,
|
||
ulFlags,
|
||
hMachine);
|
||
pSetupFree(pUniBuffer);
|
||
|
||
} else {
|
||
|
||
Status = CM_Set_Class_Registry_PropertyW(pClassGuid,
|
||
ulProperty,
|
||
Buffer,
|
||
ulLength,
|
||
ulFlags,
|
||
hMachine);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Set_Class_Registry_Property_ExA
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Open_Class_Key_ExA(
|
||
IN LPGUID ClassGuid OPTIONAL,
|
||
IN LPCSTR pszClassName OPTIONAL,
|
||
IN REGSAM samDesired,
|
||
IN REGDISPOSITION Disposition,
|
||
OUT PHKEY phkClass,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PWSTR pUniClassName = NULL;
|
||
|
||
if (ARGUMENT_PRESENT(pszClassName)) {
|
||
if (pSetupCaptureAndConvertAnsiArg(pszClassName, &pUniClassName) != NO_ERROR) {
|
||
return CR_INVALID_DATA;
|
||
}
|
||
}
|
||
|
||
Status = CM_Open_Class_Key_ExW(ClassGuid,
|
||
pUniClassName,
|
||
samDesired,
|
||
Disposition,
|
||
phkClass,
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
if (pUniClassName) {
|
||
pSetupFree(pUniClassName);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Open_Class_Key_ExA
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_Name_ExA(
|
||
IN LPGUID ClassGuid,
|
||
OUT PCHAR Buffer,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR UniBuffer[MAX_CLASS_NAME_LEN];
|
||
ULONG UniLen = MAX_CLASS_NAME_LEN;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if ((!ARGUMENT_PRESENT(Buffer)) ||
|
||
(!ARGUMENT_PRESENT(pulLength))) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
//
|
||
// call the wide version, passing a unicode buffer as a parameter
|
||
//
|
||
Status = CM_Get_Class_Name_ExW(ClassGuid,
|
||
UniBuffer,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
//
|
||
// We should never return a class name longer than MAX_CLASS_NAME_LEN.
|
||
//
|
||
ASSERT(Status != CR_BUFFER_SMALL);
|
||
|
||
//
|
||
// convert the unicode buffer to an ansi string and copy to the
|
||
// caller's buffer
|
||
//
|
||
if (Status == CR_SUCCESS) {
|
||
|
||
Status = PnPUnicodeToMultiByte(UniBuffer,
|
||
(lstrlenW(UniBuffer)+1)*sizeof(WCHAR),
|
||
Buffer,
|
||
pulLength);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Class_Name_ExA
|
||
|
||
|
||
|
||
CONFIGRET
|
||
CM_Get_Class_Key_Name_ExA(
|
||
IN LPGUID ClassGuid,
|
||
OUT LPSTR pszKeyName,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR UniBuffer[MAX_GUID_STRING_LEN];
|
||
ULONG UniLen = MAX_GUID_STRING_LEN;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if ((!ARGUMENT_PRESENT(pszKeyName)) ||
|
||
(!ARGUMENT_PRESENT(pulLength))) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
//
|
||
// call the wide version, passing a unicode buffer as a parameter
|
||
//
|
||
Status = CM_Get_Class_Key_Name_ExW(ClassGuid,
|
||
UniBuffer,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
//
|
||
// We should never return a class key name longer than MAX_GUID_STRING_LEN.
|
||
//
|
||
ASSERT(Status != CR_BUFFER_SMALL);
|
||
|
||
//
|
||
// convert the unicode buffer to an ansi string and copy to the
|
||
// caller's buffer
|
||
//
|
||
if (Status == CR_SUCCESS) {
|
||
|
||
Status = PnPUnicodeToMultiByte(UniBuffer,
|
||
(lstrlenW(UniBuffer)+1)*sizeof(WCHAR),
|
||
pszKeyName,
|
||
pulLength);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Class_Key_Name_ExA
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_Alias_ExA(
|
||
IN LPCSTR pszDeviceInterface,
|
||
IN LPGUID AliasInterfaceGuid,
|
||
OUT LPSTR pszAliasDeviceInterface,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PWSTR pUniDeviceInterface, pUniAliasDeviceInterface;
|
||
ULONG UniLen;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if ((!ARGUMENT_PRESENT(pszDeviceInterface)) ||
|
||
(!ARGUMENT_PRESENT(pszAliasDeviceInterface)) ||
|
||
(!ARGUMENT_PRESENT(pulLength))) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
//
|
||
// convert buffer string data to unicode to pass to wide version
|
||
//
|
||
if (pSetupCaptureAndConvertAnsiArg(pszDeviceInterface, &pUniDeviceInterface) != NO_ERROR) {
|
||
return CR_INVALID_DATA;
|
||
}
|
||
|
||
//
|
||
// first, call the Wide version with a zero-length buffer to retrieve
|
||
// the size required for the Unicode property.
|
||
//
|
||
UniLen = 0;
|
||
Status = CM_Get_Device_Interface_Alias_ExW(pUniDeviceInterface,
|
||
AliasInterfaceGuid,
|
||
NULL,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
if (Status != CR_BUFFER_SMALL) {
|
||
return Status;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// allocate the required buffer.
|
||
//
|
||
pUniAliasDeviceInterface = pSetupMalloc(UniLen);
|
||
if (pUniAliasDeviceInterface == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// call the Wide version to retrieve the Unicode property.
|
||
//
|
||
Status = CM_Get_Device_Interface_Alias_ExW(pUniDeviceInterface,
|
||
AliasInterfaceGuid,
|
||
pUniAliasDeviceInterface,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
//
|
||
// We specifically allocated the buffer of the required size, so it should
|
||
// always be large enough.
|
||
//
|
||
ASSERT(Status != CR_BUFFER_SMALL);
|
||
|
||
if (Status == CR_SUCCESS) {
|
||
//
|
||
// do the ANSI conversion or retrieve the ANSI buffer size required.
|
||
//
|
||
Status = PnPUnicodeToMultiByte(pUniAliasDeviceInterface,
|
||
(lstrlenW(pUniAliasDeviceInterface)+1)*sizeof(WCHAR),
|
||
pszAliasDeviceInterface,
|
||
pulLength);
|
||
|
||
}
|
||
|
||
pSetupFree(pUniAliasDeviceInterface);
|
||
|
||
Clean0:
|
||
|
||
pSetupFree(pUniDeviceInterface);
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Device_Interface_Alias_ExA
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_List_ExA(
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN DEVINSTID_A pDeviceID OPTIONAL,
|
||
OUT PCHAR Buffer,
|
||
IN ULONG BufferLen,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PWSTR pUniBuffer, pUniDeviceID = NULL;
|
||
ULONG ulAnsiBufferLen;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if ((!ARGUMENT_PRESENT(Buffer)) || (BufferLen == 0)) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(pDeviceID)) {
|
||
//
|
||
// if a filter string was passed in, convert to UNICODE before
|
||
// passing on to the wide version
|
||
//
|
||
if (pSetupCaptureAndConvertAnsiArg(pDeviceID, &pUniDeviceID) != NO_ERROR) {
|
||
return CR_INVALID_DEVICE_ID;
|
||
}
|
||
ASSERT(pUniDeviceID != NULL);
|
||
} else {
|
||
ASSERT(pUniDeviceID == NULL);
|
||
}
|
||
|
||
//
|
||
// prepare a larger buffer to hold the unicode formatted
|
||
// multi_sz data returned by CM_Get_Device_Interface_List_ExW.
|
||
//
|
||
pUniBuffer = pSetupMalloc(BufferLen * sizeof(WCHAR));
|
||
if (pUniBuffer == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
*pUniBuffer = L'\0';
|
||
|
||
//
|
||
// call the wide version
|
||
//
|
||
Status = CM_Get_Device_Interface_List_ExW(InterfaceClassGuid,
|
||
pUniDeviceID,
|
||
pUniBuffer,
|
||
BufferLen, // size in chars
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
//
|
||
// convert the unicode buffer to an ansi string and copy to the
|
||
// caller's buffer
|
||
//
|
||
if (Status == CR_SUCCESS) {
|
||
|
||
ulAnsiBufferLen = BufferLen;
|
||
Status = PnPUnicodeToMultiByte(pUniBuffer,
|
||
BufferLen*sizeof(WCHAR),
|
||
Buffer,
|
||
&ulAnsiBufferLen);
|
||
}
|
||
|
||
pSetupFree(pUniBuffer);
|
||
|
||
Clean0:
|
||
|
||
if (pUniDeviceID) {
|
||
pSetupFree(pUniDeviceID);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Device_Interface_List_ExA
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Device_Interface_List_Size_ExA(
|
||
IN PULONG pulLen,
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN DEVINSTID_A pDeviceID OPTIONAL,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS, tmpStatus;
|
||
PWSTR pUniDeviceID = NULL, pUniDeviceInterfaceList;
|
||
ULONG UniLen;
|
||
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if (!ARGUMENT_PRESENT(pulLen)) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(pDeviceID)) {
|
||
//
|
||
// if a device ID string was passed in, convert to UNICODE before
|
||
// passing on to the wide version
|
||
//
|
||
if (pSetupCaptureAndConvertAnsiArg(pDeviceID, &pUniDeviceID) != NO_ERROR) {
|
||
return CR_INVALID_DEVICE_ID;
|
||
}
|
||
ASSERT(pUniDeviceID != NULL);
|
||
} else {
|
||
ASSERT(pUniDeviceID == NULL);
|
||
}
|
||
|
||
//
|
||
// first, call the Wide version to retrieve the size required for the
|
||
// Unicode device interface list.
|
||
//
|
||
UniLen = 0;
|
||
Status = CM_Get_Device_Interface_List_Size_ExW(&UniLen,
|
||
InterfaceClassGuid,
|
||
pUniDeviceID,
|
||
ulFlags,
|
||
hMachine);
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// allocate the required buffer.
|
||
//
|
||
pUniDeviceInterfaceList = pSetupMalloc(UniLen*sizeof(WCHAR));
|
||
if (pUniDeviceInterfaceList == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// call the Wide version to retrieve the Unicode device interface list.
|
||
//
|
||
Status = CM_Get_Device_Interface_List_ExW(InterfaceClassGuid,
|
||
pUniDeviceID,
|
||
pUniDeviceInterfaceList,
|
||
UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
//
|
||
// We specifically allocated the buffer of the required size, so it should
|
||
// always be large enough.
|
||
//
|
||
ASSERT(Status != CR_BUFFER_SMALL);
|
||
|
||
if (Status == CR_SUCCESS) {
|
||
//
|
||
// retrieve the size, in bytes, of the ANSI buffer size required to
|
||
// convert this list. since this is a multi-sz string, we pass in the
|
||
// length and let PnPUnicodeToMultiByte convert the entire buffer.
|
||
//
|
||
tmpStatus = PnPUnicodeToMultiByte(pUniDeviceInterfaceList,
|
||
UniLen*sizeof(WCHAR),
|
||
NULL,
|
||
pulLen);
|
||
|
||
ASSERT(tmpStatus == CR_BUFFER_SMALL);
|
||
}
|
||
|
||
pSetupFree(pUniDeviceInterfaceList);
|
||
|
||
Clean0:
|
||
|
||
if (pUniDeviceID) {
|
||
pSetupFree(pUniDeviceID);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Device_Interface_List_Size_ExA
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Register_Device_Interface_ExA(
|
||
IN DEVINST dnDevInst,
|
||
IN LPGUID InterfaceClassGuid,
|
||
IN LPCSTR pszReference OPTIONAL,
|
||
OUT LPSTR pszDeviceInterface,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PWSTR pUniReference = NULL, pUniDeviceInterface = NULL;
|
||
ULONG UniLen;
|
||
|
||
try {
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if ((!ARGUMENT_PRESENT(pulLength)) ||
|
||
(!ARGUMENT_PRESENT(pszDeviceInterface))) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
//
|
||
// if a device reference string was passed in, convert to Unicode before
|
||
// passing on to the wide version
|
||
//
|
||
if (ARGUMENT_PRESENT(pszReference)) {
|
||
if (pSetupCaptureAndConvertAnsiArg(pszReference, &pUniReference) != NO_ERROR) {
|
||
return CR_INVALID_DATA;
|
||
}
|
||
}
|
||
|
||
//
|
||
// pass a Unicode buffer instead and convert back to caller's ANSI buffer on
|
||
// return
|
||
//
|
||
UniLen = *pulLength;
|
||
pUniDeviceInterface = pSetupMalloc(UniLen*sizeof(WCHAR));
|
||
if (pUniDeviceInterface == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
Status = CM_Register_Device_Interface_ExW(dnDevInst,
|
||
InterfaceClassGuid,
|
||
pUniReference,
|
||
pUniDeviceInterface,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine);
|
||
|
||
if (Status == CR_SUCCESS) {
|
||
//
|
||
// if the call succeeded, convert the Unicode string to ANSI
|
||
//
|
||
Status = PnPUnicodeToMultiByte(pUniDeviceInterface,
|
||
(lstrlenW(pUniDeviceInterface)+1)*sizeof(WCHAR),
|
||
pszDeviceInterface,
|
||
pulLength);
|
||
|
||
} else if (Status == CR_BUFFER_SMALL) {
|
||
//
|
||
// returned size is in chars
|
||
//
|
||
*pulLength = UniLen;
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
if (pUniDeviceInterface) {
|
||
pSetupFree(pUniDeviceInterface);
|
||
}
|
||
|
||
if (pUniReference) {
|
||
pSetupFree(pUniReference);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Register_Device_Interface_ExA
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Unregister_Device_Interface_ExA(
|
||
IN LPCSTR pszDeviceInterface,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PWSTR pUniDeviceInterface = NULL;
|
||
|
||
try {
|
||
//
|
||
// validate essential parameters only
|
||
//
|
||
if (!ARGUMENT_PRESENT(pszDeviceInterface)) {
|
||
return CR_INVALID_POINTER;
|
||
}
|
||
|
||
//
|
||
// convert buffer string data to unicode and pass to wide version
|
||
//
|
||
if (pSetupCaptureAndConvertAnsiArg(pszDeviceInterface, &pUniDeviceInterface) == NO_ERROR) {
|
||
|
||
Status = CM_Unregister_Device_Interface_ExW(pUniDeviceInterface,
|
||
ulFlags,
|
||
hMachine);
|
||
} else {
|
||
Status = CR_INVALID_DATA;
|
||
}
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
if (pUniDeviceInterface) {
|
||
pSetupFree(pUniDeviceInterface);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Unregister_Device_Interface_ExA
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_DevNode_Custom_Property_ExA(
|
||
IN DEVINST dnDevInst,
|
||
IN PCSTR pszCustomPropertyName,
|
||
OUT PULONG pulRegDataType OPTIONAL,
|
||
OUT PVOID Buffer OPTIONAL,
|
||
IN OUT PULONG pulLength,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
{
|
||
DWORD Win32Status;
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PWSTR UnicodeCustomPropName = NULL;
|
||
DWORD UniLen;
|
||
PBYTE pUniBuffer = NULL;
|
||
PSTR pAnsiBuffer = NULL;
|
||
ULONG ulDataType;
|
||
ULONG ulAnsiBufferLen;
|
||
PWSTR pUniString;
|
||
|
||
try {
|
||
//
|
||
// Validate parameters not validated by upcoming call to Unicode API
|
||
// (CM_Get_DevNode_Registry_Property_ExW).
|
||
//
|
||
if(!ARGUMENT_PRESENT(pulLength)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if((!ARGUMENT_PRESENT(Buffer)) && (*pulLength != 0)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(pszCustomPropertyName) {
|
||
//
|
||
// Convert property name to Unicode.
|
||
//
|
||
Win32Status = pSetupCaptureAndConvertAnsiArg(pszCustomPropertyName,
|
||
&UnicodeCustomPropName
|
||
);
|
||
|
||
if(Win32Status != NO_ERROR) {
|
||
//
|
||
// This routine guarantees that the returned unicode string
|
||
// pointer will be null upon failure, so we don't have to reset
|
||
// it here--just bail.
|
||
//
|
||
if(Win32Status == ERROR_NOT_ENOUGH_MEMORY) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
} else {
|
||
Status = CR_INVALID_POINTER;
|
||
}
|
||
goto Clean0;
|
||
}
|
||
|
||
} else {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Unfortunately, we have no clue as to whether or not the requested
|
||
// property is a string (thus requiring conversion from Unicode to
|
||
// ANSI). Therefore, we'll retrieve the data (if any) in its entirety,
|
||
// then convert to ANSI if necessary. Only then can we determine the
|
||
// data size (and whether it can be returned to the caller).
|
||
//
|
||
// Start out with a reasonable guess as to buffer size in an attempt to
|
||
// avoid calling the Unicode get-property API twice...
|
||
//
|
||
UniLen = 1024;
|
||
do {
|
||
pUniBuffer = pSetupMalloc(UniLen);
|
||
if(!pUniBuffer) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
Status = CM_Get_DevNode_Custom_Property_ExW(dnDevInst,
|
||
UnicodeCustomPropName,
|
||
&ulDataType,
|
||
pUniBuffer,
|
||
&UniLen,
|
||
ulFlags,
|
||
hMachine
|
||
);
|
||
if(Status != CR_SUCCESS) {
|
||
pSetupFree(pUniBuffer);
|
||
pUniBuffer = NULL;
|
||
}
|
||
|
||
} while(Status == CR_BUFFER_SMALL);
|
||
|
||
if(Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// If we get to here, we successfully retrieved the property.
|
||
//
|
||
if(pulRegDataType) {
|
||
*pulRegDataType = ulDataType;
|
||
}
|
||
|
||
if(UniLen == 0) {
|
||
//
|
||
// We retrieved an empty buffer--no need to worry about
|
||
// transferring any data into caller's buffer.
|
||
//
|
||
*pulLength = 0;
|
||
goto Clean0;
|
||
}
|
||
|
||
switch(ulDataType) {
|
||
|
||
case REG_MULTI_SZ :
|
||
case REG_SZ :
|
||
case REG_EXPAND_SZ :
|
||
//
|
||
// Worst case, an ANSI buffer large enough to hold the results
|
||
// would be the same size as the Unicode results.
|
||
//
|
||
pAnsiBuffer = pSetupMalloc(UniLen);
|
||
if(!pAnsiBuffer) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// do the ANSI conversion or retrieve the ANSI buffer size required.
|
||
// this may be a single-sz or multi-sz string, so we pass in the
|
||
// length, and let PnPUnicodeToMultiByte convert the entire buffer.
|
||
//
|
||
ulAnsiBufferLen = *pulLength;
|
||
Status = PnPUnicodeToMultiByte((PWSTR)pUniBuffer,
|
||
UniLen,
|
||
pAnsiBuffer,
|
||
&ulAnsiBufferLen);
|
||
|
||
if(ulAnsiBufferLen > *pulLength) {
|
||
ASSERT(Status == CR_BUFFER_SMALL);
|
||
Status = CR_BUFFER_SMALL;
|
||
} else {
|
||
//
|
||
// Copy ANSI string(s) into caller's buffer.
|
||
//
|
||
CopyMemory(Buffer, pAnsiBuffer, ulAnsiBufferLen);
|
||
}
|
||
|
||
*pulLength = ulAnsiBufferLen;
|
||
|
||
break;
|
||
|
||
default :
|
||
//
|
||
// buffer doesn't contain text, no conversion necessary.
|
||
//
|
||
if(UniLen > *pulLength) {
|
||
Status = CR_BUFFER_SMALL;
|
||
} else {
|
||
CopyMemory(Buffer, pUniBuffer, UniLen);
|
||
}
|
||
|
||
*pulLength = UniLen;
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
//
|
||
// Reference the following variables so the compiler will respect
|
||
// statement ordering w.r.t. their assignment.
|
||
//
|
||
pUniBuffer = pUniBuffer;
|
||
pAnsiBuffer = pAnsiBuffer;
|
||
}
|
||
|
||
if(UnicodeCustomPropName) {
|
||
pSetupFree(UnicodeCustomPropName);
|
||
}
|
||
|
||
if(pUniBuffer) {
|
||
pSetupFree(pUniBuffer);
|
||
}
|
||
|
||
if(pAnsiBuffer) {
|
||
pSetupFree(pAnsiBuffer);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_DevNode_Custom_Property_ExA
|
||
|
||
|
||
|
||
//-------------------------------------------------------------------
|
||
// Private utility routines
|
||
//-------------------------------------------------------------------
|
||
|
||
|
||
ULONG
|
||
GetPropertyDataType(
|
||
IN ULONG ulProperty)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes a property ID and returns the registry data type that
|
||
is used to store this property data (i.e., REG_SZ, etc).
|
||
Parameters:
|
||
|
||
ulProperty Property ID (one of the CM_DRP_* defines)
|
||
|
||
Return Value:
|
||
|
||
Returns one of the predefined registry data types, REG_BINARY is the default.
|
||
|
||
--*/
|
||
|
||
{
|
||
switch(ulProperty) {
|
||
|
||
case CM_DRP_DEVICEDESC:
|
||
case CM_DRP_SERVICE:
|
||
case CM_DRP_CLASS:
|
||
case CM_DRP_CLASSGUID:
|
||
case CM_DRP_DRIVER:
|
||
case CM_DRP_MFG:
|
||
case CM_DRP_FRIENDLYNAME:
|
||
case CM_DRP_LOCATION_INFORMATION:
|
||
case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
|
||
case CM_DRP_ENUMERATOR_NAME:
|
||
case CM_DRP_SECURITY_SDS: // and CM_CRP_SECURITY_SDS
|
||
case CM_DRP_UI_NUMBER_DESC_FORMAT:
|
||
return REG_SZ;
|
||
|
||
case CM_DRP_HARDWAREID:
|
||
case CM_DRP_COMPATIBLEIDS:
|
||
case CM_DRP_UPPERFILTERS:
|
||
case CM_DRP_LOWERFILTERS:
|
||
return REG_MULTI_SZ;
|
||
|
||
case CM_DRP_CONFIGFLAGS:
|
||
case CM_DRP_CAPABILITIES:
|
||
case CM_DRP_UI_NUMBER:
|
||
case CM_DRP_LEGACYBUSTYPE:
|
||
case CM_DRP_BUSNUMBER:
|
||
case CM_DRP_CHARACTERISTICS: // and CM_CRP_CHARACTERISTICS
|
||
case CM_DRP_EXCLUSIVE: // and CM_CRP_EXCLUSIVE
|
||
case CM_DRP_DEVTYPE: // and CM_CRP_DEVTYPE
|
||
case CM_DRP_ADDRESS:
|
||
case CM_DRP_REMOVAL_POLICY:
|
||
case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
|
||
case CM_DRP_REMOVAL_POLICY_OVERRIDE:
|
||
case CM_DRP_INSTALL_STATE:
|
||
return REG_DWORD;
|
||
|
||
case CM_DRP_BUSTYPEGUID:
|
||
case CM_DRP_SECURITY: // and CM_CRP_SECURITY
|
||
|
||
return REG_BINARY;
|
||
|
||
case CM_DRP_DEVICE_POWER_DATA:
|
||
return REG_BINARY;
|
||
|
||
default:
|
||
//
|
||
// We should never get here!
|
||
//
|
||
ASSERT(0);
|
||
return REG_BINARY;
|
||
}
|
||
|
||
} // GetPropertyDataType
|
||
|
||
|
||
|
||
|