read queue, ReadFile returns false and GetLastError returns ERROR_IO_PENDING. The code checks for a real error return from ReadFile. If the DebugPrint Monitor application is run twice, the second incarnation will get an error here when the DebugPrint driver read routine fails an attempt to queue a second Read IRP.

If the read request is pending, ListenThreadFunction loops calling WaitForSingleObject with a timeout of 100ms. If WaitForSingleObject times-out, ListenThreadFunction checks to see if KeepGoing has returned false. If so, it calls CancelIo to cancel the pending Read IRP and exits. Incidentally, calling CancelIo in another thread, such as the StopListener routine, does not work.

WaitForSingleObject detects when the read request has finished when the FileIOWaiter event becomes signalled. In Windows 2000, ListenThreadFunction could wait on the file object instead of an event. However, this does not work in Windows 98, so I use events that work in both operating systems. ListenThreadFunction calls GetOverlappedResult to retrieve the number of bytes that were received.

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 DebugPrintMsg routine is a time in GMT. The GMTtoLocalTime function does all the necessary grovelling around to convert this into a local time.

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.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату
×