How can I share data between my user mode application and my kernel mode driver.
How to Share an Event between Kernel Mode and User Mode
The recommended way to share memory between user mode and kernel mode is to take advantage of the memory locking and address translation mechanisms that the system uses for passing requests to drivers. An application simply passes the address and size of the buffer to be shared as a parameter to DeviceIoControl, and the system automatically locks it into memory and provides a system address for the driver. There are just a few things to remember when setting up this kind of mechanism.
First of all, the IOCTL code that the application uses when passing the buffer must be constructed using the correct buffer method, namely METHOD_OUT_DIRECT. For example,
CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
Second, the call to DeviceIoControl must use asynchronous completion, which is also known as "overlapped I/O". Here is some code that shows how that is done:
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
memset (&ov, 0, sizeof(OVERLAPPED));
ov.hEvent = hEvent;
Remember that you must open the device with FILE_FLAG_OVERLAPPED in the call to CreateFile in order for this to work, and that all calls through that handle must supply an overlap structure.
In the driver, the handler for IRP_MJ_DEVICE_CONTROL obtains the system address of the buffer via the MDL in the IRP, and then pends the request. When the buffer is no longer needed, the application calls DeviceIoControl again, this time with code IOCTL_MYDRIVER_DONE_USING_SHARE_BUFFER . The driver then completes the original IRP.
NTSTATUS MyDevice::DriverControl(Kirp I)
m_SharedBuffer = M.MapToSystemSpace();
m_SharedBufferIrp = I;
. . .
. . .
Note: It's a good idea to set a cancel routine on the IRP that holds the buffer, in case something causes the application to terminate abnormally.