bool ReadEvent(PDEBUGPRINT_DEVICE_EXTENSION dx, PIRP Irp) {

 // Try to remove Event from EventList

 PLIST_ENTRY pListEntry = ExInterlockedRemoveHeadList(&dx->EventList, &dx->EventListLock);

 if (pListEntry==NULL) return false;

 // Get event as DEBUGPRINT_EVENT

 PDEBUGPRINT_EVENT pEvent = CONTAINING_RECORD(pListEntry, DEBUGPRINT_EVENT, ListEntry);

 // Get length of event data

 ULONG EventDataLen = pEvent->Len;

 // Get max read length acceptible

 PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);

 ULONG ReadLen = IrpStack->Parameters.Read.Length;

 // Shorten event length if necessary

 if(EventDataLen>ReadLen) EventDataLen = ReadLen;

 // Copy data to Irp and complete it

 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, pEvent->EventData, EventDataLen);

 IoSetCancelRoutine(Irp, NULL);

 CompleteIrp(Irp, STATUS_SUCCESS, EventDataLen);

 // Free event memory

 ExFreePool(pEvent);

 return true;

}

DebugPrint Monitor

The DebugPrint Monitor is a user mode application that keeps reading events from the DebugPrint driver and displays them to the user. The Monitor is a standard MFC application, so this chapter will not discuss all the code in detail. The source files can be found on the book software disk.

The Monitor program saves its current screen position and column widths in the registry. Consult the code to find out how this is done.

Design

The Monitor uses a single document interface. The view class CDebugPrintMonitorView is derived from CListView, which encapsulates a list view control. It is this list view control that stores the event information once it has been received by the Monitor. The corresponding document class CDebugPrintMonitorDoc does not store the event information. It simply implements the OnSaveDocument document method to save event information from the view to a .dpm file, and OnOpenDocument to load data.

The main work is carried out in a worker thread, which runs ListenThreadFunction in Listener.cpp. This thread chugs away in the background, reading any available events from the DebugPrint driver. It posts a message to the view class for each event, passing a pointer to the event data. The view class handles these messages in its OnDebugPrintEvent routine by inserting an appropriate event item at the end of the list control.

Win32 Worker Threads

The DebugPrint Monitor application class calls StartListener in its InitInstance method to start the listen worker thread. The ExitInstance method calls StopListener to stop it.

The code uses a LISTENER_INFO structure to pass information to the worker thread. There is only one instance of this object called ListenerInfo.

typedef struct _LISTENER_INFO {

 HANDLE DebugPrintDriver;

 bool KeepGoing;

} LISTENER_INFO, *PLISTENER_INFO;

LISTENER_INFO ListenerInfo;

StartListener first stores a safe HWND handle to the view window, to be used later.

It then finds the first DebugPrint driver device and opens a handle to it using GetDeviceViaInterface01. This is a variant on GetDeviceViaInterface, shown in Chapter 5. GetDeviceViaInterface01 opens the device for overlapped I/O by specifying the FILE_FLAG_OVERLAPPED bit in the dwFlagsAndAttributes parameter to CreateFile. The DebugPrint device handle is stored in ListenerInfo.DebugPrintDriver.

The code uses the KeepGoing field in ListenerInfo to signal when the worker thread should stop. KeepGoing is therefore set to true before the thread is started. The thread is started using AfxBeginThread, passing a pointer to the function to run, ListenThreadFunction, and a context to pass to it.

ListenThreadFunction loops, waiting either for event data or for KeepGoing to return false. ListenThreadFunction is in the file Dispatch.cpp on the CD-ROM.

DebugPrint_Event Class

The DebugPrint_Event class shown in Listing 14.11 is used to communicate events to the view class. Each class instance has Driver and Message strings and an MFC CTime Timestamp. A static method called SendEvent is used to post a DebugPrint_Event message to the view class.

DebugPrint_Event::SendEvent( 'Monitor', 'Starting to listen', CTime::GetCurrentTime(), false);

Listing 14.11 DebugPrint driver DebugPrint_Event class

const UINT WM_DEBUGPRINTEVENT = (WM_USER+1);

class DebugPrint_Event {

public:

 CString Driver;

 CTime Timestamp;

 CString Message;

 bool SetModified; // false to reset document SetModifiedFlag.

 static HWND ViewHwnd; // View Hwnd

 // Generate and send an event

 static void SendEvent(CString d, CString m, CTime t = 0, bool sm=true) {

  if (ViewHwnd==NULL) return;

  DebugPrint_Event* pEvent = new DebugPrint_Event;

  pEvent->Driver = d;

  if (t==0) t = CTime::GetCurrentTime();

  pEvent->Timestamp = t;

  pEvent->Message = m;

  pEvent->SetModified = sm;

  ::PostMessage(ViewHwnd, WM_DEBUGPRINTEVENT, 0, (LPARAM)pEvent);

 }

};

Win32 Overlapped I/O

The code in ListenThreadFunction mainly deals with overlapped I/O to the DebugPrint device. It must check the state of the KeepGoing flag. Overlapped I/O lets us issue a read request and get on with other tasks.

To do overlapped I/O, a Win32 event and an OVERLAPPED structure are needed. CreateEvent is used to initialize the FileIOWaiter manual event into the nonsignalled state. The OVERLAPPED structure (ol) stores the file pointer offset and FileIOWaiter event handle.

A standard ReadFile call is used to initiate a read request. The read buffer is 1024 bytes, which should be large enough for any DebugPrint event. ReadFile is passed a pointer to the OVERLAPPED structure. Overlapped I/O does work with device files in Windows 98, but does not work on ordinary file I/O.

ReadFile returns true if the read request completes straightaway. The number of bytes transferred is stored in TxdBytes. If the read request is held in the DebugPrint

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

0

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

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