mirror of https://github.com/tongzx/nt5src
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.
456 lines
14 KiB
456 lines
14 KiB
/***************************************************************************************************
|
|
**
|
|
** MODULE:
|
|
**
|
|
**
|
|
** DESCRIPTION:
|
|
**
|
|
**
|
|
** AUTHOR: Daniel Dean.
|
|
**
|
|
**
|
|
**
|
|
** CREATED:
|
|
**
|
|
**
|
|
**
|
|
**
|
|
** (C) C O P Y R I G H T D A N I E L D E A N 1 9 9 6.
|
|
***************************************************************************************************/
|
|
#include <WINDOWS.H>
|
|
#include <string.h> // for strncmp() and wcstrok()
|
|
#include <crtdbg.h>
|
|
#include <hidsdi.h> // HID parsing library
|
|
#include <hidusage.h>
|
|
#include <HID.H>
|
|
#include "public.h"
|
|
#include "CLASS.H"
|
|
#include "IOCTL.H"
|
|
|
|
|
|
PWSTR wcGetNullDelimitedItemFromList( PWSTR pszzList );
|
|
|
|
PWSTR UnicodeString = L"This is Unicode\0Dis is more\0\0";
|
|
|
|
char szFrame[] = "HIDMON frame"; // Class name for "frame" window
|
|
char szChild[] = "HIDMON child"; // Class name for MDI window
|
|
|
|
|
|
|
|
/****************
|
|
TESTING!!!!!!!
|
|
****************/
|
|
typedef char* PGUID;
|
|
|
|
NTSTATUS
|
|
IoGetDeviceClassAssociations(
|
|
IN PGUID ClassGuid,
|
|
OUT PWSTR *SymbolicLinkList
|
|
);
|
|
|
|
/****
|
|
NTSTATUS
|
|
IoGetDeviceClassAssociations(
|
|
IN PGUID ClassGuid,
|
|
OUT PWSTR *SymbolicLinkList
|
|
)
|
|
{
|
|
|
|
*SymbolicLinkList = UnicodeString;
|
|
return TRUE;
|
|
}
|
|
****/
|
|
/***
|
|
BOOLEAN
|
|
HidD_GetGuidString (
|
|
OUT PCHAR * GuidClassInputString
|
|
)
|
|
{ return TRUE; }
|
|
***/
|
|
|
|
/***************************************************************************************************
|
|
**
|
|
** InitializeApplication.
|
|
**
|
|
** DESCRIPTION: Sets up the class data structures and does a one-time,
|
|
** initialization of the app by registering the window classes
|
|
**
|
|
** PARAMETERS:
|
|
**
|
|
** RETURNS: TRUE if successful else FALSE.
|
|
**
|
|
***************************************************************************************************/
|
|
ULONG InitializeApplication(VOID)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
|
|
// Register the frame class
|
|
wc.style = CS_DBLCLKS;
|
|
wc.lpfnWndProc = HIDFrameWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInst;
|
|
wc.hIcon = LoadIcon(hInst, IDHIDFRAME);
|
|
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE+1);
|
|
wc.lpszMenuName = IDHIDMENU;
|
|
wc.lpszClassName = szFrame;
|
|
|
|
if(RegisterClass(&wc))
|
|
{
|
|
// Register the MDI child class
|
|
wc.lpfnWndProc = HIDMDIChildWndProc;
|
|
wc.hIcon = LoadIcon(hInst,IDHIDCHILD);
|
|
wc.lpszMenuName = NULL;
|
|
wc.cbWndExtra = CBWNDEXTRA;
|
|
wc.lpszClassName = szChild;
|
|
|
|
if(RegisterClass(&wc))
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************************************
|
|
**
|
|
** InitializeInstance.
|
|
**
|
|
** DESCRIPTION: Performs a per-instance initialization of HIDMDI. It
|
|
** also creates the frame and one MDI child window.
|
|
**
|
|
** PARAMETERS:
|
|
**
|
|
** RETURNS: TRUE if successful else FALSE.
|
|
**
|
|
***************************************************************************************************/
|
|
ULONG InitializeInstance(LPSTR lpCmdLine, INT WindowState)
|
|
{
|
|
extern HWND hWndMDIClient;
|
|
CHAR sz[80];
|
|
|
|
// Get the base window title
|
|
LoadString (hInst, IDS_APPNAME, sz, sizeof(sz));
|
|
|
|
// Create the frame
|
|
// MDI Client window is created in frame's WM_CREATE case
|
|
hWndFrame = CreateWindow(szFrame,
|
|
sz,
|
|
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
|
|
CW_USEDEFAULT,
|
|
0,
|
|
CW_USEDEFAULT,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
hInst,
|
|
NULL);
|
|
|
|
if(hWndFrame && hWndMDIClient)
|
|
{
|
|
// Display the frame window
|
|
ShowWindow (hWndFrame, WindowState);
|
|
UpdateWindow (hWndFrame);
|
|
// Open all the Class device objects
|
|
OpenClassObjects();
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
/***************************************************************************************************
|
|
**
|
|
** OpenClassObjects.
|
|
**
|
|
** DESCRIPTION: Creates a new MDI child window.
|
|
**
|
|
** PARAMETERS:
|
|
**
|
|
** RETURNS: TRUE if successful else FALSE.
|
|
**
|
|
***************************************************************************************************/
|
|
#define MAX_DEVICE_NAME_LEN 255
|
|
|
|
VOID OpenClassObjects(VOID)
|
|
{
|
|
HANDLE hDevice,hGetDeviceClassDriver;
|
|
BOOL rc;
|
|
//PWSTR pwszDeviceList; // UNICODE strings
|
|
WORD wszDeviceList[1024];
|
|
PWSTR pwszDeviceName;
|
|
PCHAR pszGUID;
|
|
char pszDeviceName[MAX_DEVICE_NAME_LEN];
|
|
char pszHumanName[MAX_DEVICE_NAME_LEN];
|
|
DWORD dwReturn;
|
|
|
|
if( 1 )//rc = HidD_GetGuidString( &pszGUID ) )
|
|
{
|
|
//
|
|
// If we got a GUID string, retrieve a list of null terminated device
|
|
// name UNICODE strings similar to \\.\Device. This list is terminated
|
|
// by a double NULL
|
|
//rc = IoGetDeviceClassAssociations(pszGUID,&pwszDeviceList);
|
|
|
|
hGetDeviceClassDriver = CreateFile(TEST_DEVICE,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
if( hGetDeviceClassDriver != INVALID_HANDLE_VALUE)
|
|
rc = DeviceIoControl(hGetDeviceClassDriver,
|
|
IOCTL_GET_DEVICE_CLASS_ASSOC,
|
|
NULL,
|
|
0,
|
|
wszDeviceList,
|
|
1024*2,
|
|
&dwReturn,
|
|
NULL);
|
|
else
|
|
MessageBox(NULL,"Failed to load Test driver TEST.SYS","Error",MB_OK);
|
|
|
|
CloseHandle(hGetDeviceClassDriver);
|
|
|
|
pwszDeviceName = wcGetNullDelimitedItemFromList( wszDeviceList );
|
|
do{
|
|
|
|
// Convert the device name to ANSI
|
|
WideCharToMultiByte( CP_ACP, // ANSI Code Page
|
|
0, // No flags
|
|
pwszDeviceName, // UNICODE string
|
|
-1, // String is NULL terminated
|
|
pszDeviceName, // ANSI string
|
|
MAX_DEVICE_NAME_LEN, // Lenght of ANSI string buffer
|
|
NULL, // No default character
|
|
NULL );
|
|
|
|
// Open the Class device
|
|
hDevice = CreateFile(pszDeviceName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
if(hDevice != INVALID_HANDLE_VALUE )
|
|
{
|
|
// Turn our DeviceName into a Human Readable name
|
|
GetDeviceDescription(pszDeviceName, pszHumanName);
|
|
// Create the window
|
|
MakeNewChild(pszHumanName, hDevice);
|
|
}
|
|
else
|
|
MessageBox(NULL,"CreateFile(pszDeviceName) failed","Get On The Bus!",MB_OK);
|
|
|
|
// Get the next device name
|
|
}while( pwszDeviceName = wcGetNullDelimitedItemFromList( NULL ) ); //wcstok(NULL,L"\0") );
|
|
|
|
// TESTING!!!! remove comments from free()
|
|
// Remember to free the GUID string memory
|
|
//free(pszGUID);
|
|
}
|
|
|
|
|
|
}
|
|
/***************************************************************************************************
|
|
**
|
|
** GetDeviceDescription( char *pszDevice, char *pszName)
|
|
**
|
|
** DESCRIPTION: Given DeviceName string as returned from IoGetDeviceClassAssociations,
|
|
** place a NULL terminated string retrieved from HKLM\Enum\USB(...)\DeviceDescription
|
|
** in pszName
|
|
**
|
|
** PARAMETERS: char* pszDevice - Pointer to an ANSII string returned from IoGetDeviceClassAssociations
|
|
** char* pszName - Pointer to string to return name of device in
|
|
**
|
|
** RETURNS: void
|
|
**
|
|
***************************************************************************************************/
|
|
void GetDeviceDescription(char *pszDevice, char *pszName)
|
|
{
|
|
HKEY hkReg;
|
|
LONG rc;
|
|
LONG BytesWritten=MAX_DEVICE_NAME_LEN;
|
|
char *head;
|
|
char szRegPath[MAX_DEVICE_NAME_LEN];
|
|
head = pszDevice;
|
|
|
|
// first whack off the \\.\USB#
|
|
while( *head++ != '#' );
|
|
pszDevice = head;
|
|
// then replace all instances of # with \
|
|
|
|
while( *head )
|
|
{
|
|
if( *head == '#' )
|
|
*head = '\\';
|
|
|
|
head++;
|
|
|
|
}
|
|
|
|
// now, whack off the GUID string (begins with a { ) and preceding \
|
|
head = pszDevice;
|
|
while( *head != '{' )
|
|
head++;
|
|
// null terminate it
|
|
*--head = '\0';
|
|
|
|
// Create our registry path
|
|
wsprintf(szRegPath,"ENUM\\USB\\%s",pszDevice);
|
|
// open up the Reg and get our human readable name
|
|
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,szRegPath,0,KEY_ALL_ACCESS,&hkReg);
|
|
|
|
if( rc == ERROR_SUCCESS )
|
|
{
|
|
// add on the Named value we are looking for
|
|
rc = RegQueryValueEx(hkReg,"DeviceDesc",0,NULL,pszName,&BytesWritten);
|
|
RegCloseKey(hkReg);
|
|
}
|
|
|
|
|
|
}
|
|
/***************************************************************************************************
|
|
**
|
|
** wcGetNullDelimitedItemFromList( PWSTR pszzList)
|
|
**
|
|
** DESCRIPTION: Given a list of NULL terminated strings with the last member being a
|
|
** double NULL, will return the next string in the list. Operation is similar
|
|
** to strtok(): the first time the function is called, a valid list must be passed,
|
|
** there after to retrieve member strings, pass NULL in the pszzList param.
|
|
**
|
|
** PARAMETERS: PWSTR pszzList - Pointer to a UNICODE double null terminated list of
|
|
** NULL terminated strings.
|
|
**
|
|
**
|
|
** RETURNS: PWSTR Pointer to the next member of the list or NULL if at end of list.
|
|
**
|
|
***************************************************************************************************/
|
|
PWSTR wcGetNullDelimitedItemFromList( PWSTR pszzList )
|
|
{
|
|
static PWSTR CurrentMember=NULL; // Current pointer into the list
|
|
PWSTR tmp;
|
|
|
|
//
|
|
// Make sure pszzList is not NULL the first time in
|
|
if( !pszzList && !CurrentMember )
|
|
return NULL;
|
|
|
|
//
|
|
// If pszzList is not NULL, we are starting from scratch
|
|
if( pszzList )
|
|
CurrentMember = pszzList;
|
|
//
|
|
// If we have 2 NULL's then we are at the end of the list
|
|
if( (*CurrentMember == L'\0') && (*(CurrentMember+1) == L'\0') )
|
|
{
|
|
CurrentMember=NULL;
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
// Save a pointer to the current member
|
|
tmp = CurrentMember;
|
|
// Incriment to the next member
|
|
while( *CurrentMember++ );
|
|
// Return the current member
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************************************
|
|
**
|
|
** MakeNewChild.
|
|
**
|
|
** DESCRIPTION: Creates a new MDI child window.
|
|
**
|
|
** PARAMETERS:
|
|
**
|
|
** RETURNS: TRUE if successful else FALSE.
|
|
**
|
|
***************************************************************************************************/
|
|
|
|
/*
|
|
BOOLEAN __stdcall
|
|
HidD_MyGetPreparsedData (
|
|
IN HANDLE HidDeviceObject,
|
|
OUT PHIDP_PREPARSED_DATA * PreparsedData
|
|
);
|
|
*/
|
|
|
|
|
|
|
|
|
|
HWND MakeNewChild(char *pName, HANDLE hDevice)
|
|
{
|
|
HWND hWnd = 0;
|
|
MDICREATESTRUCT mcs;
|
|
PCHILD_INFO pChildInfo;
|
|
PHIDP_PREPARSED_DATA hidPreParsedData;
|
|
DWORD err;
|
|
|
|
NTSTATUS rc;
|
|
|
|
if(pName)
|
|
{
|
|
mcs.szTitle = (LPSTR)pName; // Fully qualified pathname
|
|
mcs.szClass = szChild;
|
|
mcs.hOwner = hInst;
|
|
mcs.x = mcs.cx = CW_USEDEFAULT; // Use the default size for the window
|
|
mcs.y = mcs.cy = CW_USEDEFAULT;
|
|
mcs.style = styleDefault; // Set the style DWORD of the window to default
|
|
|
|
// tell the MDI Client to create the child
|
|
hWnd = (HWND)SendMessage(hWndMDIClient,
|
|
WM_MDICREATE,
|
|
0,
|
|
(LONG)(LPMDICREATESTRUCT)&mcs);
|
|
if(hWnd)
|
|
{
|
|
|
|
//
|
|
// Create and fill in a device info struct for this window
|
|
|
|
pChildInfo = (PCHILD_INFO) GlobalAlloc(GPTR,sizeof(CHILD_INFO));
|
|
pChildInfo->hidCaps = (PHIDP_CAPS) GlobalAlloc(GPTR,sizeof(HIDP_CAPS));
|
|
|
|
// rc = HidD_MyGetPreparsedData( hDevice,&pChildInfo->hidPPData );
|
|
rc = HidD_GetPreparsedData( hDevice,&pChildInfo->hidPPData );
|
|
if( !rc )
|
|
err = GetLastError();
|
|
// Get a pointer to this devices capabilities
|
|
rc = HidP_GetCaps( pChildInfo->hidPPData, pChildInfo->hidCaps );
|
|
|
|
// Allocate space for and get a list of Value channel descriptions for this device
|
|
pChildInfo->pValueCaps = (PHIDP_VALUE_CAPS) GlobalAlloc(GPTR,pChildInfo->hidCaps->NumberInputValueCaps*sizeof(HIDP_VALUE_CAPS));
|
|
pChildInfo->NumValues = pChildInfo->hidCaps->NumberInputValueCaps;
|
|
rc = HidP_GetValueCaps( HidP_Input,
|
|
pChildInfo->pValueCaps,
|
|
&pChildInfo->NumValues,
|
|
pChildInfo->hidPPData
|
|
);
|
|
|
|
// Allocate space for and get a list of Button channel descriptions for this device
|
|
pChildInfo->pButtonCaps = (PHIDP_BUTTON_CAPS) GlobalAlloc(GPTR,pChildInfo->hidCaps->NumberInputButtonCaps*sizeof(HIDP_BUTTON_CAPS));
|
|
pChildInfo->NumButtons = pChildInfo->hidCaps->NumberInputButtonCaps;
|
|
rc = HidP_GetButtonCaps(HidP_Input,
|
|
pChildInfo->pButtonCaps,
|
|
&pChildInfo->NumButtons,
|
|
pChildInfo->hidPPData
|
|
);
|
|
|
|
|
|
// Save the info!
|
|
SetDeviceInfo(hWnd, pChildInfo);
|
|
SetDeviceHandle(hWnd, hDevice);
|
|
ShowWindow(hWnd, SW_SHOW);
|
|
|
|
//TESTING!!
|
|
//IOCTLRead(hWnd);
|
|
}
|
|
}
|
|
return hWnd;
|
|
}
|
|
|