Click here to Skip to main content
Click here to Skip to main content

Communication between GUI Application and Device Driver

By , 26 Mar 2002
 

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:

  1. Create an event object and down it into driver.
    HANDLE m_hCommEvent = CreateEvent(NULL, false, false, NULL);
    //download event object to device driver, m_hCommDevice is the device object
    DeviceIoControl(m_hCommDevice,
                    IO_REFERENCE_EVENT,
                    (LPVOID) m_hCommEvent, 
                     0,
                     NULL,
                     0,
                     &dwReturn,
                     NULL);
  2. Wait the event object to be signaled.
    while(true)
    {
    	WaitForSingleObject(m_hCommEvent, INFINITE);
    	//After this function, the event is set to non signaled. 
    	//Get information and deal with it.
    }     

In the device driver the code like this:

  1. 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.

  2. When the object event happened
    KeSetEvent(gpEventObject, 0, FALSE);
  3. 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

lizhiwei
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionCan anybody help mememberfirstxx30 Apr '04 - 1:11 
I'm writing personal firewall and I need to receive some data from driver .
I know how to send data to driver, but I dont now how to read data from driver.
Can you show me how to do this.
For example how to send string-"hello" from driver to GUI application.
 
If You know how to do this please email me firstx@o2.pl (source code or some projects will be very usefull)
 
Thanks.
(sorry for my english Smile | :) )
General Comm. between usermode Application and Device DrivermemberSETI5127 Mar '04 - 7:36 
Hi!
 
I'm working on a virtual soundcard, based on the "MSVAD" example contained in the Windows DDK. Microphone and speaker will be emulated by software. Realtime problems should be handled with an appropiate buffer. In general this is a minor problem for my project.
 
The question is, how to exchange stream data every 10 milliseconds between driver and user-mode application. I tried to use IRP-messages for I/O like it is done in multiple simple examples. Unfortunately it was either possible to initialize the sound or (XOR!) the access from an application. Having sound and access at the same time was not possible.
 
The application tries to connect to the driver with "CreateFile", but the resulting handle is invalid. I haven't found a way to tell the driver, how to open the device properly.
 
The second approach was a second device (with GUID) created in the driver. This device has the same structure as the I/O-Example. After some codechanges the driver started, but the "CreateFile" always called the sounddevice, resulting in a broken handle. D'Oh! | :doh:
Generaldynamic loading of dlls in kernel modesussAnonymous1 Dec '03 - 22:19 
Is there any way to dynamically load a kernel-mode DLL? Some kernel-mode routines similiar to LoadLibrary?
Or should i just use kernel32.dll's LoadLibrary in kernel-mode?
Or should kernel-mode DLLs be linked only statically ?
 
Thank you,
phoCus.

GeneralRe: dynamic loading of dlls in kernel modesussKetil Jensen23 May '05 - 21:28 
You can use LdrLoadDll from ntdll.dll ( i think )
 
the functions prototype is:
 
NTSYSAPI
NTSTATUS
NTAPI
LdrLoadDll(
IN PWCHAR PathToFile OPTIONAL,
IN ULONG Flags OPTIONAL,
IN PUNICODE_STRING ModuleFileName,
OUT PHANDLE ModuleHandle );
 
By the way ... You can't user kernel32.dll or any other usermode dll's in ring0.
 
If you have any more questions about this topic, just drop me a mail.
 
If there is any interest for it, i can write a paper on function-hooking and hooking of the kernels service table in kernel-mode.
 
As i said, just drop me a mail.
 
Ketil Jensen
minpost2@start.no
GeneralI create Event in drivermemberxenic9 Nov '03 - 20:44 
when i develop a personal firewall ,i create the named event in the driver.
and when i want to set the event to non-signal ,i use API DeviceIoControl to
call the driver to do the thing that Reset the event. i think this method is more secure.
 
I am a willing boy..
QuestionIsn't it really slow?membertomithecat19 Aug '03 - 3:30 
Hi,
 
I'm doing the same thing in my driver, except that I call KeSetEvent() from an ISR routine. Here is the client side:
 
while(!bExit)
{
IRQCnt++;
 
tmp = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
 
switch(tmp)
{
case WAIT_OBJECT_0:
bExit = TRUE;
break;
 
case WAIT_OBJECT_0 + 1:
ReadPortByte(BaseAddress, &Data);
ResetEvent(hEvents[1]);
IRQCnt++;
break;
}
}
 
And here is the ISR:
 
