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
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
|
|
|
|
|
|
|