Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

331 lines
11 KiB

//*********************************************************************
//* Microsoft Windows **
//* Copyright(c) Microsoft Corp., 1999 **
//*********************************************************************
//
// usbHwChk.CPP - Implementation of USB Keyboard and Mouse checking
//
// HISTORY:
//
// 8/20/99 vyung Created.
//
#include "msobcomm.h"
#include <setupapi.h>
#include <cfgmgr32.h>
#include <devguid.h>
#include <util.h>
#define ENUM_SUCCESS 0
#define ENUM_GENFAILURE 4
#define ENUM_CHILDFAILURE 2
#define ENUM_SIBLINGFAILURE 1
#define DEVICETYPE_MOUSE L"Mouse"
#define DEVICETYPE_KEYBOARD L"keyboard"
// BUGBUG: should be defined by sdk\inc\devguid.h
#ifndef GUID_DEVCLASS_USB
DEFINE_GUID( GUID_DEVCLASS_USB, 0x36fc9e60L, 0xc465, 0x11cf, 0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 );
#endif
// Function prototypes for cfgmgr32.dll
typedef CMAPI
CONFIGRET
(WINAPI*
PFNCMGETCHILD)(
OUT PDEVINST pdnDevInst,
IN DEVINST dnDevInst,
IN ULONG ulFlags
);
typedef CMAPI
CONFIGRET
(WINAPI*
PFCMGETSIBLING)(
OUT PDEVINST pdnDevInst,
IN DEVINST DevInst,
IN ULONG ulFlags
);
typedef CMAPI
#if defined(_REMOVE_) // looks like a typo
CMAPI
#endif // _REMOVE_
CONFIGRET
(WINAPI*
PFCMGETDEVNODEREGISTRYPROPERTYA)(
IN DEVINST dnDevInst,
IN ULONG ulProperty,
OUT PULONG pulRegDataType, OPTIONAL
OUT PVOID Buffer, OPTIONAL
IN OUT PULONG pulLength,
IN ULONG ulFlags
);
BOOL g_bKeyboard = FALSE;
BOOL g_bMouse = FALSE;
/***************************************************************************
Function: ProcessDevNode
Retrieve each DevNode in the system and checks for keyboard and mouse
***************************************************************************/
void ProcessDevNode(DEVNODE dnDevNode, FARPROC pfGetDevNodeProp)
{
//
// We have gotten a child or a sibling. Get the class of device.
//
WCHAR buf[512];
DWORD len = 0;
len = MAX_CHARS_IN_BUFFER(buf);// BUGBUG: look up params to GetDevNodeProp
DWORD cr = ((PFCMGETDEVNODEREGISTRYPROPERTYA)pfGetDevNodeProp)(dnDevNode,
CM_DRP_CLASS, // Or CM_DRP_CLASSGUID
NULL,
buf,
&len,
0);
//
// Does it match the keyboard class or the mouse class?
// If so, set that variable and continue.
//
if(0 == lstrcmpi((LPCWSTR)buf, DEVICETYPE_KEYBOARD))
{
g_bKeyboard = TRUE;
}
if(0 == lstrcmp((LPCWSTR)buf, DEVICETYPE_MOUSE))
{
g_bMouse = TRUE;
}
}
/***************************************************************************
Function: EnumerateDevices
Used to walk through every DevNode in the system and retrieve it's resources
in the registry
***************************************************************************/
long EnumerateDevices(DEVNODE dnDevNodeTraverse,
int j,
DEVNODE dnParentNode,
FARPROC pfGetChild,
FARPROC pfGetSibling,
FARPROC pfGetDevNodeProp)
{
DEVNODE dnDevNodeMe;
DEVNODE dnDevNodeSibling;
DEVNODE dnDevNodeChild;
CONFIGRET cr;
static long lError;
dnDevNodeMe = dnDevNodeTraverse;
while( TRUE )
{
cr = ((PFNCMGETCHILD)pfGetChild)(&dnDevNodeChild, dnDevNodeMe, 0);
switch(cr)
{
case CR_SUCCESS:
//Write new node, as a branch or root
ProcessDevNode(dnDevNodeMe, pfGetDevNodeProp);
//Pass up failure
lError = EnumerateDevices(dnDevNodeChild, 0, dnDevNodeMe, pfGetChild, pfGetSibling, pfGetDevNodeProp);
if ( lError != ENUM_SUCCESS )
return lError;
break;
//No children, I am a bottom branch!
case CR_NO_SUCH_DEVNODE:
// This is ok too. If just means the the call couldn't find
// either a sibling or a child.
// Write new node, as a leaf
ProcessDevNode(dnDevNodeMe, pfGetDevNodeProp);
break;
//We puked on something, return code of 3 will end entire traversal
default:
return ENUM_CHILDFAILURE;
}
//Get next sibling, repeat
cr = ((PFCMGETSIBLING)pfGetSibling)(&dnDevNodeSibling, dnDevNodeMe, 0);
switch(cr)
{
case CR_SUCCESS:
dnDevNodeMe = dnDevNodeSibling; // I'm now the sibling
break;
case CR_NO_SUCH_DEVNODE:
return ENUM_SUCCESS; //Out of siblings...
default:
return ENUM_SIBLINGFAILURE ; //We puked on something, return code of 2 will end entire traversal
}
}
}
/***************************************************************************
Function: IsMouseOrKeyboardPresent
Used to walk through every USB DevNode in the system and check it's resources
in the registry for keyboard and mouse
***************************************************************************/
DWORD
IsMouseOrKeyboardPresent(HWND HWnd,
PBOOL pbKeyboardPresent,
PBOOL pbMousePresent)
{
SP_DEVINFO_DATA DevData;
HDEVINFO hDevInfo;
DEVNODE dnDevInst;
DWORD dwPropertyType;
BYTE* lpPropertyBuffer = NULL; //buf[MAX_PATH];
DWORD requiredSize = MAX_PATH;
DWORD dwRet = ERROR_SUCCESS;
GUID tempGuid;
int i;
memcpy(&tempGuid, &GUID_DEVCLASS_USB, sizeof(GUID));
HINSTANCE hInst = NULL;
g_bKeyboard = FALSE;
g_bMouse = FALSE;
FARPROC pfGetChild = NULL, pfGetSibling = NULL, pfGetDevNodeProp = NULL;
hInst = LoadLibrary(L"CFGMGR32.DLL");
if (hInst)
{
// Load the CM_Get_* API
pfGetChild = GetProcAddress(hInst, "CM_Get_Child");
pfGetSibling = GetProcAddress(hInst, "CM_Get_Sibling");
pfGetDevNodeProp = GetProcAddress(hInst, "CM_Get_DevNode_Registry_PropertyW");
if (pfGetChild && pfGetSibling && pfGetDevNodeProp)
{
lpPropertyBuffer = new BYTE[requiredSize];
if ( ! lpPropertyBuffer ) {
dwRet = ERROR_NOT_ENOUGH_MEMORY;
goto IsMouseOrKeyboardPresentError;
}
hDevInfo = SetupDiGetClassDevs(&tempGuid,
NULL,
HWnd,
DIGCF_PRESENT);
//Set the size of DevData
DevData.cbSize = sizeof(DevData);
for (i = 0;
SetupDiEnumDeviceInfo(hDevInfo, i, &DevData);
i++)
{
if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
&DevData,
SPDRP_HARDWAREID,
(PDWORD)&dwPropertyType,
lpPropertyBuffer,
requiredSize,
&requiredSize))
{
dwRet = GetLastError();
if (dwRet == ERROR_INSUFFICIENT_BUFFER) {
//
// Allocate an appropriate size buffer and call
// SetupDiGetDeviceRegistryProperty again to get
// the hardware ids.
//
dwRet = ERROR_SUCCESS;
delete [] lpPropertyBuffer;
lpPropertyBuffer = new BYTE[requiredSize];
if ( ! lpPropertyBuffer ) {
dwRet = ERROR_NOT_ENOUGH_MEMORY;
goto IsMouseOrKeyboardPresentError;
}
if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
&DevData,
SPDRP_HARDWAREID,
(PDWORD)&dwPropertyType,
lpPropertyBuffer,
requiredSize,
&requiredSize))
{
dwRet = GetLastError();
goto IsMouseOrKeyboardPresentError;
}
} else {
goto IsMouseOrKeyboardPresentError;
}
}
//
// We've now got the hardware ids.
// Using your best string compare code for MULTI_SZ strings,
// Find out if one of the ids is "USB\ROOT_HUB"
//
// if (one of the ids is not "USB\ROOT_HUB") {
// continue;
// }
//
if(0 != wmemcmp( (LPCWSTR)lpPropertyBuffer, L"USB", MAX_CHARS_IN_BUFFER(L"USB") ))
{
continue;
}
dnDevInst = DevData.DevInst;
//
// One of the ids is USB\ROOT_HUB.
// Time to search for a keyboard or a mouse!
// Use the following two apis to search through the tree underneath
// the root hub to find devnodes. I haven't included this search code,
// but I'm sure you can be creative and use a depth or breadth algorithm
// of some sort. When you're done, break out of the loop.
//
if (ENUM_SUCCESS != EnumerateDevices(dnDevInst, 2, 0, pfGetChild, pfGetSibling, pfGetDevNodeProp))
{
dwRet = GetLastError();
TRACE1( L"EnumerateDevices failed. Error = %d", dwRet);
}
}
}
else
{
dwRet = GetLastError();
}
}
else
{
dwRet = GetLastError();
}
MYASSERT( dwRet == ERROR_SUCCESS );
IsMouseOrKeyboardPresentError:
if (hInst) {
FreeLibrary(hInst);
hInst = NULL;
}
if (lpPropertyBuffer) {
delete [] lpPropertyBuffer;
lpPropertyBuffer = NULL;
}
*pbKeyboardPresent = g_bKeyboard;
*pbMousePresent = g_bMouse;
return dwRet;
}