windows-nt/Source/XPSP1/NT/base/pnp/cfgmgr32/misc.c
2020-09-26 16:20:57 +08:00

1784 lines
47 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1995-2001 Microsoft Corporation
Module Name:
misc.c
Abstract:
This module contains miscellaneous Configuration Manager API routines.
CM_Get_Version
CM_Is_Version_Available
CM_Connect_Machine
CM_Disconnect_Machine
CM_Get_Global_State
CM_Run_Detection
CM_Query_Arbitrator_Free_Data
CM_Query_Resource_Conflicts
CM_Query_Arbitrator_Free_Size
CMP_Report_LogOn
CMP_Init_Detection
CMP_WaitServicesAvailable
CMP_WaitNoPendingInstallEvents
CMP_GetBlockedDriverInfo
Author:
Paula Tomlinson (paulat) 6-20-1995
Environment:
User mode only.
Revision History:
20-Jun-1995 paulat
Creation and initial implementation.
--*/
//
// includes
//
#include "precomp.h"
#include "cfgi.h"
#include "setupapi.h"
#include "spapip.h"
#include "pnpipc.h"
//
// global data
//
extern PVOID hLocalStringTable; // NOT MODIFIED BY THESE PROCEDURES
extern WCHAR LocalMachineNameNetBIOS[]; // NOT MODIFIED BY THESE PROCEDURES
extern WCHAR LocalMachineNameDnsFullyQualified[];// NOT MODIFIED BY THESE PROCEDURES
#define NUM_LOGON_RETRIES 30
//
// Private prototypes
//
BOOL
IsRemoteServiceRunning(
IN LPCWSTR UNCServerName,
IN LPCWSTR ServiceName
);
WORD
CM_Get_Version_Ex(
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine retrieves the version number of the Configuration Manager APIs.
Arguments:
hMachine
Return value:
The function returns the major revision number in the high byte and the
minor revision number in the low byte. For example, version 4.0 of
Configuration Manager returns 0x0400.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WORD wVersion = (WORD)CFGMGR32_VERSION;
handle_t hBinding = NULL;
//
// setup rpc binding handle
//
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return wVersion = 0;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_GetVersion(
hBinding, // rpc machine name
&wVersion); // server size version
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_WARNINGS,
"PNP_GetVersion caused an exception (%d)\n",
RpcExceptionCode()));
SetLastError(RpcExceptionCode());
wVersion = 0;
}
RpcEndExcept
return wVersion;
} // CM_Get_Version_Ex
BOOL
CM_Is_Version_Available_Ex(
IN WORD wVersion,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine returns whether a specific version of the Configuration Manager
APIs are available.
Arguments:
wVersion - Version to query.
hMachine - Machine to connect to.
Return value:
The function returns TRUE if the version of the Configuration Manager APIs is
equal to or greater than the specified version.
--*/
{
CONFIGRET Status = CR_SUCCESS;
handle_t hBinding = NULL;
WORD wVersionInternal;
//
// version 0x0400 is available on all servers, by definition.
//
if (wVersion <= (WORD)0x0400) {
return TRUE;
}
//
// setup rpc binding handle
//
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
return FALSE;
}
//
// retrieve the internal server version.
//
if (!PnPGetVersion(hMachine, &wVersionInternal)) {
return FALSE;
}
//
// versions up to and including the internal server version are available.
//
return (wVersion <= wVersionInternal);
} // CM_Is_Version_Available_Ex
CONFIGRET
CM_Connect_MachineW(
IN PCWSTR UNCServerName,
OUT PHMACHINE phMachine
)
/*++
Routine Description:
This routine connects to the machine specified and returns a handle that
is then passed to future calls to the Ex versions of the CM routines.
This allows callers to get device information on remote machines.
Arguments:
UNCServerName - Specifies the UNC name of the remote machine to connect to.
phMachine - Specifies the address of a variable to receive a handle to
the connected machine.
Return value:
If the function succeeds, it returns CR_SUCCESS, otherwise it returns one
of the CR_* error codes.
--*/
{
CONFIGRET Status = CR_SUCCESS;
WORD wVersion = 0, wVersionInternal;
PPNP_MACHINE pMachine = NULL;
INT MachineNameLen;
try {
//
// validate parameters
//
if (!ARGUMENT_PRESENT(phMachine)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
*phMachine = NULL;
//
// if machine name specified, check for UNC format
//
if(UNCServerName && *UNCServerName) {
MachineNameLen = lstrlen(UNCServerName);
if((MachineNameLen < 3) || (MachineNameLen > (MAX_PATH + 2)) ||
(UNCServerName[0] != L'\\') ||
(UNCServerName[1] != L'\\')) {
Status = CR_INVALID_MACHINENAME;
goto Clean0;
}
}
//
// allocate memory for the machine structure and initialize it
//
pMachine = (PPNP_MACHINE)pSetupMalloc(sizeof(PNP_MACHINE));
if(!pMachine) {
Status = CR_OUT_OF_MEMORY;
goto Clean0;
}
if (!UNCServerName ||
!*UNCServerName ||
!lstrcmpi(UNCServerName, LocalMachineNameNetBIOS) ||
!lstrcmpi(UNCServerName, LocalMachineNameDnsFullyQualified)) {
//----------------------------------------------------------
// If no machine name was passed in or the machine name
// matches the local name, use local machine info rather
// than creating a new binding.
//----------------------------------------------------------
PnPGetGlobalHandles(NULL,
&pMachine->hStringTable,
&pMachine->hBindingHandle);
if (!UNCServerName) {
lstrcpy(pMachine->szMachineName, LocalMachineNameNetBIOS);
} else {
lstrcpy(pMachine->szMachineName, UNCServerName);
}
} else {
//
// First, make sure that the RemoteRegistry service is running on
// the remote machine, since RemoteRegistry is required for several
// cfgmgr32/setupapi services.
//
if (!IsRemoteServiceRunning(UNCServerName, L"RemoteRegistry")) {
Status = CR_NO_CM_SERVICES;
goto Clean0;
}
//-------------------------------------------------------------
// A remote machine name was specified so explicitly force a
// new binding for this machine.
//-------------------------------------------------------------
pMachine->hBindingHandle =
(PVOID)PNP_HANDLE_bind((PNP_HANDLE)UNCServerName);
if (pMachine->hBindingHandle == NULL) {
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
Status = CR_OUT_OF_MEMORY;
} else if (GetLastError() == ERROR_INVALID_COMPUTERNAME) {
Status = CR_INVALID_MACHINENAME;
} else {
Status = CR_FAILURE;
}
goto Clean0;
}
//
// initialize a string table for use with this connection to
// the remote machine
//
pMachine->hStringTable = pSetupStringTableInitialize();
if (pMachine->hStringTable == NULL) {
Status = CR_OUT_OF_MEMORY;
goto Clean0;
}
//
// Add a priming string (see dll entrypt in main.c for details)
//
pSetupStringTableAddString(pMachine->hStringTable,
PRIMING_STRING,
STRTAB_CASE_SENSITIVE);
//
// save the machine name
//
lstrcpy(pMachine->szMachineName, UNCServerName);
}
//
// test the binding by calling the simplest RPC call (good way
// for the caller to know whether the service is actually
// running)
//
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_GetVersion(
pMachine->hBindingHandle,
&wVersion);
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_WARNINGS,
"PNP_GetVersion caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
if (Status == CR_SUCCESS) {
//
// we got the standard version alright, now try to determine the
// internal version of the server. initialize the version supplied
// to the internal version of the client.
//
wVersionInternal = (WORD)CFGMGR32_VERSION_INTERNAL;
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_GetVersionInternal(pMachine->hBindingHandle,
&wVersionInternal);
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
//
// rpc exception may occur if the interface does not exist on
// the server, indicating a server version prior to NT 5.1.
//
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_WARNINGS,
"PNP_GetVersionInternal caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
if (Status == CR_SUCCESS) {
//
// PNP_GetVersionInternal exists on NT 5.1 and later.
//
ASSERT(wVersionInternal >= (WORD)0x0501);
//
// use the real internal version of the server instead of the
// static version returned by PNP_GetVersion.
//
wVersion = wVersionInternal;
}
//
// no matter what happened while trying to retrieve the internal
// version of the server, we were successful before this.
//
Status = CR_SUCCESS;
}
if (Status == CR_SUCCESS) {
pMachine->ulSignature = (ULONG)MACHINE_HANDLE_SIGNATURE;
pMachine->wVersion = wVersion;
*phMachine = (HMACHINE)pMachine;
}
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
if (Status != CR_SUCCESS && pMachine != NULL) {
pSetupFree(pMachine);
}
return Status;
} // CM_Connect_MachineW
CONFIGRET
CM_Disconnect_Machine(
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine disconnects from a machine that was previously connected to
with the CM_Connect_Machine call.
Arguments:
hMachine - Specifies a machine handle previously returned by a call to
CM_Connect_Machine.
Return value:
If the function succeeds, it returns CR_SUCCESS, otherwise it returns one
of the CR_* error codes.
--*/
{
CONFIGRET Status = CR_SUCCESS;
PPNP_MACHINE pMachine = NULL;
try {
//
// validate parameters
//
if (hMachine == NULL) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
pMachine = (PPNP_MACHINE)hMachine;
if (pMachine->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
//
// only free the machine info if it's not the local machine
//
if (pMachine->hStringTable != hLocalStringTable) {
//
// free the rpc binding for this remote machine
//
PNP_HANDLE_unbind((PNP_HANDLE)pMachine->szMachineName,
(handle_t)pMachine->hBindingHandle);
//
// release the string table
//
pSetupStringTableDestroy(pMachine->hStringTable);
}
//
// invalidate the signature so we never try to free it again.
//
pMachine->ulSignature = 0;
//
// free the memory for the PNP_MACHINE struct
//
pSetupFree(pMachine);
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Disconnect_Machine
CONFIGRET
CM_Get_Global_State_Ex(
OUT PULONG pulState,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine retrieves the global state of the configuration manager.
Parameters:
pulState Supplies the address of the variable that receives the
Configuration Manager<65>s state. May be a combination of the
following values:
Configuration Manager Global State Flags:
CM_GLOBAL_STATE_CAN_DO_UI
Can UI be initiated? [TBD: On NT, this may relate to
whether anyone is logged in]
CM_GLOBAL_STATE_SERVICES_AVAILABLE
Are the CM APIs available? (on Windows NT this is always set)
CM_GLOBAL_STATE_SHUTTING_DOWN
The Configuration Manager is shutting down.
[TBD: Does this only happen at shutdown/restart time?]
CM_GLOBAL_STATE_DETECTION_PENDING
The Configuration Manager is about to initiate some
sort of detection.
Windows 95 also defines the following additional flag:
CM_GLOBAL_STATE_ON_BIG_STACK
[TBD: What should this be defaulted to for NT?]
ulFlags Not used, 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.
--*/
{
CONFIGRET Status = CR_SUCCESS;
handle_t hBinding = NULL;
try {
//
// validate parameters
//
if (!ARGUMENT_PRESENT(pulState)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, 0)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
//
// setup rpc binding handle (don't need string table handle)
//
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_GetGlobalState(
hBinding, // rpc binding handle
pulState, // returns global state
ulFlags); // not used
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_GetGlobalState caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Get_Global_State_Ex
CONFIGRET
CM_Run_Detection_Ex(
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine loads and executes a detection module.
Parameters:
ulFlags - Specifies the reason for the detection. Can be one of the
following values:
Detection Flags:
CM_DETECT_NEW_PROFILE - Run detection for a new hardware
profile.
CM_DETECT_CRASHED - Previously attempted detection crashed.
(Windows 95 defines the following two unused flags as well:
CM_DETECT_HWPROF_FIRST_BOOT and CM_DETECT_RUN.)
Return Value:
If the function succeeds, the return value is CR_SUCCESS.
If the function fails, the return value is CR_INVALID_FLAG.
--*/
{
CONFIGRET Status = CR_SUCCESS;
handle_t hBinding = NULL;
try {
//
// validate parameters
//
if (INVALID_FLAGS(ulFlags, CM_DETECT_BITS)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
//
// setup rpc binding handle (don't need string table handle)
//
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_RunDetection(
hBinding,
ulFlags); // not used
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_RunDetection caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Run_Detection_Ex
CONFIGRET
CM_Query_Arbitrator_Free_Data_Ex(
OUT PVOID pData,
IN ULONG DataLen,
IN DEVINST dnDevInst,
IN RESOURCEID ResourceID,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine returns information about available resources of a
particular type. If the given size is not large enough, this API
truncates the data and returns CR_BUFFER_SMALL. To determine the
buffer size needed to receive all the available resource information,
use the CM_Query_Arbitrator_Free_Size API.
Parameters:
pData Supplies the address of the buffer that receives information
on the available resources for the resource type specified
by ResourceID.
DataLen Supplies the size, in bytes, of the data buffer.
dnDevNode Supplies the handle of the device instance associated with
the arbitrator. This is only meaningful for local
arbitrators--for global arbitrators, specify the root device
instance or NULL. On Windows NT, this parameter must
specify either the Root device instance or NULL.
ResourceID Supplies the type of the resource. Can be one of the ResType
values listed in Section 2.1.2.1.. (This API returns
CR_INVALID_RESOURCEID if this value is ResType_All or
ResType_None.)
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_BUFFER_SMALL,
CR_FAILURE,
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_INVALID_POINTER, or
CR_INVALID_RESOURCEID.
(Windows 95 may also return CR_NO_ARBITRATOR.)
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR pDeviceID [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(pData)) || (DataLen == 0)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, CM_QUERY_ARBITRATOR_BITS)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
if (ResourceID > ResType_MAX && ResourceID != ResType_ClassSpecific) {
Status = CR_INVALID_RESOURCEID;
goto Clean0;
}
//
// setup rpc binding handle (don't need 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,pDeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_QueryArbitratorFreeData(
hBinding,
pData,
DataLen,
pDeviceID,
ResourceID,
ulFlags); // not used
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_QueryArbitratorFreeData caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Query_Arbitrator_Free_Data_Ex
#if 0
CONFIGRET
WINAPI
CM_Query_Resource_Conflicts_Ex(
IN DEVINST dnDevInst,
IN RESOURCEID ResourceID,
IN PCVOID ResourceData,
IN ULONG ResourceLen,
IN OUT PVOID pData,
IN OUT PULONG pulDataLen,
IN ULONG ulFlags
)
/*++
Routine Description:
This routine returns a list of devnodes that own resources that would
conflict with the specified resource. If there are no conflicts, the
returned list is NULL. If the caller supplied buffer is not large enough,
CR_BUFFER_SMALL is returned and pulDataLen contains the required buffer
size.
Parameters:
dnDevInst Supplies the handle of the device instance associated with
the arbitrator. This is only meaningful for local
arbitrators--for global arbitrators, specify the root device
instance or NULL. On Windows NT, this parameter must
specify either the Root device instance or NULL. ???
ResourceID Supplies the type of the resource. Can be one of the ResType
values listed in Section 2.1.2.1.. (This API returns
CR_INVALID_RESOURCEID if this value is ResType_All or
ResType_None.)
ResourceData Supplies the adress of an IO_DES, MEM_DES, DMA_DES, IRQ_DES,
etc, structure, depending on the given resource type.
ResourceLen Supplies the size, in bytes, of the structure pointed to
by ResourceData.
pData Supplies the address of the buffer that receives information
on the available resources for the resource type specified
by ResourceID.
pulDataLen Supplies the size, in bytes, of the data buffer.
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_BUFFER_SMALL,
CR_FAILURE,
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_INVALID_POINTER, or
CR_INVALID_RESOURCEID.
(Windows 95 may also return CR_NO_ARBITRATOR.)
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR pDeviceID [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(pData)) ||
(!ARGUMENT_PRESENT(pulDataLen)) ||
(*pulDataLen == 0)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, CM_QUERY_ARBITRATOR_BITS)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
if (ResourceID > ResType_MAX && ResourceID != ResType_ClassSpecific) {
Status = CR_INVALID_RESOURCEID;
goto Clean0;
}
//
// setup rpc binding handle (don't need 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,pDeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_QueryArbitratorFreeData(
hBinding,
pData,
DataLen,
pDeviceID,
ResourceID,
ulFlags); // not used
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_QueryArbitratorFreeData caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Query_Resource_Conflicts_Ex
#endif
CONFIGRET
CM_Query_Arbitrator_Free_Size_Ex(
OUT PULONG pulSize,
IN DEVINST dnDevInst,
IN RESOURCEID ResourceID,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine retrieves the size of the available resource information
that would be returned in a call to the CM_Query_Arbitrator_Free_Data
API.
Parameters:
pulSize Supplies the address of the variable that receives the size,
in bytes, that is required to hold the available resource
information.
dnDevNode Supplies the handle of the device instance associated with
the arbitrator. This is only meaningful for local
arbitrators--for global arbitrators, specify the root
device instance or NULL. On Windows NT, this parameter
must specify either the Root device instance or NULL.
ResourceID Supplies the type of the resource. Can be one of the
ResType values listed in Section 2.1.2.1.. (This API returns
CR_INVALID_RESOURCEID if this value is ResType_All or
ResType_None.)
ulFlags CM_QUERY_ARBITRATOR_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_FAILURE,
CR_INVALID_DEVNODE,
CR_INVALID_FLAG,
CR_INVALID_POINTER, or
CR_INVALID_RESOURCEID.
(Windows 95 may also return CR_NO_ARBITRATOR.)
--*/
{
CONFIGRET Status = CR_SUCCESS;
WCHAR pDeviceID [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(pulSize)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, CM_QUERY_ARBITRATOR_BITS)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
if (ResourceID > ResType_MAX && ResourceID != ResType_ClassSpecific) {
Status = CR_INVALID_RESOURCEID;
goto Clean0;
}
//
// setup rpc binding handle (don't need 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,pDeviceID,&ulLen);
if (Success == FALSE || INVALID_DEVINST(pDeviceID)) {
Status = CR_INVALID_DEVINST;
goto Clean0;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_QueryArbitratorFreeSize(
hBinding,
pulSize,
pDeviceID,
ResourceID,
ulFlags); // not used
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_QueryArbitratorFreeSize caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CM_Query_Arbitrator_Free_Size_Ex
//-------------------------------------------------------------------
// Private CM routines
//-------------------------------------------------------------------
CONFIGRET
CMP_Report_LogOn(
IN ULONG ulPrivateID,
IN DWORD ProcessID
)
{
CONFIGRET Status = CR_SUCCESS;
handle_t hBinding = NULL;
BOOL bAdmin = FALSE;
DWORD Retries = 0;
//
// This routine currently gets called by userinit.exe to let us know
// that someone has just logged on.
//
try {
//
// validate parameters
//
if (ulPrivateID != 0x07020420) {
Status = CR_INVALID_DATA;
goto Clean0;
}
//
// this is always to the local server, by definition
//
if (!PnPGetGlobalHandles(NULL, NULL, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
//
// determine from the userinit process, whether the user
// logged onto an account that is part of Administrators
// local group
//
bAdmin = pSetupIsUserAdmin();
for (Retries = 0; Retries < NUM_LOGON_RETRIES; Retries++) {
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_ReportLogOn(
hBinding, // rpc binding handle
bAdmin, // Is Admin?
ProcessID); // userinit.exe process id
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_ReportLogOn caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
if (Status == CR_NO_CM_SERVICES ||
Status == CR_REMOTE_COMM_FAILURE) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PlugPlay services not available (%d), retrying...\n",
Status));
Sleep(5000); // wait and then retry
continue;
} else {
goto Clean0; // success or other non-rpc error
}
}
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CMP_Report_LogOn
CONFIGRET
CMP_Init_Detection(
IN ULONG ulPrivateID
)
{
CONFIGRET Status = CR_SUCCESS;
handle_t hBinding = NULL;
try {
//
// validate parameters
//
if (ulPrivateID != 0x07020420) {
Status = CR_INVALID_DATA;
goto Clean0;
}
//
// this is always to the local server, by definition
//
if (!PnPGetGlobalHandles(NULL, NULL, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_InitDetection(
hBinding); // rpc binding handle
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_ERRORS,
"PNP_InitDetection caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CMP_Init_Detection
CONFIGRET
CMP_WaitServicesAvailable(
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine determines whether the user-mode pnp manager server side
(umpnpmgr) is up and running yet (providing the PNP_Xxx side of the
config manager apis).
Parameters:
hMachine - private (opaque) cm machine handle. If NULL, the call refers
to the local machine.
Return Value:
If the service is avialable upon return then CR_SUCCESS is returned.
If some other failure occurs, CR_FAILURE is returned.
--*/
{
CONFIGRET Status = CR_NO_CM_SERVICES;
handle_t hBinding = NULL;
WORD wVersion;
try {
//
// setup rpc binding handle (don't need string table handle)
//
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
while ((Status == CR_NO_CM_SERVICES) ||
(Status == CR_MACHINE_UNAVAILABLE) ||
(Status == CR_REMOTE_COMM_FAILURE)) {
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_GetVersion(
hBinding, // rpc machine name
&wVersion); // server size version
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_WARNINGS,
"PNP_GetVersion caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
if (Status == CR_SUCCESS) {
//
// Service is avilable now, return success.
//
goto Clean0;
}
if ((Status == CR_NO_CM_SERVICES) ||
(Status == CR_MACHINE_UNAVAILABLE) ||
(Status == CR_REMOTE_COMM_FAILURE)) {
//
// This is some error related to the service not being
// available, wait and try again.
//
Sleep(5000);
} else {
//
// Some other error, the service may never be avaiable
// so bail out now.
//
Status = CR_FAILURE;
goto Clean0;
}
}
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CMP_WaitServicesAvailable
DWORD
CMP_WaitNoPendingInstallEvents(
IN DWORD dwTimeout
)
/*++
Routine Description:
This routine waits until there are no pending device install events.
If a timeout value is specified then it will return either when no
install events are pending or when the timeout period has expired,
whichever comes first. This routine is intended to be called after
user-logon, only.
NOTE: New install events can occur at anytime, this routine just
indicates that there are no install events at this moment.
Parameters:
dwTimeout - Specifies the time-out interval, in milliseconds. The function
returns if the interval elapses, even if there are still pending
install events. If dwTimeout is zero, the function just tests whether
there are pending install events and returns immediately. If
dwTimeout is INFINITE, the function's time-out interval never elapses.
Return Value:
If the function succeeds, the return value indicates the event that caused
the function to return. If the function fails, the return value is
WAIT_FAILED. To get extended error information, call GetLastError.
The return value on success is one of the following values:
WAIT_ABANDONED The specified object is a mutex object that was not
released by the thread that owned the mutex object before
the owning thread terminated. Ownership of the mutex
object is granted to the calling thread, and the mutex is
set to nonsignaled.
WAIT_OBJECT_0 The state of the specified object is signaled.
WAIT_TIMEOUT The time-out interval elapsed, and the object's state is
nonsignaled.
--*/
{
DWORD Status = WAIT_FAILED;
HANDLE hEvent = NULL;
try {
hEvent = OpenEvent(SYNCHRONIZE, FALSE, PNP_NO_INSTALL_EVENTS);
if (hEvent == NULL) {
Status = WAIT_FAILED;
} else {
Status = WaitForSingleObject(hEvent, dwTimeout);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = WAIT_FAILED;
}
if (hEvent) {
CloseHandle(hEvent);
}
return Status;
} // CMP_WaitNoPendingInstallEvents
CONFIGRET
CMP_GetBlockedDriverInfo(
OUT LPBYTE Buffer,
IN OUT PULONG pulLength,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine retrieves the list of drivers that have been blocked from
loading on the system since boot.
Arguments:
Buffer - Supplies the address of the buffer that receives the list of
drivers that have been blocked from loading on the system. Can
be NULL when simply retrieving data size.
pulLength - Supplies the address of the variable that contains the size, in
bytes, of the buffer. If the variable is initially zero, the
API replaces it with the buffer size needed to receive all the
data. In this case, the Buffer parameter is ignored.
ulFlags - Must be zero.
hMachine - Machine handle returned from CM_Connect_Machine or NULL.
Return value:
If the function succeeds, it returns CR_SUCCESS, otherwise it returns one of
the CR_* error codes.
--*/
{
CONFIGRET Status;
ULONG ulTransferLen;
BYTE NullBuffer = 0;
handle_t hBinding = NULL;
try {
//
// validate parameters
//
if (!ARGUMENT_PRESENT(pulLength)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if ((!ARGUMENT_PRESENT(Buffer)) && (*pulLength != 0)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, 0)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
//
// setup rpc binding handle (don't need string table handle)
//
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
//
// NOTE: The ulTransferLen variable is just used to control
// how much data is marshalled via rpc between address spaces.
// ulTransferLen should be set on entry to the size of the Buffer.
// The last parameter should also be the size of the Buffer on entry
// and on exit contains either the amount transferred (if a transfer
// occured) or the amount required, this value should be passed back
// in the callers pulLength parameter.
//
ulTransferLen = *pulLength;
if (!ARGUMENT_PRESENT(Buffer)) {
Buffer = &NullBuffer;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_GetBlockedDriverInfo(
hBinding, // rpc binding handle
Buffer, // receives blocked driver info
&ulTransferLen, // input/output buffer size
pulLength, // bytes copied (or bytes required)
ulFlags); // not used
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_WARNINGS,
"PNP_GetBlockedDriverInfo caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CMP_GetBlockedDriverInfo
CONFIGRET
CMP_GetServerSideDeviceInstallFlags(
IN PULONG pulSSDIFlags,
IN ULONG ulFlags,
IN HMACHINE hMachine
)
/*++
Routine Description:
This routine retrieves the server side device install flags.
Arguments:
pulSSDIFlags - Pointer to a ULONG that receives the server side device
install flags.
ulFlags - Must be zero.
hMachine - Machine handle returned from CM_Connect_Machine or NULL.
Return value:
If the function succeeds, it returns CR_SUCCESS, otherwise it returns one of
the CR_* error codes.
--*/
{
CONFIGRET Status;
handle_t hBinding = NULL;
try {
//
// validate parameters
//
if (!ARGUMENT_PRESENT(pulSSDIFlags)) {
Status = CR_INVALID_POINTER;
goto Clean0;
}
if (INVALID_FLAGS(ulFlags, 0)) {
Status = CR_INVALID_FLAG;
goto Clean0;
}
//
// setup rpc binding handle (don't need string table handle)
//
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
Status = CR_FAILURE;
goto Clean0;
}
RpcTryExcept {
//
// call rpc service entry point
//
Status = PNP_GetServerSideDeviceInstallFlags(
hBinding, // rpc binding handle
pulSSDIFlags, // receives server side device install flags
ulFlags); // not used
}
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
KdPrintEx((DPFLTR_PNPMGR_ID,
DBGF_WARNINGS,
"PNP_GetServerSideDeviceInstallFlags caused an exception (%d)\n",
RpcExceptionCode()));
Status = MapRpcExceptionToCR(RpcExceptionCode());
}
RpcEndExcept
Clean0:
NOTHING;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = CR_FAILURE;
}
return Status;
} // CMP_GetServerSideDeviceInstallFlags
//-------------------------------------------------------------------
// Local Stubs
//-------------------------------------------------------------------
WORD
CM_Get_Version(
VOID
)
{
return CM_Get_Version_Ex(NULL);
}
BOOL
CM_Is_Version_Available(
IN WORD wVersion
)
{
return CM_Is_Version_Available_Ex(wVersion, NULL);
}
CONFIGRET
CM_Get_Global_State(
OUT PULONG pulState,
IN ULONG ulFlags
)
{
return CM_Get_Global_State_Ex(pulState, ulFlags, NULL);
}
CONFIGRET
CM_Query_Arbitrator_Free_Data(
OUT PVOID pData,
IN ULONG DataLen,
IN DEVINST dnDevInst,
IN RESOURCEID ResourceID,
IN ULONG ulFlags
)
{
return CM_Query_Arbitrator_Free_Data_Ex(pData, DataLen, dnDevInst,
ResourceID, ulFlags, NULL);
}
CONFIGRET
CM_Query_Arbitrator_Free_Size(
OUT PULONG pulSize,
IN DEVINST dnDevInst,
IN RESOURCEID ResourceID,
IN ULONG ulFlags
)
{
return CM_Query_Arbitrator_Free_Size_Ex(pulSize, dnDevInst, ResourceID,
ulFlags, NULL);
}
CONFIGRET
CM_Run_Detection(
IN ULONG ulFlags
)
{
return CM_Run_Detection_Ex(ulFlags, NULL);
}
//-------------------------------------------------------------------
// ANSI Stubs
//-------------------------------------------------------------------
CONFIGRET
CM_Connect_MachineA(
IN PCSTR UNCServerName,
OUT PHMACHINE phMachine
)
{
CONFIGRET Status = CR_SUCCESS;
PWSTR pUniName = NULL;
if (UNCServerName == NULL ||
*UNCServerName == 0x0) {
//
// no explicit name specified, so assume local machine and
// nothing to translate
//
Status = CM_Connect_MachineW(pUniName,
phMachine);
} else if (pSetupCaptureAndConvertAnsiArg(UNCServerName, &pUniName) == NO_ERROR) {
Status = CM_Connect_MachineW(pUniName,
phMachine);
pSetupFree(pUniName);
} else {
Status = CR_INVALID_DATA;
}
return Status;
} // CM_Connect_MachineA