InputApc()函数是如何调用ProcessKeyboardInput()函数的?

InputApc()函数是如何调用ProcessKeyboardInput()函数的?

下面是调用栈,这篇文章是解释第五行到第四行的。

.//ntuser/kernel/ntinput.c:2601:VOID xxxKeyEvent(

.//windows/core/ntuser/kernel/ntinput.c:4664:VOID xxxProcessKeyEvent(

.//core/ntuser/kernel/ntinput.c:58:VOID ProcessKeyboardInputWorker(PKEYBOARD_INPUT_DATA pkei,

.//core/ntuser/kernel/ntinput.c:4608:VOID ProcessKeyboardInput(PDEVICEINFO pDeviceInfo)

.//windows/core/ntuser/kernel/ntinput.c:2032:VOID NTAPI InputApc(

第一部分:userk.h

第一部分A

typedef struct tagKEYBOARD_DEVICE_INFO { // DEVICE_TYPE_KEYBOARD

KEYBOARD_ATTRIBUTES Attr;

KEYBOARD_ID_EX IdEx;

KEYBOARD_INPUT_DATA Data[MAXIMUM_ITEMS_READ];

} KEYBOARD_DEVICE_INFO, *PKEYBOARD_DEVICE_INFO;

第一部分B

typedef struct tagGENERIC_DEVICE_INFO {

#ifdef GENERIC_INPUT

HEAD head;

#endif

struct tagDEVICEINFO *pNext;

BYTE type;

BYTE bFlags;

USHORT usActions;

BYTE nRetryRead;

UNICODE_STRING ustrName;

HANDLE handle;

PVOID NotificationEntry;

PKEVENT pkeHidChangeCompleted; // wake RequestDeviceChange()

IO_STATUS_BLOCK iosb;

NTSTATUS ReadStatus;

#ifdef DIAGNOSE_IO

HANDLE OpenerProcess;

NTSTATUS OpenStatus;

NTSTATUS AttrStatus;

ULONG timeStartRead; // tick before ZwReadFile

ULONG timeEndRead; // tick after ZwReadFile

int nReadsOutstanding; // ZwReadFile ++, consume data --

#endif

#ifdef PRERELEASE

UINT fForcedDetach : 1; // Set if the device is forced detached from TS

#endif

} GENERIC_DEVICE_INFO, *PGENERIC_DEVICE_INFO;

第一部分C

// valuse for GENERIC_DEVICE_INFO.type

#define DEVICE_TYPE_MOUSE 0

#define DEVICE_TYPE_KEYBOARD 1

#ifdef GENERIC_INPUT

#define DEVICE_TYPE_HID 2

#define DEVICE_TYPE_MAX 2

#else

#define DEVICE_TYPE_MAX 1

#endif

第一部分D

typedef struct tagDEVICEINFO {

GENERIC_DEVICE_INFO;

union {

MOUSE_DEVICE_INFO mouse;

KEYBOARD_DEVICE_INFO keyboard;

#ifdef GENERIC_INPUT

HID_DEVICE_INFO hid;

#endif

};

} DEVICEINFO, *PDEVICEINFO;

第一部分E

typedef struct tagDEVICE_TEMPLATE {

SIZE_T cbDeviceInfo; // bytes to allocate for DEVICEINFO

const GUID *pClassGUID; // GUID of the class

UINT uiRegistrySection; // Parameters for class (HKLM\SYSTEM\CurrentControlSet\Services\*\Parameters)

LPWSTR pwszClassName; // Class name (eg: L"mouclass")

LPWSTR pwszDefDevName; // Default Device Name

LPWSTR pwszLegacyDevName; // Legacy Device Name (eg: "PointerClassLegacy0")

ULONG IOCTL_Attr; // IOCTL_*_QUERY_ATTRIBUTES

UINT offAttr; // offset of *_ATTRIBUTES struct within DEVICEINFO

ULONG cbAttr; // sizeof *_ATTRIBUTES struct

UINT offData; // offset of *_INPUT_DATA buffer within DEVICEINFO

ULONG cbData; // sizeof *_INPUT_DATA buffer

VOID (*DeviceRead)(PDEVICEINFO); // routine to read the device

PKEVENT pkeHidChange; // event to signal changes to this sort of device

#ifdef GENERIC_INPUT

DWORD dwFlags; // Flags...

#endif

} DEVICE_TEMPLATE, *PDEVICE_TEMPLATE;

第二部分:pnp.c

DEVICE_TEMPLATE aDeviceTemplate[DEVICE_TYPE_MAX + 1] = {

// DEVICE_TYPE_MOUSE

{

sizeof(GENERIC_DEVICE_INFO)+sizeof(MOUSE_DEVICE_INFO), // cbDeviceInfo

&GUID_CLASS_MOUSE, // pClassGUID

PMAP_MOUCLASS_PARAMS, // uiRegistrySection

L"mouclass", // pwszClassName

DD_MOUSE_DEVICE_NAME_U L"0", // pwszDefDevName

DD_MOUSE_DEVICE_NAME_U L"Legacy0", // pwszLegacyDevName

IOCTL_MOUSE_QUERY_ATTRIBUTES, // IOCTL_Attr

FIELD_OFFSET(DEVICEINFO, mouse.Attr), // offAttr

sizeof((PDEVICEINFO)NULL)->mouse.Attr, // cbAttr

FIELD_OFFSET(DEVICEINFO, mouse.Data), // offData

sizeof((PDEVICEINFO)NULL)->mouse.Data, // cbData

ProcessMouseInput, // Reader routine

NULL // pkeHidChange

},

// DEVICE_TYPE_KEYBOARD

{

sizeof(GENERIC_DEVICE_INFO)+sizeof(KEYBOARD_DEVICE_INFO), // cbDeviceInfo

&GUID_CLASS_KEYBOARD, // pClassGUID

PMAP_KBDCLASS_PARAMS, // uiRegistrySection

L"kbdclass", // pwszClassName

DD_KEYBOARD_DEVICE_NAME_U L"0", // pwszDefDevName

DD_KEYBOARD_DEVICE_NAME_U L"Legacy0", // pwszLegacyDevName

IOCTL_KEYBOARD_QUERY_ATTRIBUTES, // IOCTL_Attr

FIELD_OFFSET(DEVICEINFO, keyboard.Attr), // offAttr

sizeof((PDEVICEINFO)NULL)->keyboard.Attr, // cbAttr

FIELD_OFFSET(DEVICEINFO, keyboard.Data), // offData

sizeof((PDEVICEINFO)NULL)->keyboard.Data, // cbData

ProcessKeyboardInput, // Reader routine

NULL // pkeHidChange

},

#ifdef GENERIC_INPUT

// DEVICE_TYPE_HID

{

sizeof(GENERIC_DEVICE_INFO)+sizeof(HID_DEVICE_INFO), // cbDeviceInfo

&GUID_CLASS_INPUT, // pClassGUID

0, // uiRegistrySection. LATER: add real one

L"hid", // pwszClassName

L"", // pwszDefDevName

L"", // pwszLegacyDevName

0, // IOCTL_ATTR

0, // offAttr

0, // cbAttr

0, // offData

0, // cbData

ProcessHidInput, // Reader routine

NULL, // pkeHidChange,

DT_HID, // dwFlags

},

#endif

// Add new input device type template here

};

第三部分:ntinput.c

PDEVICE_TEMPLATE pDevTpl = &aDeviceTemplate[pDeviceInfo->type];

对于键盘来说,pDeviceInfo->type等于1,

pDevTpl->DeviceRead 指针为函数指针ProcessKeyboardInput()

VOID NTAPI InputApc(

IN PVOID ApcContext,

IN PIO_STATUS_BLOCK IoStatusBlock,

IN ULONG Reserved

)

{

PDEVICEINFO pDeviceInfo = (PDEVICEINFO)ApcContext;

UNREFERENCED_PARAMETER(Reserved);

/*

* Check if the RIT is being terminated.

* If we hit this assertion, the RIT was killed by someone inadvertently.

* Not much can be done if it once happens.

*/

UserAssert(gptiRit);

UserAssert((gptiRit->TIF_flags & TIF_INCLEANUP) == 0);

#ifdef DIAGNOSE_IO

pDeviceInfo->nReadsOutstanding--;

#endif

/*

* If this device needs freeing, abandon reading now and request the free.

* (Don't even process the input that we received in this APC)

*/

if (pDeviceInfo->usActions & GDIAF_FREEME) {

#ifdef GENERIC_INPUT

CheckCritOut();

EnterCrit();

#endif

EnterDeviceInfoListCrit();

pDeviceInfo->bFlags &= ~GDIF_READING;

FreeDeviceInfo(pDeviceInfo);

LeaveDeviceInfoListCrit();

#ifdef GENERIC_INPUT

LeaveCrit();

#endif

return;

}

if (NT_SUCCESS(IoStatusBlock->Status) && pDeviceInfo->handle) {

PDEVICE_TEMPLATE pDevTpl = &aDeviceTemplate[pDeviceInfo->type];

pDevTpl->DeviceRead(pDeviceInfo);

}

if (IsRemoteConnection()) {

PoSetSystemState(ES_SYSTEM_REQUIRED);

}

StartDeviceRead(pDeviceInfo);

}