阅读:1162回复:2
如何在驱动和app之间同步
如何使用事件在驱动和APP之间同步?
|
|
沙发#
发布于:2004-12-12 18:58
Figure 1 Using Asynchronous Capabilities
Async.c /* Async.c - 1999 James M. Finnegan - Microsoft Systems Journal This module sends various requests the associated kernel-mode driver to instruct the driver to trigger KM to user-mode notification mechanisms. */ #include <windows.h> #include <winioctl.h> #define FILE_DEVICE_UNKNOWN 0x00000022 #define IOCTL_UNKNOWN_BASE FILE_DEVICE_UNKNOWN #define IOCTL_NOTIFY_KERNEL_EVENT CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0800, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NOTIFY_USER_EVENT CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0801, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NOTIFY_EMPTY_IRP CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0802, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NOTIFY_REGISTER_APC CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NOTIFY_REGISTER_APC_WITH_KM_ALERTING \ CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0804, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) extern HANDLE hDriver; BOOL WINAPI KernelModeEvent(DWORD t) { HANDLE KnotifyEvent; DWORD dwBytesReturned; BOOL bReturnCode = FALSE; OVERLAPPED ov={0}; // Create an event handle for async notification // from our driver ov.hEvent = CreateEvent(NULL, // Default security TRUE, // Manual reset FALSE, // non-signaled state NULL); // No name // Tell the driver to signal its event... bReturnCode = DeviceIoControl(hDriver, IOCTL_NOTIFY_KERNEL_EVENT, 0, 0, 0, 0, &dwBytesReturned, &ov); // Wait here for the event handle to be set, indicating // that the IOCTL processing is complete. bReturnCode = GetOverlappedResult(hDriver, &ov, &dwBytesReturned, TRUE); CloseHandle(ov.hEvent); // Get a handle to the named kernel event and wait on it! KnotifyEvent = OpenEvent(SYNCHRONIZE, FALSE, "KnotifyEvent"); WaitForSingleObject(KnotifyEvent, INFINITE); MessageBox(NULL,"Kernel-mode event has been signaled!","Unotify",MB_OK); return 0; } BOOL WINAPI UserModeEvent(DWORD t) { HANDLE UserModeEvent; DWORD dwBytesReturned; BOOL bReturnCode = FALSE; OVERLAPPED ov={0}; // Create an event handle that the KM driver can signal UserModeEvent = CreateEvent(NULL, // Default security TRUE, // Manual reset FALSE, // non-signaled state NULL); // No name // Create an event handle for async notification // from our driver ov.hEvent = CreateEvent(NULL, // Default security TRUE, // Manual reset FALSE, // non-signaled state NULL); // No name // Tell the driver to signal its event... bReturnCode = DeviceIoControl(hDriver, IOCTL_NOTIFY_USER_EVENT, &UserModeEvent, sizeof(HANDLE), 0, 0, &dwBytesReturned, &ov); // Wait here for the event handle to be set, indicating // that the IOCTL processing is complete. bReturnCode = GetOverlappedResult(hDriver, &ov, &dwBytesReturned, TRUE); CloseHandle(ov.hEvent); WaitForSingleObject(UserModeEvent, INFINITE); MessageBox(NULL,"User-mode event has been signaled!","Unotify",MB_OK); CloseHandle(UserModeEvent); return 0; } BOOL WINAPI EmptyIRP(DWORD t) { DWORD dwBytesReturned; BOOL bReturnCode = FALSE; OVERLAPPED ov={0}; // Create an event handle for async notification // from our driver ov.hEvent = CreateEvent(NULL, // Default security TRUE, // Manual reset FALSE, // non-signaled state NULL); // No name // Issue an empty IRP to the driver. The driver will mark it pending till // it's ready to complete it bReturnCode = DeviceIoControl(hDriver, IOCTL_NOTIFY_EMPTY_IRP, 0, 0, 0, 0, &dwBytesReturned, &ov); // Wait here for the event handle to be set, indicating // that the IOCTL processing is complete. bReturnCode = GetOverlappedResult(hDriver, &ov, &dwBytesReturned, TRUE); CloseHandle(ov.hEvent); MessageBox(NULL,"Empty IRP has been completed!","Unotify",MB_OK); return 0; } void ApcCallback(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) { char Message[80]; wsprintf(Message,"APC Callback!\n P1 == %lx\n P2 == %lx\n P3 == %lx", NormalContext, SystemArgument1, SystemArgument2); MessageBox(NULL, Message, "Unotify", MB_OK); } void ApcDispatch() { DWORD dwBytesReturned; BOOL bReturnCode = FALSE; OVERLAPPED ov={0}; DWORD pfnApc = (DWORD)&ApcCallback; // Create an event handle for async notification // from our driver ov.hEvent = CreateEvent(NULL, // Default security TRUE, // Manual reset FALSE, // non-signaled state NULL); // No name // Tell the driver to signal its event... bReturnCode = DeviceIoControl(hDriver, IOCTL_NOTIFY_REGISTER_APC, &pfnApc, sizeof(DWORD), 0, 0, &dwBytesReturned, &ov); // Wait here for the event handle to be set, indicating // that the IOCTL processing is complete. bReturnCode = GetOverlappedResult(hDriver, &ov, &dwBytesReturned, TRUE); CloseHandle(ov.hEvent); MessageBox(NULL,"APC Dispatched!","Unotify",MB_OK); // Force the thread into being alertable... SleepEx(INFINITE, TRUE); } void ApcDispatchWithKMAlertHack() { DWORD dwBytesReturned; BOOL bReturnCode = FALSE; OVERLAPPED ov={0}; DWORD pfnApc = (DWORD)&ApcCallback; // Create an event handle for async notification // from our driver ov.hEvent = CreateEvent(NULL, // Default security TRUE, // Manual reset FALSE, // non-signaled state NULL); // No name // Tell the driver to signal its event... bReturnCode = DeviceIoControl(hDriver, IOCTL_NOTIFY_REGISTER_APC_WITH_KM_ALERTING, &pfnApc, sizeof(DWORD), 0, 0, &dwBytesReturned, &ov); // Wait here for the event handle to be set, indicating // that the IOCTL processing is complete. bReturnCode = GetOverlappedResult(hDriver, &ov, &dwBytesReturned, TRUE); CloseHandle(ov.hEvent); MessageBox(NULL,"APC Dispatched! Look, no user-mode alert!","Unotify",MB_OK); } DynamIc.c /* Dynamic.c - 1998, 1999 James M. Finnegan - Microsoft Systems Journal This module implements the functionality to dynamically load and unload Windows NT drivers via the Service Control Manager. */ #include <windows.h> BOOL InstallAndStartDriver(SC_HANDLE hSCManager, LPCTSTR DriverName, LPCTSTR ServiceExe) { SC_HANDLE hService; BOOL bReturn; // Create the driver entry in the SC Manager. hService = CreateService(hSCManager, // SCManager database DriverName, // name of service DriverName, // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_KERNEL_DRIVER, // service type SERVICE_DEMAND_START, // start type SERVICE_ERROR_NORMAL, // error control type ServiceExe, // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL // no password ); // This may fail because the service entry already exists. However, // we've tried to load it earlier, so something clearly is wrong if // we can't create it! if(!hService) return FALSE; // Start the driver! bReturn = StartService(hService, 0, NULL); // Dispose of the handle... CloseServiceHandle(hService); // Return whatever the driver start returned... return bReturn; } BOOL LoadDynamicNTDriver() { SC_HANDLE hSCManager; char currentDirectory[128]; BOOL bReturn; // Open Service Control Manager on the local machine... hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); // Assume driver is in the same directory as the DLL. Hence, create // a fully qualified pathname for the SCM to add to the registry. GetCurrentDirectory(128, currentDirectory); lstrcat(currentDirectory,"\\Knotify.sys"); // Install drive in the registry and start it... bReturn = InstallAndStartDriver(hSCManager, "Knotify", currentDirectory); // Close the Service Control Manager... CloseServiceHandle(hSCManager); return bReturn; } //////////////////////////////////////////////////////////////////////////// // Unload routines //////////////////////////////////////////////////////////////////////////// BOOL UnloadDynamicNTDriver() { SC_HANDLE hSCManager; SC_HANDLE hService; SERVICE_STATUS serviceStatus; BOOL bReturn; // Open Service Control Manager on the local machine... hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); // Open the Service Control Manager for our driver service... hService = OpenService(hSCManager, "Knotify", SERVICE_ALL_ACCESS); // Stop the driver. Will return TRUE on success... bReturn = ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus); // Delete the driver from the registry... if(bReturn == TRUE) bReturn = DeleteService(hService); // Close the SC Manager CloseServiceHandle(hService); // Close Service Control Manager CloseServiceHandle(hSCManager); return bReturn; } HANDLE LoadDriver(OSVERSIONINFO *os, BOOL *fNTDynaLoaded) { HANDLE hDevice; // Default to FALSE on informing the caller if we've dynamically // loaded the Windows NT driver via the SCM. *fNTDynaLoaded = FALSE; // If we're under Windows NT... if(os->dwPlatformId == VER_PLATFORM_WIN32_NT) { // Try opening the device driver (in case it's static). // We'll deal with a failure in a moment... hDevice = CreateFile("\\\\.\\Knotify", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, // Default security OPEN_EXISTING, FILE_FLAG_OVERLAPPED, // Perform asynchronous I/O 0); // No template // If the device driver wasn't started, let's dynamically load it // here... if(hDevice == INVALID_HANDLE_VALUE) { // Load and start the driver... LoadDynamicNTDriver(); // Open the driver... hDevice = CreateFile("\\\\.\\Knotify", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, // Default security OPEN_EXISTING, FILE_FLAG_OVERLAPPED, // Perform asynchronous I/O 0); // No template // Set the global to indicate that we've Dynaloaded. This will // Cause DllMain to stop and unload on a process detach. *fNTDynaLoaded = TRUE; } return hDevice; } } Unotify.c /* Unotify.c - 1999 James M. Finnegan - Microsoft Systems Journal This is the main module for demonstrating asynchronous notification from kernel mode. */ #include <windows.h> #include <stdio.h> #include "resource.h" LRESULT WINAPI WndProc(HWND,UINT,WPARAM,LPARAM); HANDLE hDriver = INVALID_HANDLE_VALUE; // External functions in Dynamic.c extern HANDLE LoadDriver(OSVERSIONINFO *, BOOL *); extern BOOL UnloadDynamicNTDriver(); // External functions in Async.c extern BOOL WINAPI KernelModeEvent(DWORD); extern BOOL WINAPI UserModeEvent(DWORD); extern BOOL WINAPI EmptyIRP(DWORD); extern void ApcDispatch(); extern void ApcDispatchWithKMAlertHack(); int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { static char szAppName[]="UNotify"; HWND hWnd; MSG msg; WNDCLASS wndclass; if(!hPrevInstance) { wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); wndclass.lpszClassName = szAppName; if(!RegisterClass(&wndclass)) return -1; } // Create the main window hWnd = CreateWindow(szAppName,"MSJ Kernel Mode Async Notification App", WS_OVERLAPPED | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |WS_SYSMENU | WS_CLIPCHILDREN, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, 0,0,hInstance,NULL); ShowWindow(hWnd,nCmdShow); UpdateWindow(hWnd); while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } VOID CenterWindow(HWND hWnd) { RECT rect; WORD wWidth, wHeight; GetWindowRect(hWnd,&rect); wWidth =GetSystemMetrics(SM_CXSCREEN); wHeight=GetSystemMetrics(SM_CYSCREEN); MoveWindow(hWnd,(wWidth/2) - ((rect.right - rect.left)/2), (wHeight/2) - ((rect.bottom - rect.top) /2), rect.right - rect.left, rect.bottom - rect.top, FALSE); } LRESULT WINAPI WndProc(HWND hWnd,UINT uMessage,WPARAM wParam,LPARAM lParam) { static OSVERSIONINFO os={0}; static BOOL fNTDynaLoaded; HANDLE hThread; DWORD dwThread; switch(uMessage) { case WM_CREATE: CenterWindow(hWnd); // Get the current OS information. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&os); hDriver = LoadDriver(&os, &fNTDynaLoaded); break; case WM_COMMAND: switch(wParam) { case IDM_KERNEL_EVENT: if(!(hThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE) KernelModeEvent, NULL, 0, &dwThread))) MessageBox(NULL,"Cannot create thread!","Error",MB_OK); break; case IDM_USER_EVENT: if(!(hThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE) UserModeEvent, NULL, 0, &dwThread))) MessageBox(NULL,"Cannot create thread!","Error",MB_OK); break; case IDM_EMPTY_IRP: if(!(hThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE) EmptyIRP, NULL, 0, &dwThread))) MessageBox(NULL,"Cannot create thread!","Error",MB_OK); break; case IDM_APC: ApcDispatch(); break; case IDM_APC_KM_THREAD_ALERTING: ApcDispatchWithKMAlertHack(); break; case IDM_EXIT: PostMessage(hWnd, WM_CLOSE, 0, 0L); break; } break; case WM_DESTROY: CloseHandle(hDriver); // If the Windows NT driver was previously dynamically loaded, unload // it here! if(fNTDynaLoaded) UnloadDynamicNTDriver(); PostQuitMessage(0); break; default: return DefWindowProc(hWnd,uMessage,wParam,lParam); break; } return 0L; } Knotify.c /* Knotify.c - 1999 James M. Finnegan - Microsoft Systems Journal This module implements the kernel code to demonstrate notification techniques to user-mode Win32-based applications */ #include "ntddk.h" #include <stdio.h> #define FILE_DEVICE_UNKNOWN 0x00000022 #define IOCTL_UNKNOWN_BASE FILE_DEVICE_UNKNOWN #define IOCTL_NOTIFY_KERNEL_EVENT CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0800, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NOTIFY_USER_EVENT CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0801, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NOTIFY_EMPTY_IRP CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0802, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NOTIFY_REGISTER_APC CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NOTIFY_REGISTER_APC_WITH_KM_ALERTING \ CTL_CODE( IOCTL_UNKNOWN_BASE, 0x0804, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) // Definitions for Windows NT-supplied APC routines. These are exported in the // import libraries, but are not in NTDDK.H void KeInitializeApc(PKAPC Apc, PKTHREAD Thread, CCHAR ApcStateIndex, PKKERNEL_ROUTINE KernelRoutine, PKRUNDOWN_ROUTINE RundownRoutine, PKNORMAL_ROUTINE NormalRoutine, KPROCESSOR_MODE ApcMode, PVOID NormalContext); void KeInsertQueueApc(PKAPC Apc, PVOID SystemArgument1, PVOID SystemArgument2, UCHAR unknown); void KnotifyUnloadDriver(PDRIVER_OBJECT DriverObject); NTSTATUS KnotifyDispatchCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS KnotifyDispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT DeviceObject; HANDLE NotifyHandle; PKEVENT NotifyEvent; } DEVICE_EXTENSION, *PDEVICE_EXTENSION ; NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) /*++ Routine Description: This routine is called when the driver is loaded by Windows NT. Arguments: DriverObject - Pointer to driver object created by system. RegistryPath - Pointer to the name of the services node for this driver. Return Value: The function value is the final status from the initialization operation. --*/ { NTSTATUS ntStatus; UNICODE_STRING uszDriverString; UNICODE_STRING uszDeviceString; UNICODE_STRING uszNotifyEventString; PDEVICE_OBJECT pDeviceObject; PDEVICE_EXTENSION extension; // Point uszDriverString at the driver name RtlInitUnicodeString(&uszDriverString, L"\\Device\\Knotify"); // Create and initialize device object ntStatus = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &uszDriverString, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject); if(ntStatus != STATUS_SUCCESS) return ntStatus; // Assign extension variable... extension = pDeviceObject->DeviceExtension; // Point uszDeviceString at the device name RtlInitUnicodeString(&uszDeviceString, L"\\DosDevices\\Knotify"); // Create symbolic link to the user-visible name ntStatus = IoCreateSymbolicLink(&uszDeviceString, &uszDriverString); if(ntStatus != STATUS_SUCCESS) { // Delete device object if not successful IoDeleteDevice(pDeviceObject); return ntStatus; } // Load structure to point to IRP handlers... DriverObject->DriverUnload = KnotifyUnloadDriver; DriverObject->MajorFunction[IRP_MJ_CREATE] = KnotifyDispatchCreateClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = KnotifyDispatchCreateClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KnotifyDispatchIoctl; // Create event for user-mode processes to monitor RtlInitUnicodeString(&uszNotifyEventString, L"\\BaseNamedObjects\\KnotifyEvent"); extension->NotifyEvent = IoCreateNotificationEvent(&uszNotifyEventString, &extension->NotifyHandle); KeClearEvent(extension->NotifyEvent); // Return success return ntStatus; } NTSTATUS KnotifyDispatchCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information=0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return(STATUS_SUCCESS); } PWORK_QUEUE_ITEM pItem; void KSignalEvent(PKEVENT NotifyEvent) { LARGE_INTEGER Timeout; // AET - 143 Timeout.QuadPart = -5000000; // Delay execution to show "asynchronous" processing KeDelayExecutionThread(KernelMode, FALSE, &Timeout); KeSetEvent(NotifyEvent, 0, FALSE); ExFreePool(pItem); } void KDelayIRPCompletion(PIRP Irp) { LARGE_INTEGER Timeout; Timeout.QuadPart = -5000000; // Delay execution to show "asynchronous" processing KeDelayExecutionThread(KernelMode, FALSE, &Timeout); Irp->IoStatus.Status = STATUS_SUCCESS; // Set # of bytes to copy back to user mode... Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); ExFreePool(pItem); } void KMApcCallback(PKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) { ExFreePool(Apc); return; } NTSTATUS KnotifyDispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS ntStatus; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension; switch(irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_NOTIFY_KERNEL_EVENT: { KeClearEvent(extension->NotifyEvent); pItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM)); // Queue execution to a system thread to permit this IRP to // complete... ExInitializeWorkItem(pItem, KSignalEvent, extension->NotifyEvent); ExQueueWorkItem(pItem, DelayedWorkQueue); ntStatus = STATUS_SUCCESS; break; } case IOCTL_NOTIFY_USER_EVENT: { PKEVENT UserEvent; // Obtain a kernel pointer to the user-mode-created event handle... ObReferenceObjectByHandle(*(( PHANDLE)Irp->AssociatedIrp.SystemBuffer), 0, (POBJECT_TYPE) NULL, UserMode, (PVOID)&UserEvent, (POBJECT_HANDLE_INFORMATION) NULL); pItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM)); // Queue execution to a system thread to permit this IRP to // complete... ExInitializeWorkItem(pItem, KSignalEvent, UserEvent); ExQueueWorkItem(pItem, DelayedWorkQueue); ntStatus = STATUS_SUCCESS; break; } case IOCTL_NOTIFY_EMPTY_IRP: pItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM)); // Queue execution to a system thread to permit this IRP to // complete... ExInitializeWorkItem(pItem, KDelayIRPCompletion, Irp); ExQueueWorkItem(pItem, DelayedWorkQueue); // Mark the IRP pending. The driver will complete it later... IoMarkIrpPending(Irp); ntStatus = STATUS_PENDING; break; case IOCTL_NOTIFY_REGISTER_APC: { PKAPC Apc; ULONG *UserRoutine = (ULONG *)Irp->AssociatedIrp.SystemBuffer; Apc = ExAllocatePool(NonPagedPool, sizeof(KAPC)); KeInitializeApc(Apc, KeGetCurrentThread(), 0, (PKKERNEL_ROUTINE)&KMApcCallback, // kernel-mode routine 0, // rundown routine (PKNORMAL_ROUTINE)*UserRoutine, // user-mode routine UserMode, (PVOID)(ULONG)1); KeInsertQueueApc(Apc, (PVOID)(ULONG)2, (PVOID)(ULONG)3, 0); ntStatus = STATUS_SUCCESS; break; } case IOCTL_NOTIFY_REGISTER_APC_WITH_KM_ALERTING: { KEVENT event; PKTHREAD pThread = KeGetCurrentThread(); PKAPC Apc; ULONG *UserRoutine = (ULONG *)Irp->AssociatedIrp.SystemBuffer; LARGE_INTEGER Timeout; Timeout.QuadPart = 0; Apc = ExAllocatePool(NonPagedPool, sizeof(KAPC)); KeInitializeApc(Apc, KeGetCurrentThread(), 0, (PKKERNEL_ROUTINE)&KMApcCallback, // kernel-mode routine 0, // rundown routine (PKNORMAL_ROUTINE)*UserRoutine, // user-mode routine UserMode, (PVOID)(ULONG)1); KeInsertQueueApc(Apc, (PVOID)(ULONG)2, (PVOID)(ULONG)3, 0); // Cheezy way to force the thread into being alertable :-) KeInitializeEvent(&event, SynchronizationEvent, FALSE); KeWaitForSingleObject(&event, Executive, UserMode, TRUE, &Timeout); ntStatus = STATUS_SUCCESS; break; } default: break; } Irp->IoStatus.Status = ntStatus; // Set # of bytes to copy back to user mode... if(ntStatus == STATUS_SUCCESS) Irp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength; else Irp->IoStatus.Information = 0; if(ntStatus != STATUS_PENDING) IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } void KnotifyUnloadDriver(PDRIVER_OBJECT DriverObject) { UNICODE_STRING uszDeviceString; IoDeleteDevice(DriverObject->DeviceObject); RtlInitUnicodeString(&uszDeviceString, L"\\DosDevices\\Knotify"); IoDeleteSymbolicLink(&uszDeviceString); } -------------------------------------------------------------------------------- Figure 2 Using the OVERLAPPED Structure OVERLAPPED ov={0}; • • • // Create an event handle for async notification // from our driver ov.hEvent = CreateEvent(NULL, // Default security TRUE, // Manual reset FALSE, // non-signaled state NULL); // No name // Tell the driver to signal its event... bReturnCode = DeviceIoControl(hDriver, IOCTL_NOTIFY_USER_EVENT, &UserModeEvent, sizeof(HANDLE), 0, 0, &dwBytesReturned, &ov); // Wait here for the event handle to be set, indicating // that the IOCTL processing is complete. bReturnCode = GetOverlappedResult(hDriver, &ov, &dwBytesReturned, TRUE); CloseHandle(ov.hEvent); -------------------------------------------------------------------------------- Figure 3 APC Snippet from NTDDK.H typedef CCHAR KPROCESSOR_MODE; typedef enum _MODE { KernelMode, UserMode, MaximumMode } MODE; // end_ntndis // // APC function types // // Put in an empty definition for the KAPC so that the // routines can reference it before it is declared. struct _KAPC; typedef VOID (*PKNORMAL_ROUTINE) ( IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ); typedef VOID (*PKKERNEL_ROUTINE) ( IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 ); typedef VOID (*PKRUNDOWN_ROUTINE) ( IN struct _KAPC *Apc ); typedef BOOLEAN (*PKSYNCHRONIZE_ROUTINE) ( IN PVOID SynchronizeContext ); typedef BOOLEAN (*PKTRANSFER_ROUTINE) ( VOID ); // // // Asynchronous Procedure Call (APC) object // typedef struct _KAPC { CSHORT Type; CSHORT Size; ULONG Spare0; struct _KTHREAD *Thread; LIST_ENTRY ApcListEntry; PKKERNEL_ROUTINE KernelRoutine; PKRUNDOWN_ROUTINE RundownRoutine; PKNORMAL_ROUTINE NormalRoutine; PVOID NormalContext; // // N.B. The following two members MUST be together. // PVOID SystemArgument1; PVOID SystemArgument2; CCHAR ApcStateIndex; KPROCESSOR_MODE ApcMode; BOOLEAN Inserted; } KAPC, *PKAPC, *RESTRICTED_POINTER PRKAPC; -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- Send feedback to MSDN.Look here for MSDN Online resources. |
|
|
板凳#
发布于:2004-12-12 19:05
多谢AllenZh大虾指点
接分 |
|