Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2428 lines
67 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
devnode.c
Abstract:
This module contains the API routines that operate directly on device
instances (or DevNodes, in Win95 terminology).
CM_Create_DevNode
CM_Setup_DevNode
CM_Disable_DevNode
CM_Enable_DevNode
CM_Get_DevNode_Status
CM_Set_DevNode_Problem
CM_Reenumerate_DevNode
CM_Query_And_Remove_SubTree
CM_Uninstall_DevNode
CM_Request_Device_Eject
CM_Add_ID
CM_Register_Device_Driver
This module also contains the following API routines which are
not implemented.
CM_Move_DevNode
CM_Query_Remove_Subtree
CM_Remove_SubTree
Author:
Paula Tomlinson (paulat) 6-20-1995
Environment:
User mode only.
Revision History:
6-Jun-1995 paulat
Creation and initial implementation.
--*/
//
// includes
//
#include "precomp.h"
#pragma hdrstop
#include "cfgi.h"
#include <pnpmgr.h>
CONFIGRET
CM_Create_DevNode_ExW(
OUT PDEVINST pdnDevInst,
IN DEVINSTID_W pDeviceID,
IN DEVINST dnParent,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine creates a new device instance in the hardware tree.
Parameters:
pdnDevNode Supplies the address of the variable that receives a handle
to the new device instance.
pDeviceID Supplies a pointer to a NULL-terminated string specifying
the device instance ID for this new device instance. This
is the registry path (relative to the Enum branch) where
this device instance will be located (e.g., Root\*PNP0500\0000).
In Windows NT, this parameter is not optional.
dnParent Supplies the handle of the device instance that is the parent
of the device instance being created.
ulFlags Supplies flags specifying options for the creation of the
device instance. May be one of the following values:
CM_CREATE_DEVNODE_NORMAL
Create the device instance now, and perform installation
for it at a later time.
CM_CREATE_DEVNODE_NO_WAIT_INSTALL
Create the device instance, and perform installation for
it immediately.
CM_CREATE_DEVNODE_PHANTOM
Create a phantom device instance (i.e., a handle to a
device instance that is not alive as far as the ConfigMgr
APIs are concerned). This may be used for CM APIs that
require a devnode handle, but for which no real devnode
currently exists (e.g., registry property APIs). This
flag may not be specified with CR_CREATE_DEVNODE_NORMAL
or CR_CREATE_DEVNODE_NO_WAIT_INSTALL. A phantom devnode
created in this manner is not accessible to other callers
(i.e., CM_Locate_DevNode won't find it). However, callers
attempting to create a devnode with the same name as this
phantom devnode will not be able to do so (they will get
CR_ALREADY_SUCH_DEVNODE).
CM_CREATE_DEVNODE_GENERATE_ID
Create a Root-enumerated devnode using a unique device
instance ID generated from the supplied device ID in
pDeviceID. If this flag is set, then pDeviceID is assumed
to contain simply a device ID (i.e., no enumerator key
prefix, and no device instance suffix). A unique 4-digit,
base-10 identifier string will be created under
Enum\Root\<pDeviceID>, and the devnode will be created
based on that device instance ID. For instance, to add a
new legacy COM port devnode, this API would be called with
a pDeviceID of *PNP0500. Assuming there was already one
COM port instance in the registry (instance 0000), the new
device instance ID would be: Root\*PNP0500\0001
The caller may find out what device instance name was
generated by calling CM_Get_Device_ID with the devnode
returned from this API.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_ALREADY_SUCH_DEVNODE,
CR_INVALID_DEVICE_ID,
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_INVALID_POINTER,
CR_OUT_OF_MEMORY,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR ParentID[MAX_DEVICE_ID_LEN];
WCHAR szNewDeviceID[MAX_DEVICE_ID_LEN];
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen=MAX_DEVICE_ID_LEN;
BOOL Success;
size_t DeviceIDLen;
try {
//
// validate parameters
//
if (!ARGUMENT_PRESENT(pdnDevInst)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if (dnParent == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
if (!ARGUMENT_PRESENT(pDeviceID)) {
Status = CR_INVALID_DEVICE_ID;
goto Clean0;
}
//
// the length of the supplied device id string must be shorter than
// MAX_DEVICE_ID_LEN chars so that there is also room for the NULL term
// char in a buffer of this size. (many of the CM_ APIs make different
// assumptions about the consideration of the NULL term char in
// MAX_DEVICE_ID_LEN; account for the NULL term char to be safe)
//
if (FAILED(StringCchLength(pDeviceID,
MAX_DEVICE_ID_LEN,
&DeviceIDLen))) {
Status = CR_INVALID_DEVICE_ID;
goto Clean0;
}
ASSERT(DeviceIDLen < MAX_DEVICE_ID_LEN);
if (DeviceIDLen == 0) {
Status = CR_INVALID_DEVICE_ID;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, CM_CREATE_DEVNODE_BITS)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
//
// Windows NT 5.0 does not support CM_CREATE_DEVNODE_NO_WAIT_INSTALL
//
if (ulFlags & CM_CREATE_DEVNODE_NO_WAIT_INSTALL) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
//
// setup rpc binding handle and string table handle
//
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
//
// Initialize the caller's devnode. This will have the side effect of
// generating an exception before we actually do anything if the caller
// supplied a bogus address.
//
*pdnDevInst = 0;
//
// 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, dnParent,ParentID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(ParentID)) {
Status = CR_INVALID_DEVNODE;
goto Clean0;
}
//
// make sure the new device instance is properly formatted
//
CopyFixedUpDeviceId(szNewDeviceID,
pDeviceID,
(DWORD)DeviceIDLen);
//
// If not requesting instance generation, then it must be a
// valid device instance path.
//
if (!(ulFlags & CM_CREATE_DEVINST_GENERATE_ID)) {
if ((!*szNewDeviceID) ||
(!IsLegalDeviceId(szNewDeviceID))) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
}
//
// Special privileges are no longer required by the server.
//
// Note that with previous versions of the PlugPlay RPC server,
// SE_LOAD_DRIVER_PRIVILEGE was required for this operation. We do not
// need to enable the privilege for local callers, since this version of
// CFGMGR32 should match a local version of UMPNPMGR that does not
// require the privilege. For remote calls, it's not always possible
// for us to enable the privilege anyways, since the client may not have
// the privilege on the local machine, but may as authenticated on the
// server. The server typically sees all privileges that a remote
// caller has as "enabled by default", so we are not required to enable
// the privilege here either.
//
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_CreateDevInst(
hBinding, // rpc binding handle
szNewDeviceID, // device instance to create
ParentID, // parent device instance
MAX_DEVICE_ID_LEN, // max length of szNewDeviceID
ulFlags); // flags
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_CreateDevInst caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
if (Status != CR_SUCCESS) {
goto Clean0;
}
//
// assign a unique device instance value to the newly created device
// instance
//
ASSERT(*szNewDeviceID && IsLegalDeviceId(szNewDeviceID));
*pdnDevInst = pSetupStringTableAddString(hStringTable, szNewDeviceID,
STRTAB_CASE_SENSITIVE);
if (*pdnDevInst == 0) {
Status = CR_NO_SUCH_DEVNODE;
}
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Create_DevNode_ExW
CONFIGRET
CM_Move_DevNode_Ex(
IN DEVINST dnFromDevInst,
IN DEVINST dnToDevInst,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine replaces a root-enumerated device instance by the valid
non-root-enumerated device instance. The device installer uses this
service when it detects that a non-root enumerated device instance is
really the same as its root enumerated counterpart. This API migrates
the old device instance to the new location, and marks the old location
as having a problem.
** THIS ROUTINE IS NOT IMPLEMENTED **
Parameters:
dnFromDevNode Supplies the handle of the device instance that has been
root enumerated.
dnToDevNode Supplies the handle of the device instance that is a
reenumeration (duplicate) of the root device instance.
ulFlags Must be zero.
Return Value:
** PRESENTLY, ALWAYS RETURNS CR_CALL_NOT_IMPLEMENTED **
--*/
{
UNREFERENCED_PARAMETER(dnFromDevInst);
UNREFERENCED_PARAMETER(dnToDevInst);
UNREFERENCED_PARAMETER(ulFlags);
UNREFERENCED_PARAMETER(hMachine);
return CR_CALL_NOT_IMPLEMENTED;
} // CM_Move_DevNode_Ex
CONFIGRET
CM_Setup_DevNode_Ex(
IN DEVINST dnDevInst,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine reenables and configures a specified device instance or
retrieves information from its enumerator.
Parameters:
dnDevNode Supplies the handle of the device instance which may be
reconfigured.
ulFlags Supplies a flag indicating the action to take. Can be one
of the following values:
CM_SETUP_DEVNODE_READY
Reenable the device instance that had a problem.
CM_SETUP_DOWNLOAD
Retrieve information about this device instance
from its enumerator.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_FLAG,
CR_INVALID_DEVNODE,
CR_OUT_OF_MEMORY,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen=MAX_DEVICE_ID_LEN;
BOOL Success;
HANDLE hToken;
ULONG ulPrivilege;
try {
//
// validate parameters
//
if (INVALID_FLAGS(ulFlags, CM_SETUP_BITS)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// setup rpc binding handle and string table handle
//
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
//
// retrieve the device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// Enable privileges required by the server
//
ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
hToken = PnPEnablePrivileges(&ulPrivilege, 1);
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_DeviceInstanceAction(
hBinding, // rpc binding handle
PNP_DEVINST_SETUP, // requested major action - SETUP
ulFlags, // requested minor action
DeviceID, // device instance to create
NULL); // (not used)
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_DeviceInstanceAction caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//
// Restore previous privileges
//
PnPRestorePrivileges(hToken);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Setup_DevNode_Ex
CONFIGRET
CM_Disable_DevNode_Ex(
IN DEVINST dnDevInst,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine disables a device instance.
Parameters:
dnDevNode Supplies the handle of the device instance to be disabled.
ulFlags May be one of CM_DISABLE_BITS.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_FLAG,
CR_NOT_DISABLEABLE,
CR_INVALID_DEVNODE,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
ULONG ulLen = MAX_DEVICE_ID_LEN;
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
BOOL Success;
PNP_VETO_TYPE vetoType, *pVetoType;
WCHAR vetoName[MAX_DEVICE_ID_LEN], *pszVetoName;
ULONG ulNameLength;
HANDLE hToken;
ULONG ulPrivilege;
try {
//
// validate parameters
//
if (INVALID_FLAGS(ulFlags, CM_DISABLE_BITS)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// setup rpc binding handle and string table handle
//
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
//
// retrieve the device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
if (ulFlags & CM_DISABLE_UI_NOT_OK) {
vetoType = PNP_VetoTypeUnknown;
pVetoType = &vetoType;
vetoName[0] = L'\0';
pszVetoName = &vetoName[0];
ulNameLength = MAX_DEVICE_ID_LEN;
} else {
pVetoType = NULL;
pszVetoName = NULL;
ulNameLength = 0;
}
//
// Enable privileges required by the server
//
ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
hToken = PnPEnablePrivileges(&ulPrivilege, 1);
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_DisableDevInst(
hBinding, // rpc binding handle
DeviceID, // device instance to create
pVetoType,
pszVetoName,
ulNameLength,
ulFlags); // requested minor action (not used)
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_DisableDevInst caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//
// Restore previous privileges
//
PnPRestorePrivileges(hToken);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Disable_DevNode_Ex
CONFIGRET
CM_Enable_DevNode_Ex(
IN DEVINST dnDevInst,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine enables a device instance.
Parameters:
dnDevNode Supplies the handle of the device instance to enable.
ulFlags Must be zero.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_FLAG,
CR_INVALID_DEVNODE,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
ULONG ulLen = MAX_DEVICE_ID_LEN;
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
BOOL Success;
HANDLE hToken;
ULONG ulPrivilege;
try {
//
// validate parameters
//
if (INVALID_FLAGS(ulFlags, 0)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// setup rpc binding handle and string table handle
//
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
//
// retrieve the device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// Enable privileges required by the server
//
ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
hToken = PnPEnablePrivileges(&ulPrivilege, 1);
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_DeviceInstanceAction(
hBinding, // rpc binding handle
PNP_DEVINST_ENABLE, // requested major action - ENABLE
ulFlags, // requested minor action (not used)
DeviceID, // device instance to enable
NULL); // (not used)
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_DeviceInstanceAction caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//
// Restore previous privileges
//
PnPRestorePrivileges(hToken);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Enable_DevNode_Ex
CONFIGRET
CM_Get_DevNode_Status_Ex(
OUT PULONG pulStatus,
OUT PULONG pulProblemNumber,
IN DEVINST dnDevInst,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine retrieves the status of a device instance.
Parameters:
pulStatus Supplies the address of the variable that receives the
status flag of the device instance. Can be a combination
of the DN_* values.
pulProblemNumber Supplies the address of the variable that receives an
identifier indicating the problem. Can be one of the
CM_PROB_* values.
dnDevNode Supplies the handle of the device instance for which
to retrieve status.
ulFlags Must be zero.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_INVALID_POINTER, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR DeviceID [MAX_DEVICE_ID_LEN];
ULONG ulLen = MAX_DEVICE_ID_LEN;
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
BOOL Success;
try {
//
// validate parameters
//
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
if ((!ARGUMENT_PRESENT(pulStatus)) ||
(!ARGUMENT_PRESENT(pulProblemNumber))) {
Status = CR_INVALID_POINTER;
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;
}
//
// retrieve the device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// No special privileges are required by the server
//
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_GetDeviceStatus(
hBinding, // rpc binding handle
DeviceID, // device instance to get status for
pulStatus, // return StatusFlags here
pulProblemNumber, // return Problem here
ulFlags); // (not used)
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_GetDeviceStatus caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Get_DevNode_Status_Ex
CONFIGRET
CM_Set_DevNode_Problem_Ex(
IN DEVINST dnDevInst,
IN ULONG ulProblem,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine clears or set the problem of a device instance.
Parameters:
dnDevNode Supplies the handle of the device instance for which
to set the problem.
ulProblem Supplies the new problem value. Can be one of the
CM_PROB_* values. If zero, the problem is cleared.
ulFlags Must be zero.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen = MAX_DEVICE_ID_LEN;
BOOL Success;
HANDLE hToken;
ULONG ulPrivilege;
try {
//
// validate parameters
//
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, CM_SET_DEVNODE_PROBLEM_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 device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// Enable privileges required by the server
//
ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
hToken = PnPEnablePrivileges(&ulPrivilege, 1);
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_SetDeviceProblem(
hBinding, // rpc binding handle
DeviceID, // device instance
ulProblem, // specifies new Problem
ulFlags); // (not used)
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_SetDeviceProblem caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//
// Restore previous privileges
//
PnPRestorePrivileges(hToken);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Set_DevNode_Problem_Ex
CONFIGRET
CM_Reenumerate_DevNode_Ex(
IN DEVINST dnDevInst,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine causes the specified device instance to be enumerated
(if it is enumerable).
Parameters:
dnDevNode Supplies the handle of the device instance to be enumerated.
ulFlags Supplies flags specifying options for the re-enumeration of the
device instance. May be one of the following values:
CM_REENUMERATE_NORMAL
CM_REENUMERATE_SYNCHRONOUS
CM_REENUMERATE_RETRY_INSTALLATION
CM_REENUMERATE_ASYNCHRONOUS
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR DeviceID [MAX_DEVICE_ID_LEN];
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen = MAX_DEVICE_ID_LEN;
BOOL Success;
HANDLE hToken;
ULONG ulPrivilege;
try {
//
// validate parameters
//
if (INVALID_FLAGS(ulFlags, CM_REENUMERATE_BITS)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// setup rpc binding handle and string table handle
//
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
//
// retrieve the device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// Enable privileges required by the server
//
ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
hToken = PnPEnablePrivileges(&ulPrivilege, 1);
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_DeviceInstanceAction(
hBinding, // rpc binding handle
PNP_DEVINST_REENUMERATE,// requested major action - REENUMERATE
ulFlags, // requested minor action
DeviceID, // device instance subtree to reenumerate
NULL); // (not used)
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_DeviceInstanceAction caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//
// Restore previous privileges
//
PnPRestorePrivileges(hToken);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Reenumerate_DevNode_Ex
CONFIGRET
CM_Query_And_Remove_SubTree_ExW(
IN DEVINST dnAncestor,
OUT PPNP_VETO_TYPE pVetoType,
OUT LPWSTR pszVetoName,
IN ULONG ulNameLength,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine checks whether a device instance and its progeny can be
removed. If the query isn't vetoed then a remove is done. The replaces
the old CM_Query_Remove_SubTree followed by CM_Remove_SubTree.
Parameters:
dnAncestor Supplies the handle of the device instance at the root of
the subtree to be removed.
ulFlags Specifies whether UI should be presented for
this action. Can be one of the following values:
CM_REMOVE_UI_OK - OK to present UI for query-removal.
CM_REMOVE_UI_NOT_OK - Don't present UI for query-removal.
CM_REMOVE_NO_RESTART - Don't attempt to restart the devnode.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_REMOVE_VETOED,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR pDeviceID [MAX_DEVICE_ID_LEN];
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen = MAX_DEVICE_ID_LEN;
HANDLE hToken;
ULONG ulPrivilege;
try {
//
// validate parameters
//
if (dnAncestor == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, CM_REMOVE_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 device instance ID string associated with the devinst
//
pSetupStringTableStringFromIdEx(hStringTable, dnAncestor,pDeviceID,&ulLen);
ASSERT(pDeviceID && *pDeviceID && IsLegalDeviceId(pDeviceID));
if (pDeviceID == NULL || INVALID_DEVINST(pDeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
if (ulNameLength == 0) {
pszVetoName = NULL;
}
if (pszVetoName != NULL) {
*pszVetoName = L'\0';
}
if (pVetoType != NULL) {
*pVetoType = PNP_VetoTypeUnknown;
}
//
// Enable privileges required by the server
//
ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
hToken = PnPEnablePrivileges(&ulPrivilege, 1);
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_QueryRemove(
hBinding, // rpc binding handle
pDeviceID, // device instance subtree to remove
pVetoType,
pszVetoName,
ulNameLength,
ulFlags);
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_QueryRemove caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//
// Restore previous privileges
//
PnPRestorePrivileges(hToken);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Query_And_Remove_SubTree_ExW
CONFIGRET
CM_Query_Remove_SubTree_Ex(
IN DEVINST dnAncestor,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine checks whether a device instance and its progeny can be
removed. This API must be called before calling CM_Remove_SubTree to
make sure applications prepare for the removal of the device or to
give the applications a chance to deny the request to remove the device.
If the removal happens ?surprise style? (i.e., there?s no advanced
warning or chance to veto), then this API should not be called before
calling CM_Remove_SubTree.
Parameters:
dnAncestor Supplies the handle of the device instance at the root of
the subtree to be removed.
ulFlags Specifies whether UI should be presented for
this action. Can be one of the following values:
CM_QUERY_REMOVE_UI_OK - OK to present UI for query-removal.
CM_QUERY_REMOVE_UI_NOT_OK -Don't present UI for query-removal.
Return Value:
** PRESENTLY, ALWAYS RETURNS CR_CALL_NOT_IMPLEMENTED **
--*/
{
UNREFERENCED_PARAMETER(dnAncestor);
UNREFERENCED_PARAMETER(ulFlags);
UNREFERENCED_PARAMETER(hMachine);
return CR_CALL_NOT_IMPLEMENTED;
} // CM_Query_Remove_SubTree_Ex
CONFIGRET
CM_Remove_SubTree_Ex(
IN DEVINST dnAncestor,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine removes a device instance and its children from the
running system. This API notifies each device instance in the subtree
of the dnAncestor parameter of the device's removal. (On Windows NT,
this means that each driver/service controlling a device in this
subtree receives a device removal notification.)
Parameters:
dnAncestor Supplies the handle of the device instance that is being removed.
ulFlags Must be either CM_REMOVE_UI_OK or CM_REMOVE_UI_NOT_OK.
Return Value:
** PRESENTLY, ALWAYS RETURNS CR_CALL_NOT_IMPLEMENTED **
--*/
{
UNREFERENCED_PARAMETER(dnAncestor);
UNREFERENCED_PARAMETER(ulFlags);
UNREFERENCED_PARAMETER(hMachine);
return CR_CALL_NOT_IMPLEMENTED;
} // CM_Remove_SubTree_Ex
CONFIGRET
CM_Uninstall_DevNode_Ex(
IN DEVNODE dnDevInst,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine uninstalls a device instance (i.e., deletes its registry
key(s) in the Enum branch). This API can only be called for phantom
device instances, and the handle supplied is invalid after the call.
This API does not attempt to delete all possible storage locations
associated with the device instance. It will do a recursive delete on
the devnode key, so that any subkeys will be removed. It will also
delete the devnode key (and any subkeys) located in the Enum branch
of each hardware profile. It will not delete any software keys or user
keys (CM_Delete_DevNode_Key must be called to do that before calling
this API).
Parameters:
dnPhantom Handle of a phantom device instance to uninstall. This
handle is typically retrieved by a call to CM_Locate_DevNode
or CM_Create_DevNode.
ulFlags Must be zero.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_REGISTRY_ERROR,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen = MAX_DEVICE_ID_LEN;
WCHAR szParentKey[MAX_CM_PATH], szChildKey[MAX_CM_PATH],
DeviceID[MAX_DEVICE_ID_LEN];
BOOL Success;
try {
//
// validate parameters
//
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;
}
//
// retrieve the device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// Special privileges are no longer required by the server.
//
// Note that with previous versions of the PlugPlay RPC server,
// SE_LOAD_DRIVER_PRIVILEGE was required for this operation. We do not
// need to enable the privilege for local callers, since this version of
// CFGMGR32 should match a local version of UMPNPMGR that does not
// require the privilege. For remote calls, it's not always possible
// for us to enable the privilege anyways, since the client may not have
// the privilege on the local machine, but may as authenticated on the
// server. The server typically sees all privileges that a remote
// caller has as "enabled by default", so we are not required to enable
// the privilege here either.
//
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_UninstallDevInst(
hBinding, // rpc binding handle
DeviceID, // device instance to uninstall
ulFlags); // (unused)
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_UninstallDevInst caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//------------------------------------------------------------------
// after deleting the main hw key and the config specific hw keys,
// cleanup the user hw key, which can only be done on the client
// side.
//------------------------------------------------------------------
//
// form the user hardware registry key path
//
// note - in some cases, GetDevNodeKeyPath may call PNP_GetClassInstance
// or PNP_SetDeviceRegProp to set values on the server, in which case
// special privileges would be required by the server. the call below,
// which specifies the flags (CM_REGISTRY_HARDWARE | CM_REGISTRY_USER)
// is NOT one of those cases, so there is no need to have any privileges
// enabled during this call.
//
Status =
GetDevNodeKeyPath(
hBinding,
DeviceID,
CM_REGISTRY_HARDWARE | CM_REGISTRY_USER,
0,
szParentKey,
SIZECHARS(szParentKey),
szChildKey,
SIZECHARS(szChildKey),
FALSE);
if (Status != CR_SUCCESS) {
goto Clean0;
}
//
// delete the specified private user key
//
Status = DeletePrivateKey(HKEY_CURRENT_USER, szParentKey, szChildKey);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Uninstall_DevNode_Ex
CONFIGRET
CM_Request_Device_Eject_ExW(
IN DEVNODE dnDevInst,
OUT PPNP_VETO_TYPE pVetoType,
OUT LPWSTR pszVetoName,
IN ULONG ulNameLength,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
Parameters:
dnDevInst Handle of a device instance. This handle is typically
retrieved by a call to CM_Locate_DevNode or CM_Create_DevNode.
ulFlags Must be zero.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_REGISTRY_ERROR,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen = MAX_DEVICE_ID_LEN;
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
BOOL Success;
HANDLE hToken;
ULONG ulPrivileges[2];
try {
//
// validate parameters
//
if (ulNameLength == 0) {
pszVetoName = NULL;
}
if (pszVetoName != NULL) {
*pszVetoName = L'\0';
}
if (pVetoType != NULL) {
*pVetoType = PNP_VetoTypeUnknown;
}
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// no flags are currently valid
//
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;
}
//
// retrieve the device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// Enable privileges required by the server
//
// Note - for most devices, only the SeLoadDriverPrivilege privilege
// will be required, however if the device being ejected is a dock
// device, the SeUndockPrivilege privilege will be required instead.
// Since we don't know if the device the user is requesting to eject is
// a dock device or not (that is determined on the server-side), we
// attempt to enable both privileges.
//
// ISSUE-2002/03/04-jamesca: Should client perform dock device check?
// We could avoid enabling one of these two privileges unecessarily
// if the client checked the capabilities of the device in advance to
// see if the device was actually a dock or not. In the case of a
// dock this routine would simply call CM_Request_Eject_PC, which
// would enable the SeUndockPrivilege. This logic already exists on
// the server, is it appropriate for the client also/instead?
//
ulPrivileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
ulPrivileges[1] = SE_UNDOCK_PRIVILEGE;
hToken = PnPEnablePrivileges(ulPrivileges, 2);
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_RequestDeviceEject(
hBinding, // rpc binding handle
DeviceID, // device instance subtree to remove
pVetoType,
pszVetoName,
ulNameLength,
ulFlags);
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_RequestDeviceEject caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//
// Restore previous privileges
//
PnPRestorePrivileges(hToken);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Request_Device_Eject_ExW
CONFIGRET
CM_Add_ID_ExW(
IN DEVINST dnDevInst,
IN PWSTR pszID,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine adds a device ID to a device instance's HardwareID or
CompatibleIDs list.
Parameters:
dnDevInst Handle of a device instance. This handle is typically
retrieved by a call to CM_Locate_DevNode or CM_Create_DevNode.
pszID Supplies a pointer to a NULL-terminated string specifying
the ID to be added.
ulFlags Supplies flags for the ID. May be one of the following values:
ID Type Flags:
CM_ADD_ID_HARDWARE The specified ID is a hardware ID. Add
it to the device instance's HardwareID
list.
CM_ADD_ID_COMPATIBLE The specified ID is a compatible ID.
Add it to the device instance's
CompatibleIDs list.
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_DEVNODE,
CR_INVALID_POINTER,
CR_INVALID_FLAG,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen = MAX_DEVICE_ID_LEN;
BOOL Success;
try {
//
// validate parameters
//
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
if (!ARGUMENT_PRESENT(pszID)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, CM_ADD_ID_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 device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// Special privileges are no longer required by the server.
//
// Note that with previous versions of the PlugPlay RPC server,
// SE_LOAD_DRIVER_PRIVILEGE was required for this operation. We do not
// need to enable the privilege for local callers, since this version of
// CFGMGR32 should match a local version of UMPNPMGR that does not
// require the privilege. For remote calls, it's not always possible
// for us to enable the privilege anyways, since the client may not have
// the privilege on the local machine, but may as authenticated on the
// server. The server typically sees all privileges that a remote
// caller has as "enabled by default", so we are not required to enable
// the privilege here either.
//
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_AddID(
hBinding, // rpc binding handle
DeviceID, // device instance
pszID, // id to add
ulFlags); // hardware or compatible
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_AddID caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Add_ID_ExW
CMAPI
CONFIGRET
CM_Register_Device_Driver_Ex(
IN DEVINST dnDevInst,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine registers the device driver for the specified device.
Parameters:
dnDevInst Handle of a device instance. This handle is typically
retrieved by a call to CM_Locate_DevNode or CM_Create_DevNode.
ulFlags Supplies flags for register the driver. May be one of the
following values:
CM_REGISTER_DEVICE_DRIVER_STATIC
CM_REGISTER_DEVICE_DRIVER_DISABLEABLE
CM_REGISTER_DEVICE_DRIVER_REMOVABLE
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is a CR error code.
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_ACCESS_DENIED, or
CR_FAILURE.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR DeviceID [MAX_DEVICE_ID_LEN];
PVOID hStringTable = NULL;
handle_t hBinding = NULL;
ULONG ulLen = MAX_DEVICE_ID_LEN;
BOOL Success;
HANDLE hToken;
ULONG ulPrivilege;
try {
//
// validate parameters
//
if (dnDevInst == 0) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, CM_REGISTER_DEVICE_DRIVER_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 device instance ID string associated with the devinst
//
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
//
// Enable privileges required by the server
//
ulPrivilege = SE_LOAD_DRIVER_PRIVILEGE;
hToken = PnPEnablePrivileges(&ulPrivilege, 1);
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_RegisterDriver(
hBinding, // rpc binding handle
DeviceID, // device instance
ulFlags); // hardware or compatible
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_RegisterDriver caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
//
// Restore previous privileges
//
PnPRestorePrivileges(hToken);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Register_Device_Driver_Ex
//-------------------------------------------------------------------
// Local Stubs
//-------------------------------------------------------------------
CONFIGRET
CM_Create_DevNodeW(
OUT PDEVINST pdnDevInst,
IN DEVINSTID_W pDeviceID,
IN DEVINST dnParent,
IN ULONG ulFlags
)
{
return CM_Create_DevNode_ExW(pdnDevInst, pDeviceID, dnParent,
ulFlags, NULL);
}
CONFIGRET
CM_Create_DevNodeA(
OUT PDEVINST pdnDevInst,
IN DEVINSTID_A pDeviceID,
IN DEVINST dnParent,
IN ULONG ulFlags
)
{
return CM_Create_DevNode_ExA(pdnDevInst, pDeviceID, dnParent,
ulFlags, NULL);
}
CONFIGRET
CM_Move_DevNode(
IN DEVINST dnFromDevInst,
IN DEVINST dnToDevInst,
IN ULONG ulFlags
)
{
return CM_Move_DevNode_Ex(dnFromDevInst, dnToDevInst, ulFlags, NULL);
}
CONFIGRET
CM_Setup_DevNode(
IN DEVINST dnDevInst,
IN ULONG ulFlags
)
{
return CM_Setup_DevNode_Ex(dnDevInst, ulFlags, NULL);
}
CONFIGRET
CM_Disable_DevNode(
IN DEVINST dnDevInst,
IN ULONG ulFlags
)
{
return CM_Disable_DevNode_Ex(dnDevInst, ulFlags, NULL);
}
CONFIGRET
CM_Enable_DevNode(
IN DEVINST dnDevInst,
IN ULONG ulFlags
)
{
return CM_Enable_DevNode_Ex(dnDevInst, ulFlags, NULL);
}
CONFIGRET
CM_Get_DevNode_Status(
OUT PULONG pulStatus,
OUT PULONG pulProblemNumber,
IN DEVINST dnDevInst,
IN ULONG ulFlags
)
{
return CM_Get_DevNode_Status_Ex(pulStatus, pulProblemNumber,
dnDevInst, ulFlags, NULL);
}
CONFIGRET
CM_Set_DevNode_Problem(
IN DEVINST dnDevInst,
IN ULONG ulProblem,
IN ULONG ulFlags
)
{
return CM_Set_DevNode_Problem_Ex(dnDevInst, ulProblem, ulFlags, NULL);
}
CONFIGRET
CM_Reenumerate_DevNode(
IN DEVINST dnDevInst,
IN ULONG ulFlags
)
{
return CM_Reenumerate_DevNode_Ex(dnDevInst, ulFlags, NULL);
}
CONFIGRET
CM_Query_And_Remove_SubTree(
IN DEVINST dnAncestor,
OUT PPNP_VETO_TYPE pVetoType,
OUT LPWSTR pszVetoName,
IN ULONG ulNameLength,
IN ULONG ulFlags
)
{
return CM_Query_And_Remove_SubTree_Ex( dnAncestor,
pVetoType,
pszVetoName,
ulNameLength,
ulFlags,
NULL);
}
CONFIGRET
CM_Query_And_Remove_SubTreeA(
IN DEVINST dnAncestor,
OUT PPNP_VETO_TYPE pVetoType,
OUT LPSTR pszVetoName,
IN ULONG ulNameLength,
IN ULONG ulFlags
)
{
return CM_Query_And_Remove_SubTree_ExA( dnAncestor,
pVetoType,
pszVetoName,
ulNameLength,
ulFlags,
NULL);
}
CONFIGRET
CM_Remove_SubTree(
IN DEVINST dnAncestor,
IN ULONG ulFlags
)
{
return CM_Remove_SubTree_Ex(dnAncestor, ulFlags, NULL);
}
CONFIGRET
CM_Uninstall_DevNode(
IN DEVNODE dnPhantom,
IN ULONG ulFlags
)
{
return CM_Uninstall_DevNode_Ex(dnPhantom, ulFlags, NULL);
}
CONFIGRET
CM_Add_IDW(
IN DEVINST dnDevInst,
IN PWSTR pszID,
IN ULONG ulFlags
)
{
return CM_Add_ID_ExW(dnDevInst, pszID, ulFlags, NULL);
}
CONFIGRET
CM_Add_IDA(
IN DEVINST dnDevInst,
IN PSTR pszID,
IN ULONG ulFlags
)
{
return CM_Add_ID_ExA(dnDevInst, pszID, ulFlags, NULL);
}
CMAPI
CONFIGRET
CM_Register_Device_Driver(
IN DEVINST dnDevInst,
IN ULONG ulFlags
)
{
return CM_Register_Device_Driver_Ex(dnDevInst, ulFlags, NULL);
}
CONFIGRET
CM_Query_Remove_SubTree(
IN DEVINST dnAncestor,
IN ULONG ulFlags
)
{
return CM_Query_Remove_SubTree_Ex(dnAncestor, ulFlags, NULL);
}
CONFIGRET
CM_Request_Device_EjectW(
IN DEVINST dnDevInst,
OUT PPNP_VETO_TYPE pVetoType,
OUT LPWSTR pszVetoName,
IN ULONG ulNameLength,
IN ULONG ulFlags
)
{
return CM_Request_Device_Eject_ExW(dnDevInst,
pVetoType,
pszVetoName,
ulNameLength,
ulFlags,
NULL);
}
CONFIGRET
CM_Request_Device_EjectA(
IN DEVNODE dnDevInst,
OUT PPNP_VETO_TYPE pVetoType,
OUT LPSTR pszVetoName,
IN ULONG ulNameLength,
IN ULONG ulFlags
)
{
return CM_Request_Device_Eject_ExA( dnDevInst,
pVetoType,
pszVetoName,
ulNameLength,
ulFlags,
NULL);
}
//-------------------------------------------------------------------
// ANSI STUBS
//-------------------------------------------------------------------
CONFIGRET
CM_Add_ID_ExA(
IN DEVINST dnDevInst,
IN PSTR pszID,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
{
CONFIGRET Status = CR_SUCCESS;
PWSTR pUniID = NULL;
if (pSetupCaptureAndConvertAnsiArg(pszID, &pUniID) == NO_ERROR) {
Status = CM_Add_ID_ExW(dnDevInst,
pUniID,
ulFlags,
hMachine);
pSetupFree(pUniID);
} else {
Status = CR_INVALID_POINTER;
}
return Status;
} // CM_Add_ID_ExA
CONFIGRET
CM_Create_DevNode_ExA(
OUT PDEVINST pdnDevInst,
IN DEVINSTID_A pDeviceID,
IN DEVINST dnParent,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
{
CONFIGRET Status = CR_SUCCESS;
PWSTR pUniDeviceID = NULL;
if (pSetupCaptureAndConvertAnsiArg(pDeviceID, &pUniDeviceID) == NO_ERROR) {
Status = CM_Create_DevNode_ExW(pdnDevInst,
pUniDeviceID,
dnParent,
ulFlags,
hMachine);
pSetupFree(pUniDeviceID);
} else {
Status = CR_INVALID_DEVICE_ID;
}
return Status;
} // CM_Create_DevNode_ExA
CONFIGRET
CM_Query_And_Remove_SubTree_ExA(
IN DEVINST dnAncestor,
OUT PPNP_VETO_TYPE pVetoType,
OUT LPSTR pszVetoName,
IN ULONG ulNameLength,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
{
CONFIGRET Status = CR_SUCCESS, tmpStatus;
PWSTR pUniVetoName = NULL;
ULONG ulAnsiBufferLen;
size_t UniBufferLen = 0;
//
// validate essential parameters only
//
if ((!ARGUMENT_PRESENT(pszVetoName)) && (ulNameLength != 0)) {
return CR_INVALID_POINTER;
}
if (ulNameLength != 0) {
//
// pass a Unicode buffer instead and convert back to caller's
// ANSI buffer on return
//
pUniVetoName = pSetupMalloc(MAX_VETO_NAME_LENGTH*sizeof(WCHAR));
if (pUniVetoName == NULL) {
return CR_OUT_OF_MEMORY;
}
}
//
// call the wide version
//
Status = CM_Query_And_Remove_SubTree_ExW(dnAncestor,
pVetoType,
pUniVetoName,
MAX_VETO_NAME_LENGTH,
ulFlags,
hMachine);
//
// We should never return a veto name longer than MAX_VETO_NAME_LENGTH.
//
ASSERT(Status != CR_BUFFER_SMALL);
if ((Status == CR_REMOVE_VETOED) && (ARGUMENT_PRESENT(pszVetoName))) {
//
// convert the unicode buffer to an ANSI string and copy to the caller's
// buffer
//
ASSERT(pUniVetoName != NULL);
if (FAILED(StringCchLength(
pUniVetoName,
MAX_VETO_NAME_LENGTH,
&UniBufferLen))) {
//
// the returned veto name is not a valid length (shouldn't happen),
// but still return that a veto occurred.
//
return CR_REMOVE_VETOED;
}
ulAnsiBufferLen = ulNameLength;
tmpStatus =
PnPUnicodeToMultiByte(
pUniVetoName,
(ULONG)((UniBufferLen + 1)*sizeof(WCHAR)),
pszVetoName,
&ulAnsiBufferLen);
//
// if conversion was unsuccessful, return that status instead
//
if (tmpStatus != CR_SUCCESS) {
Status = tmpStatus;
}
}
if (pUniVetoName != NULL) {
pSetupFree(pUniVetoName);
}
return Status;
} // CM_Query_And_Remove_SubTree_ExA
CONFIGRET
CM_Request_Device_Eject_ExA(
IN DEVNODE dnDevInst,
OUT PPNP_VETO_TYPE pVetoType,
OUT LPSTR pszVetoName,
IN ULONG ulNameLength,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
{
CONFIGRET Status = CR_SUCCESS, tmpStatus;
PWSTR pUniVetoName = NULL;
ULONG ulAnsiBufferLen;
size_t UniBufferLen = 0;
//
// validate essential parameters only
//
if ((!ARGUMENT_PRESENT(pszVetoName)) && (ulNameLength != 0)) {
return CR_INVALID_POINTER;
}
if (ulNameLength != 0) {
//
// pass a Unicode buffer instead and convert back to caller's
// ANSI buffer on return
//
pUniVetoName = pSetupMalloc(MAX_VETO_NAME_LENGTH*sizeof(WCHAR));
if (pUniVetoName == NULL) {
return CR_OUT_OF_MEMORY;
}
}
//
// call the wide version
//
Status = CM_Request_Device_Eject_ExW(dnDevInst,
pVetoType,
pUniVetoName,
MAX_VETO_NAME_LENGTH,
ulFlags,
hMachine);
//
// We should never return a veto name longer than MAX_VETO_NAME_LENGTH.
//
ASSERT(Status != CR_BUFFER_SMALL);
if ((Status == CR_REMOVE_VETOED) && (ARGUMENT_PRESENT(pszVetoName))) {
//
// convert the unicode buffer to an ANSI string and copy to the caller's
// buffer
//
ASSERT(pUniVetoName != NULL);
if (FAILED(StringCchLength(
pUniVetoName,
MAX_VETO_NAME_LENGTH,
&UniBufferLen))) {
//
// the returned veto name is not a valid length (shouldn't happen),
// but still return that a veto occurred.
//
return CR_REMOVE_VETOED;
}
ulAnsiBufferLen = ulNameLength;
tmpStatus =
PnPUnicodeToMultiByte(
pUniVetoName,
(ULONG)((UniBufferLen + 1)*sizeof(WCHAR)),
pszVetoName,
&ulAnsiBufferLen);
//
// if conversion was unsuccessful, return that status instead
//
if (tmpStatus != CR_SUCCESS) {
Status = tmpStatus;
}
}
if (pUniVetoName != NULL) {
pSetupFree(pUniVetoName);
}
return Status;
} // CM_Request_Device_Eject_ExA