if (KeReadStateEvent(deviceExtension->UserNotificationEvent))
{
KdPrint(("Byte lost.\n"));
InterlockedIncrement(&deviceExtension->LostBytes);
}
else
{
KeSetEvent(deviceExtension->UserNotificationEvent, 0, FALSE);
}
 
My problem is that even at very slow IRQ freq. (2Hz!) I get this "Byte lost" message, which means that the client had no time to call ResetEvent() and another IRQ has already came in. The strange thing is that if I fire IRQs at highter freqs. tghe number of lost bytes doesn't increase proportionally (it doesn't increase at all).
 
Any ideas? I heard that this is the standard way of notifying user-mode apps, but I just can't believe that it's this slow.
 
Thanks.
Tamas

AnswerRe: Isn't it really slow?memberDavidR_r7 Jul '04 - 9:04 
I think your problem is that interrupt is not caused by eadge ,and you do not release the reason for the ISR. What I mean is that when you get a new byte a flag is set and each time while the flag is set you get new ISR about the same byte. the solution is to relase the flag in the client.
 
DavidR
GeneralRe: Isn't it really slow?membertomithecat7 Jul '04 - 9:33 
Thank you David!
 
Long time passed since I asked this question. Since then I figured out many things about kernel-mode drivers. I wrote 2 drivers (PCI, parallel port) and completely left out this kind of user notification technique. I think it's a bad solution most of the time, because it always takes considerable amount of time to switch between user mode and kernel mode. The proper way of doing it is to handle the IRQ within the driver and have the user call ReadFile() to get data from the driver. Both of my drivers were used in time critical scenarios and it could handle 20kHz IRQ rate fine, without burning much CPU resources.
 
Anyway, thanks for the help!
Tamas
 


GeneralRe: Isn't it really slow?sussAnonymous5 Nov '04 - 11:37 
I'm sending this to Richard Marcel, for some reason his eamil address was rejected by my smtp server:
 
Once you can handle the IRQ, the rest is a piece of cake. Smile | :)

Ok, so, here is how I do it:

In user mode:
1. Open the driver with CreateFile() - (Remember that you have to call IoCreateSymbolicLink() in your driver somewhere (most probably in the DriverEntry routine) to be able to access the driver this way. Also, you must pass in the OPEN_EXISTING and the FILE_FLAG_OVERLAPPED flags)
2. Call ReadFile() asynchronously and pass it a buffer. (ie. use an OVERLAPPED structure)
3. Call WaitForSingleObject() or use GetQueuedCompletionStatus()
4. You have the data in the buffer!

In kernel mode:
1. Have a dispatch Read function in your driver (DriverObject->MajorFunction[IRP_MJ_READ] = )
2. Create a queue by the InitializeListHead() function in your DriverEntry routine.
3. Init the CS queue (Cancel-safe queue) with IoCsqInitialize() in your DriverEntry routine. (the DDK help has a complete sample)
4. In your dispatch Read function, queue the IRP into a CSQ.
a. Call IoCsqInsertIrp() to queue the IRP.
b. return STATUS_PENDING from your dispatch routine.

At this stage the ReadFile() function returns with STATUS_PENDING in the user mode code and step 3. starts.

5. When an IRQ arrives, queue your DPC routine with KeInsertQueueDpc()
6. In your DPC routine:
a. Call IoCsqRemoveNextIrp() to get the IRP you queued in the Read dispatch routine.
b. Get access to the user buffer by something like this:
PUCHAR p = (PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
c. Fill the buffer with any data you like.
7. Call KeFlushIoBuffers(Irp->MdlAddress, TRUE, FALSE);
8. Call IoCompleteRequest(Irp, ...) to complete the IRP.

When 8. completes, step 3 in the user code returns and you have the data in your buffer!

Of course, you may skip 7 and 8 and fill the buffer step by step in more than one IRQ and call them when the buffer is full.

So, it's as simple as that! I hope it helps. Drop me a mail if you have any more questions.

Regards,
Tamas Karoly
Generalabout Miniport Driver!memberdewen18 Aug '03 - 10:13 
hi,
i have a C6701EVM of Texas Instruments(TI).I have written some C-programms and realized the communication between the EVM and the Host using the driver of TI.Now I want to write a Miniport Driver and put the C-programm source code into this Miniport Driver.It will be realized that the DSP-card works as a TCP/IP-networkcard.But I do not know whether this concept is right or not.The following illustrates the concept:
EVM(Evaluation Model Board)<--->Driver of TI<--->Miniport Driver(includes C source code)<---->TCP/IP
I hope someone can help me. Thank you!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 27 Mar 2002
Article Copyright 2002 by lizhiwei
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid