Background
Recently I
read a good article in which the author wrote a device driver and a GUI
program, and he wanted to notify the GUI App when some event happened in the device
driver. In his article, when a new process was created, a callback function in
his driver would be called and it would notify the GUI App and display some
information about the new process immediately. In the device driver, the author
create a named event and opened it in GUI App. Then when an event happened, he
handled it like this:
KeSetEvent(Event, 0, FALSE);
KeClearEvent(Event);
At this time,
the GUI App was waiting for the event. Between the interval of the two
functions, the App must got information of the new process. It works, but I
don't think it's a good solution.
Why does
the author code like this? Because, if we create an event in kernel mode, we
can't modify its state in user mode, we only can check its state. But normally,
we want the GUI App to modify the event to to non signaled, and it can wait the event
again. I think this is the eligible IPC model to deal with this question.
About my
solution
Kernel mode
has higher priority than user mode. In kernel mode we can modify data in user
mode conveniently. So I create an event object in user mode, and refer it in
kernel mode. Now both device driver and GUI App can check and modify the state
of the event object.
How to
integrate it into your application
In your
App, you must open the device object firstly, then code like this:
- Create an
event object and down it into driver.
HANDLE m_hCommEvent = CreateEvent(NULL, false, false, NULL);
DeviceIoControl(m_hCommDevice,
IO_REFERENCE_EVENT,
(LPVOID) m_hCommEvent,
0,
NULL,
0,
&dwReturn,
NULL);
- Wait the
event object to be signaled.
while(true)
{
WaitForSingleObject(m_hCommEvent, INFINITE);
}
In the device driver the code like this:
- In the IRP_MJ_DEVICE_CONTROL major routine:
case IO_REFERENCE_EVENT:
hEvent = (HANDLE) irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
status = ObReferenceObjectByHandle(
hEvent,
GENERIC_ALL,
NULL,
KernelMode,
&gpEventObject,
&objHandleInfo);
the gpEventObject is a PRKEVENT object, so
we can use KeEventXXX and KeWaitForXXX to operate it.
- When the
object event happened
KeSetEvent(gpEventObject, 0, FALSE);
- When we
don't need it, we should dereference it:
case IO_DEREFERENCE_EVENT:
if(gpEventObject)
ObDereferenceObject(gpEventObject);
I have tested
my solution in a personal firewall product. It works well. When my IP Filter
Driver got an IP packet, it checks the IP header as my security rules. If the
packet will be intercepted, it reports to my GUI App.
The sample download include two projects: a GUI app and a device driver. The GUI App is a dialog based
MFC application. It has a log window which can register the operations on event
object. The device driver is only a very simple kernel mode device driver. It
can operate the event object as the GUI App requries. I you want to run this demo, you
must install and start the driver firstly.
Because there are so many tools can
install and start device deriver, so I don't include the code to do this work.
If you have any
problems and advices, Please notify me.