The final hurdle to overcome is registering your driver as an event source so that the event viewer knows where to find your message text resource. Two registry changes must be made.
First, the HKLMSystemCurrentControlSetServicesEventLogSystem key has an existing REG_MULTI_SZ value called Sources. Add the name of your driver's executable (without the extension) as a line in Sources.
In this same registry key, make a new subkey with this same driver name. In this subkey, add a REG_EXPAND_SZ value called EventMessageFile and set a REG_DWORD called TypesSupported with a value of 0x7. For Wdm3, set EventMessageFile to the following value.
%SystemRoot%System32IoLogMsg.dll;%SystemRoot%System32DriversWdm3.sys
The Wdm3 installation INF file supposedly has the correct information to make these registry changes when a Wdm3 device is installed. Listing 13.4 shows the amendments made to the standard installation file. The AddService directive's last field specifies the name of the section containing the error logging registry values. There are optional fields to specify the log type (System, Security, or Application) and a log name.
The Wdm3.Service.EventLog section specifies the values for the EventMessageFile and TypesSupported values. The EventMessageFile entry is on one long line.
However, I found that this did not work completely in Windows 2000 Beta 3. 'Wdm3' was correctly added to the Sources value and the HKLMSystemCurrentControlSetServicesEventLog SystemWdm3 key was correctly made, but no values were placed in the key.
It is simplest just to add these registry entries by hand. You will have to use
Note: A revised version of installation file Wdm3sysWdm3free.inf is available on the book's web site, www.phdcc.com/wdmbook. This updated version fixes the EventLog section problem.
For NT 3.51 and NT 4 drivers, you cannot use an INF installation file. Instead, you will have to amend your installation program to set up the registry entries. The example installation code, install.cpp (on the book's CD-ROM) shows how to do this job.
Listing 13.4 Wdm3free.inf installation file event logging sections
[Wdm3.Install.NT.Services]
AddService =
Wdm3, %SPSVCINST_ASSOCSERVICE%, Wdm3.Service, Wdm3.Service.EventLog
; …
[Wdm3.Service.EventLog]
HKR,,EventMessageFile,%FLG_ADDREG_TYPE_EXPAND_SZ%,
'%%SystemRoot%%System32IoLogMsg.dll;
%%SystemRoot%%System32driversWdm3.sys'
HKR,,TypesSupported,%FLG_ADDREG_TYPE_DW0RD%,7
Generating Events
Listing 13.5 shows the routines that provide the event logging,
The basic IO_ERR0R_L0G_PACKET structure contains one dump data ULONG, but no insertion strings. It is an extendible structure. Zero or more dump data ULONGs can be provided, followed immediately by any NULL terminated wide strings. This makes calculating and filling the packet size slightly involved.
Listing 13.5 InitializeEventLog and LogEvent routines
void InitializeEventLog(IN PDRIVER_OBJECT DriverObject) {
SavedDriverObject = DriverObject;
// Log a message saying that logging is started.
LogEvent(WDM3_MSG_LOGGING_STARTED, NULL, // IRP
NULL, 0, // dump data
NULL, 0); // strings
}
bool LogEvent(IN NTSTATUS ErrorCode, IN PIRP Irp, IN ULONG DumpData[], IN int DumpDataCount, IN PWSTR Strings[], IN int StringCount) {
if (SavedDriverObject==NULL) return false;
// Start working out size of complete event packet
int size = sizeof(IO_ERROR_LOG_PACKET);
// Add in dump data size.
// Less one as DumpData already has 1 ULONG in IO_ERROR_LOG_PACKET
if (DumpDataCount>0) size += sizeof(ULONG) * (DumpDataCount-1);
// Add in space needed for insertion strings (inc terminating NULLs)
int* StringSizes = NULL;
if (StringCount>0) {
StringSizes = (int*)ExAllocatePool(NonPagedPool, StringCount*sizeof(int));
if (StringSizes==NULL) return false;
// Remember each string size
for (int i=0; i<StringCount; i++) {
StringSizes[i] = (int)GetWideStringSize(Strings[i]);
size += StringSizes[i ];
}
}
if (size>ERROR_LOG_MAXIMUM_SIZE) // 0x98!
{
if (StringSizes!=NULL) ExFreePool(StringSizes);
return false;
}
// Try to allocate the packet
PIO_ERROR_LOG_PACKET Packet = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(SavedDriverObject, size);
if (Packet==NULL) {
if (StringSizes!=NULL) ExFreePool(StringSizes);
return false;
}
// Fill in standard parts of the packet
Packet->ErrorCode = ErrorCode;
Packet->UniqueErrorValue = 0;
// Fill in IRP related fields
Packet->MajorFunctionCode = 0;
Packet->RetryCount = 0;