2163 lines
57 KiB
C
2163 lines
57 KiB
C
/*++
|
||
|
||
Copyright (c) 1995-2001 Microsoft Corporation
|
||
|
||
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"
|
||
#include "cfgi.h"
|
||
|
||
#include "setupapi.h"
|
||
#include "spapip.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 one of the following:
|
||
CR_ALREADY_SUCH_DEVNODE,
|
||
CR_INVALID_DEVICE_ID,
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_POINTER, or
|
||
CR_OUT_OF_MEMORY.
|
||
|
||
--*/
|
||
|
||
{
|
||
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;
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (!ARGUMENT_PRESENT(pdnDevInst)) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (dnParent == 0) {
|
||
Status = CR_INVALID_DEVINST;
|
||
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 ((!ARGUMENT_PRESENT(pDeviceID)) ||
|
||
(lstrlen(pDeviceID) >= MAX_DEVICE_ID_LEN)) {
|
||
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, lstrlen(pDeviceID));
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
}
|
||
|
||
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 **
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_DEVNODE,
|
||
CR_OUT_OF_MEMORY.
|
||
(Windows 95 may also return CR_NOT_AT_APPY_TIME.)
|
||
|
||
--*/
|
||
|
||
{
|
||
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 one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_INVALID_DEVNODE,
|
||
CR_OUT_OF_MEMORY, 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 (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;
|
||
}
|
||
|
||
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
|
||
|
||
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 one of the following:
|
||
CR_INVALID_FLAG,
|
||
CR_NOT_DISABLEABLE, or
|
||
CR_INVALID_DEVNODE.
|
||
(Note, Windows 95 also may return CR_NOT_AT_APPY_TIME.)
|
||
|
||
--*/
|
||
|
||
{
|
||
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;
|
||
|
||
|
||
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;
|
||
}
|
||
|
||
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
|
||
|
||
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 one of the following:
|
||
CR_INVALID_FLAG or
|
||
CR_INVALID_DEVNODE.
|
||
(Note, Windows 95 also may return CR_NOT_AT_APPY_TIME.)
|
||
|
||
--*/
|
||
|
||
{
|
||
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 (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;
|
||
}
|
||
|
||
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 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
|
||
|
||
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 one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG, or
|
||
CR_INVALID_POINTER.
|
||
|
||
--*/
|
||
|
||
{
|
||
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;
|
||
}
|
||
|
||
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 one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG.
|
||
|
||
--*/
|
||
|
||
{
|
||
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 (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;
|
||
}
|
||
|
||
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
|
||
|
||
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 Must be zero.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is CR_INVALID_FLAG (i.e., the
|
||
function does not fail). The device instance is not checked for validity.
|
||
|
||
--*/
|
||
|
||
{
|
||
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 (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;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_DeviceInstanceAction(
|
||
hBinding, // rpc binding handle
|
||
PNP_DEVINST_REENUMERATE, // requested major action-REMOVESUBTREE
|
||
ulFlags, // requested minor action
|
||
DeviceID, // device instance subtree to remove
|
||
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
|
||
|
||
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 one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG,
|
||
CR_REMOVE_VETOED. (Windows 95 may also return CR_NOT_AT_APPY_TIME.)
|
||
|
||
--*/
|
||
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR pDeviceID [MAX_DEVICE_ID_LEN];
|
||
PVOID hStringTable = NULL;
|
||
handle_t hBinding = NULL;
|
||
ULONG ulLen = MAX_DEVICE_ID_LEN;
|
||
|
||
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;
|
||
}
|
||
|
||
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
|
||
|
||
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 **
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG,
|
||
CR_REMOVE_VETOED. (Windows 95 may also return CR_NOT_AT_APPY_TIME.)
|
||
|
||
--*/
|
||
|
||
{
|
||
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 **
|
||
|
||
If the function succeeds, the return value is CR_SUCCESS.
|
||
If the function fails, the return value is one of the following:
|
||
CR_INVALID_DEVNODE or
|
||
CR_INVALID_FLAG.
|
||
(Windows 95 may also return CR_NOT_AT_APPY_TIME.)
|
||
|
||
--*/
|
||
|
||
{
|
||
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 one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG, or
|
||
CR_REGISTRY_ERROR
|
||
|
||
--*/
|
||
|
||
{
|
||
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;
|
||
}
|
||
|
||
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
|
||
//
|
||
Status = GetDevNodeKeyPath(hBinding, DeviceID,
|
||
CM_REGISTRY_HARDWARE | CM_REGISTRY_USER,
|
||
0, szParentKey, szChildKey);
|
||
|
||
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 one of the following:
|
||
CR_INVALID_DEVNODE,
|
||
CR_INVALID_FLAG, or
|
||
CR_REGISTRY_ERROR
|
||
|
||
--*/
|
||
|
||
{
|
||
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;
|
||
|
||
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;
|
||
}
|
||
|
||
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
|
||
|
||
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.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
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;
|
||
}
|
||
|
||
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.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
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 (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;
|
||
}
|
||
|
||
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
|
||
|
||
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;
|
||
PWSTR pUniVetoName = NULL;
|
||
ULONG ulAnsiBufferLen;
|
||
|
||
//
|
||
// 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) {
|
||
//
|
||
// convert the unicode buffer to an ANSI string and copy to the caller's
|
||
// buffer
|
||
//
|
||
ulAnsiBufferLen = ulNameLength;
|
||
Status = PnPUnicodeToMultiByte(pUniVetoName,
|
||
(lstrlenW(pUniVetoName)+1)*sizeof(WCHAR),
|
||
pszVetoName,
|
||
&ulAnsiBufferLen);
|
||
}
|
||
|
||
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;
|
||
PWSTR pUniVetoName = NULL;
|
||
ULONG ulAnsiBufferLen;
|
||
|
||
//
|
||
// 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) {
|
||
//
|
||
// convert the unicode buffer to an ANSI string and copy to the caller's
|
||
// buffer
|
||
//
|
||
ulAnsiBufferLen = ulNameLength;
|
||
Status = PnPUnicodeToMultiByte(pUniVetoName,
|
||
(lstrlenW(pUniVetoName)+1)*sizeof(WCHAR),
|
||
pszVetoName,
|
||
&ulAnsiBufferLen);
|
||
}
|
||
|
||
if (pUniVetoName != NULL) {
|
||
pSetupFree(pUniVetoName);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Request_Device_Eject_ExA
|
||
|
||
|
||
|