read queue,
If the read request is pending, ListenThreadFunction loops calling
The remaining code extracts the event information from the read buffer and builds an event object to post to the Monitor view class. The event timestamp that was generated in the
ListenThreadFunction finally closes the event and file handles using CloseHandle.
Listing 14.12 DebugPrint driver ListenThreadFunction function
UINT ListenThreadFunction(LPVOID pParam) {
PLISTENER_INFO pListenerInfo = (PLISTENER_INFO)pParam;
if (pListenerInfo==NULL) return –1;
CString StartMsg = 'Starting to listen';
// …
DebugPrint_Event::SendEvent('Monitor', StartMsg, CTime::GetCurrentTime(), false);
// Buffer for events
const int MAX_EVENT_LEN = 1024;
char Event[MAX_EVENT_LEN+1];
// Create Overlapped read structure and event
HANDLE FileIOWaiter = CreateEvent(NULL, TRUE, FALSE, NULL);
if (FileIOWaiter==NULL) goto Exit2;
OVERLAPPED ol;
ol.Offset = 0;
ol.OffsetHigh = 0;
ol.hEvent = FileIOWaiter;
// Keep looping, waiting for events, until KeepGoing goes false
for(;;) {
// Initiate overlapped read
DWORD TxdBytes;
ResetEvent(FileIOWaiter);
memset(Event,0,MAX_EVENT_LEN+1);
if (!ReadFile(ListenerInfo.DebugPrintDriver, Event, MAX_EVENT_LEN, &TxdBytes, &ol)) {
// Check for read errors
if (GetLastError() !=ERROR_IO_PENDING) {
CString Msg;
Msg.Format('Read didn't return pending %d', GetLastError());
DebugPrint_Event::SendEvent('Monitor', Msg);
goto Exit;
}
// Wait for read to complete (check for KeepGoing
// going false every 100ms)
while (WaitForSingleObject(FileIOWaiter, 100)== WAIT_TIMEOUT) {
if (!ListenerInfo.KeepGoing) {
// Cancel the pending read
CancelIo(ListenerInfo.DebugPrintDriver);
goto Exit;
}
}
// Get read result, ie bytes transferred
if (!GetOverlappedResult(ListenerInfo.DebugPrintDriver, &ol, &TxdBytes, FALSE)) {
DebugPrint_Event::SendEvent('Monitor', 'GetOverlappedResult failed');
continue;
}
}
// Check there's something there
if (TxdBytes < sizeof(TIME_FIELDS)+2) {
DebugPrint_Event::SendEvent('Monitor', 'Short read msg');
continue;
}
// Extract Timestamp, Driver and Msg, and post to View
Event[MAX_EVENT_LEN] = ' ';
PTIME_FIELDS pTF = (PTIME_FIELDS)Event;
CTime gmtEventTime(pTF->Year, pTF->Month, pTF->Day, pTF->Hour, pTF->Minute, pTF->Second);
CTime EventTime = GMTtoLocalTime(gmtEventTime);
char* DriverName = Event+sizeof(TIME_FIELDS);
CString CSDriverName = DriverName;
CString CSDriverMsg = Event+sizeof(TIME_FIELDS)+strlen(DriverName)+1;
DebugPrint_Event::SendEvent(CSDriverName, CSDriverMsg, EventTime);
}
Exit:
CloseHandle(FileIOWaiter);
Exit2:
CloseHandle(ListenerInfo.DebugPrintDriver);
ListenerInfo.DebugPrintDriver = NULL;
DebugPrint_Event::SendEvent('Monitor', 'Stopped listening');
return 0;
}
Conclusion
This chapter has built a full working driver, which can be used to generate debug trace prints that can be seen in a user application. It has covered system threads, dispatcher objects, linked lists, file I/O, a simple IRP queue, and IRP cancel routines.