510 lines
16 KiB
Smarty
510 lines
16 KiB
Smarty
|
`**********************************************************************`
|
||
|
`* This is an include template file for tracewpp preprocessor. *`
|
||
|
`* *`
|
||
|
`* Copyright 1999-2001 Microsoft Corporation. All Rights Reserved. *`
|
||
|
`**********************************************************************`
|
||
|
|
||
|
// template `TemplateFile`
|
||
|
//
|
||
|
// Defines a set of functions that simplifies
|
||
|
// kernel mode registration for tracing
|
||
|
//
|
||
|
|
||
|
#if !defined(WppDebug)
|
||
|
# define WppDebug(a,b)
|
||
|
#endif
|
||
|
|
||
|
#define WMIREG_FLAG_CALLBACK 0x80000000 // not exposed in DDK
|
||
|
|
||
|
|
||
|
#ifndef WPPINIT_EXPORT
|
||
|
# define WPPINIT_EXPORT
|
||
|
#endif
|
||
|
|
||
|
#ifdef WPP_GLOBALLOGGER
|
||
|
WPPINIT_EXPORT
|
||
|
void WppIntToHex(
|
||
|
LPWSTR Buf,
|
||
|
unsigned int value,
|
||
|
int digits
|
||
|
)
|
||
|
{
|
||
|
static LPCWSTR hexDigit = L"0123456789abcdef";
|
||
|
while (--digits >= 0) {
|
||
|
Buf[digits] = hexDigit[ value & 15 ];
|
||
|
value /= 16; // compiler is smart enough to change it to bitshift
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define WPP_TEXTGUID_LEN 37
|
||
|
|
||
|
// b1e5deaf-1524-4a04-82c4-c9dfbce6cf97<NULL>
|
||
|
// 0 1 2 3
|
||
|
// 0123456789012345678901234567890123456
|
||
|
WPPINIT_EXPORT
|
||
|
void WppGuidToStr(LPWSTR buf, LPCGUID guid) {
|
||
|
WppIntToHex(buf + 0, guid->Data1, 8);
|
||
|
buf[8] = '-';
|
||
|
WppIntToHex(buf + 9, guid->Data2, 4);
|
||
|
buf[13] = '-';
|
||
|
WppIntToHex(buf + 14, guid->Data3, 4);
|
||
|
buf[18] = '-';
|
||
|
WppIntToHex(buf + 19, guid->Data4[0], 2);
|
||
|
WppIntToHex(buf + 21, guid->Data4[1], 2);
|
||
|
buf[23] = '-';
|
||
|
WppIntToHex(buf + 24, guid->Data4[2], 2);
|
||
|
WppIntToHex(buf + 26, guid->Data4[3], 2);
|
||
|
WppIntToHex(buf + 28, guid->Data4[4], 2);
|
||
|
WppIntToHex(buf + 30, guid->Data4[5], 2);
|
||
|
WppIntToHex(buf + 32, guid->Data4[6], 2);
|
||
|
WppIntToHex(buf + 34, guid->Data4[7], 2);
|
||
|
buf[36] = 0;
|
||
|
}
|
||
|
|
||
|
#define GREGVALUENAMELENGTH 18 + WPP_TEXTGUID_LEN + 1 // wslen(L"WMI\\GlobalLogger\\") + GUIDLENGTH
|
||
|
|
||
|
WPPINIT_EXPORT
|
||
|
void WppInitGlobalLogger(
|
||
|
LPCGUID pControlGuid,
|
||
|
PTRACEHANDLE pLogger,
|
||
|
PULONG pFlags,
|
||
|
PUCHAR pLevel )
|
||
|
{
|
||
|
WCHAR GRegValueName[GREGVALUENAMELENGTH] ; // L"WMI\\GlobalLogger\\d58c126f-b309-11d1-969e-0000f875a5bc" ;
|
||
|
RTL_QUERY_REGISTRY_TABLE parms[3];
|
||
|
ULONG Lflags = 0,
|
||
|
Llevel = 0,
|
||
|
Lstart = 0;
|
||
|
NTSTATUS status ;
|
||
|
ULONG aZero = 0 ;
|
||
|
|
||
|
|
||
|
WppDebug(0,("WPP checking Global Logger"));
|
||
|
|
||
|
swprintf(GRegValueName,L"WMI\\GlobalLogger\\");
|
||
|
//
|
||
|
// Fill in the query table to find out if the Global Logger is Started
|
||
|
//
|
||
|
// Trace Flags
|
||
|
parms[0].QueryRoutine = NULL ;
|
||
|
parms[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
|
parms[0].Name = L"Start";
|
||
|
parms[0].EntryContext = &Lstart;
|
||
|
parms[0].DefaultType = REG_DWORD;
|
||
|
parms[0].DefaultData = &aZero;
|
||
|
parms[0].DefaultLength = sizeof(ULONG);
|
||
|
// Termination
|
||
|
parms[1].QueryRoutine = NULL ;
|
||
|
parms[1].Flags = 0 ;
|
||
|
//
|
||
|
// Perform the query
|
||
|
//
|
||
|
|
||
|
status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL | RTL_REGISTRY_OPTIONAL,
|
||
|
GRegValueName,
|
||
|
parms,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (!NT_SUCCESS(status) || Lstart == 0 ) {
|
||
|
return ;
|
||
|
}
|
||
|
// Fill in the query table to find out if we should use the Global logger
|
||
|
//
|
||
|
// Trace Flags
|
||
|
parms[0].QueryRoutine = NULL ;
|
||
|
parms[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
|
parms[0].Name = L"Flags";
|
||
|
parms[0].EntryContext = &Lflags;
|
||
|
parms[0].DefaultType = REG_DWORD;
|
||
|
parms[0].DefaultData = &aZero;
|
||
|
parms[0].DefaultLength = sizeof(ULONG);
|
||
|
// Trace level
|
||
|
parms[1].QueryRoutine = NULL ;
|
||
|
parms[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
|
parms[1].Name = L"Level";
|
||
|
parms[1].EntryContext = &Llevel;
|
||
|
parms[1].DefaultType = REG_DWORD;
|
||
|
parms[1].DefaultData = &aZero;
|
||
|
parms[1].DefaultLength = sizeof(UCHAR);
|
||
|
// Termination
|
||
|
parms[2].QueryRoutine = NULL ;
|
||
|
parms[2].Flags = 0 ;
|
||
|
|
||
|
|
||
|
WppGuidToStr(&GRegValueName[wcslen(GRegValueName)], pControlGuid) ;
|
||
|
|
||
|
//
|
||
|
// Perform the query
|
||
|
//
|
||
|
|
||
|
status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL | RTL_REGISTRY_OPTIONAL,
|
||
|
GRegValueName,
|
||
|
parms,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (NT_SUCCESS(status)) {
|
||
|
if (Lstart==1) {
|
||
|
*pLogger= WMI_GLOBAL_LOGGER_ID ;
|
||
|
*pFlags = Lflags & 0x7FFFFFFF ;
|
||
|
*pLevel = (UCHAR)(Llevel & 0xFF) ;
|
||
|
WppDebug(0,("WPP Enabled via Global Logger Flags=0x%08X Level=0x%02X",Lflags,Llevel));
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif //#ifdef WPP_GLOBALLOGGER
|
||
|
|
||
|
WPPINIT_EXPORT
|
||
|
NTSTATUS
|
||
|
WppTraceCallback(
|
||
|
IN UCHAR minorFunction,
|
||
|
IN PVOID DataPath,
|
||
|
IN ULONG BufferLength,
|
||
|
IN PVOID Buffer,
|
||
|
IN PVOID Context,
|
||
|
OUT PULONG Size
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Callback routine for IoWMIRegistrationControl.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
status
|
||
|
|
||
|
Comments:
|
||
|
|
||
|
if return value is STATUS_BUFFER_TOO_SMALL and BufferLength >= 4,
|
||
|
then first ulong of buffer contains required size
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
WPP_PROJECT_CONTROL_BLOCK *cb = (WPP_PROJECT_CONTROL_BLOCK*)Context;
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
|
||
|
UNREFERENCED_PARAMETER(DataPath);
|
||
|
|
||
|
WppDebug(0,("WppTraceCallBack 0x%08X %p\n", minorFunction, Context));
|
||
|
|
||
|
*Size = 0;
|
||
|
|
||
|
switch(minorFunction)
|
||
|
{
|
||
|
case IRP_MN_REGINFO:
|
||
|
{
|
||
|
PWMIREGINFOW wmiRegInfo;
|
||
|
PCUNICODE_STRING regPath;
|
||
|
PWCHAR stringPtr;
|
||
|
ULONG registryPathOffset;
|
||
|
ULONG bufferNeeded;
|
||
|
UNICODE_STRING nullRegistryPath;
|
||
|
|
||
|
#if defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
|
||
|
wmiRegInfo = (PWMIREGINFO)Buffer;
|
||
|
|
||
|
if (wmiRegInfo->GuidCount >= 1) {
|
||
|
// Replace the null trace GUID with the driver's trace control GUID
|
||
|
wmiRegInfo->WmiRegGuid[wmiRegInfo->GuidCount-1].Guid = *cb->Registration.ControlGuid;
|
||
|
wmiRegInfo->WmiRegGuid[wmiRegInfo->GuidCount-1].Flags =
|
||
|
WMIREG_FLAG_TRACE_CONTROL_GUID | WMIREG_FLAG_TRACED_GUID;
|
||
|
*Size= wmiRegInfo->BufferSize;
|
||
|
status = STATUS_SUCCESS;
|
||
|
#ifdef WPP_GLOBALLOGGER
|
||
|
// Check if Global logger is active
|
||
|
WppInitGlobalLogger(cb->Registration.ControlGuid,
|
||
|
(PTRACEHANDLE)&cb->Control.Logger,
|
||
|
&cb->Control.Flags[0],
|
||
|
&cb->Control.Level);
|
||
|
#endif //#ifdef WPP_GLOBALLOGGER
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
regPath = cb->Registration.RegistryPath;
|
||
|
|
||
|
if (regPath == NULL)
|
||
|
{
|
||
|
// No registry path specified. This is a bad thing for
|
||
|
// the device to do, but is not fatal
|
||
|
|
||
|
RtlInitUnicodeString(&nullRegistryPath, NULL);
|
||
|
regPath = &nullRegistryPath;
|
||
|
}
|
||
|
|
||
|
registryPathOffset = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid)
|
||
|
+ 1 * sizeof(WMIREGGUIDW);
|
||
|
|
||
|
bufferNeeded = registryPathOffset +
|
||
|
regPath->Length + sizeof(USHORT);
|
||
|
|
||
|
|
||
|
if (bufferNeeded <= BufferLength)
|
||
|
{
|
||
|
RtlZeroMemory(Buffer, BufferLength);
|
||
|
|
||
|
wmiRegInfo = (PWMIREGINFO)Buffer;
|
||
|
wmiRegInfo->BufferSize = bufferNeeded;
|
||
|
wmiRegInfo->RegistryPath = registryPathOffset;
|
||
|
wmiRegInfo->GuidCount = 1;
|
||
|
|
||
|
wmiRegInfo->WmiRegGuid[0].Guid = *cb->Registration.ControlGuid;
|
||
|
wmiRegInfo->WmiRegGuid[0].Flags =
|
||
|
WMIREG_FLAG_TRACE_CONTROL_GUID | WMIREG_FLAG_TRACED_GUID;
|
||
|
|
||
|
stringPtr = (PWCHAR)((PUCHAR)Buffer + registryPathOffset);
|
||
|
*stringPtr++ = regPath->Length;
|
||
|
RtlCopyMemory(stringPtr,
|
||
|
regPath->Buffer,
|
||
|
regPath->Length);
|
||
|
|
||
|
status = STATUS_SUCCESS;
|
||
|
*Size = bufferNeeded;
|
||
|
} else {
|
||
|
status = STATUS_BUFFER_TOO_SMALL;
|
||
|
if (BufferLength >= sizeof(ULONG)) {
|
||
|
*((PULONG)Buffer) = bufferNeeded;
|
||
|
*Size = sizeof(ULONG);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef WPP_GLOBALLOGGER
|
||
|
// Check if Global logger is active
|
||
|
WppInitGlobalLogger(cb->Registration.ControlGuid,
|
||
|
(PTRACEHANDLE)&cb->Control.Logger,
|
||
|
&cb->Control.Flags[0],
|
||
|
&cb->Control.Level);
|
||
|
#endif //#ifdef WPP_GLOBALLOGGER
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IRP_MN_ENABLE_EVENTS:
|
||
|
case IRP_MN_DISABLE_EVENTS:
|
||
|
{
|
||
|
PWNODE_HEADER Wnode = (PWNODE_HEADER)Buffer;
|
||
|
ULONG Level;
|
||
|
ULONG ReturnLength ;
|
||
|
|
||
|
if (cb == NULL )
|
||
|
{
|
||
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (BufferLength >= sizeof(WNODE_HEADER)) {
|
||
|
status = STATUS_SUCCESS;
|
||
|
|
||
|
if (minorFunction == IRP_MN_DISABLE_EVENTS) {
|
||
|
cb->Control.Level = 0;
|
||
|
cb->Control.Flags[0] = 0;
|
||
|
cb->Control.Logger = 0;
|
||
|
} else {
|
||
|
TRACEHANDLE lh;
|
||
|
lh = (TRACEHANDLE)( Wnode->HistoricalContext );
|
||
|
cb->Control.Logger = lh;
|
||
|
#if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
if ((status = WmiQueryTraceInformation( TraceEnableLevelClass,
|
||
|
&Level,
|
||
|
sizeof(Level),
|
||
|
&ReturnLength,
|
||
|
(PVOID)Wnode)) == STATUS_SUCCESS)
|
||
|
{
|
||
|
cb->Control.Level = (UCHAR)Level;
|
||
|
}
|
||
|
|
||
|
status = WmiQueryTraceInformation( TraceEnableFlagsClass,
|
||
|
&cb->Control.Flags[0],
|
||
|
sizeof(cb->Control.Flags[0]),
|
||
|
&ReturnLength,
|
||
|
(PVOID)Wnode);
|
||
|
#else // #ifndef WPP_TRACE_W2K_COMPATABILITY
|
||
|
cb->Control.Flags[0] = WmiGetLoggerEnableFlags(lh) ;
|
||
|
cb->Control.Level = (UCHAR)WmiGetLoggerEnableLevel(lh) ;
|
||
|
WppDebug(0,("Enable/Disable Logger = %p, Flags = 0x%8x, Level = %x08X\n",
|
||
|
cb->Control.Logger,cb->Control.Flags[0],cb->Control.Level));
|
||
|
#endif // #ifndef WPP_TRACE_W2K_COMPATABILITY
|
||
|
}
|
||
|
} else {
|
||
|
status = STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IRP_MN_ENABLE_COLLECTION:
|
||
|
case IRP_MN_DISABLE_COLLECTION:
|
||
|
{
|
||
|
status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IRP_MN_QUERY_ALL_DATA:
|
||
|
case IRP_MN_QUERY_SINGLE_INSTANCE:
|
||
|
case IRP_MN_CHANGE_SINGLE_INSTANCE:
|
||
|
case IRP_MN_CHANGE_SINGLE_ITEM:
|
||
|
case IRP_MN_EXECUTE_METHOD:
|
||
|
{
|
||
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
// DbgPrintEx(XX_FLTR, DPFLTR_TRACE_LEVEL,
|
||
|
// "%!FUNC!(%!SYSCTRL!) => %!status! (size = %d)", minorFunction, status, *Size);
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
WPPINIT_EXPORT
|
||
|
void WppInitKm(
|
||
|
#if defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
IN PDEVICE_OBJECT pDevObject,
|
||
|
#endif // #if defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
IN PUNICODE_STRING RegistryPath,
|
||
|
IN OUT WPP_REGISTRATION_BLOCK* WppReg
|
||
|
)
|
||
|
{
|
||
|
RegistryPath; // unused
|
||
|
while(WppReg) {
|
||
|
WPP_TRACE_CONTROL_BLOCK *cb = (WPP_TRACE_CONTROL_BLOCK*)WppReg;
|
||
|
NTSTATUS status ;
|
||
|
#if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
WppReg -> Callback = WppTraceCallback;
|
||
|
#else // #if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
WppReg -> Callback = NULL ;
|
||
|
#endif // #if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
WppReg -> RegistryPath = NULL;
|
||
|
cb -> FlagsLen = WppReg -> FlagsLen;
|
||
|
cb -> Level = 0;
|
||
|
cb -> Flags[0] = 0;
|
||
|
#if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
status = IoWMIRegistrationControl((PDEVICE_OBJECT)WppReg,
|
||
|
WMIREG_ACTION_REGISTER | WMIREG_FLAG_CALLBACK
|
||
|
#else // #if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
status = IoWMIRegistrationControl(pDevObject,
|
||
|
WMIREG_ACTION_REGISTER
|
||
|
#endif // #if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
);
|
||
|
WppDebug(0,("IoWMIRegistrationControl status = %08X\n"));
|
||
|
WppReg = WppReg->Next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
WPPINIT_EXPORT
|
||
|
void WppCleanupKm(
|
||
|
WPP_REGISTRATION_BLOCK* WppReg
|
||
|
)
|
||
|
{
|
||
|
while (WppReg) {
|
||
|
IoWMIRegistrationControl((PDEVICE_OBJECT)WppReg, WMIREG_ACTION_DEREGISTER | WMIREG_FLAG_CALLBACK );
|
||
|
WppReg = WppReg -> Next;
|
||
|
}
|
||
|
}
|
||
|
#else // #if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
WPPINIT_EXPORT
|
||
|
void WppCleanupKm(
|
||
|
PDEVICE_OBJECT pDO
|
||
|
)
|
||
|
{
|
||
|
IoWMIRegistrationControl(pDO, WMIREG_ACTION_DEREGISTER );
|
||
|
}
|
||
|
#endif // #if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
|
||
|
#if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
#define WPP_SYSTEMCONTROL(PDO)
|
||
|
#define WPP_SYSTEMCONTROL2(PDO, offset)
|
||
|
#else // #if !defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
|
||
|
ULONG_PTR WPP_Global_NextDeviceOffsetInDeviceExtension = -1;
|
||
|
|
||
|
#define WPP_SYSTEMCONTROL(PDO) \
|
||
|
PDO->MajorFunction[ IRP_MJ_SYSTEM_CONTROL ] = WPPSystemControlDispatch;
|
||
|
#define WPP_SYSTEMCONTROL2(PDO, offset) \
|
||
|
WPP_SYSTEMCONTROL(PDO); WPP_Global_NextDeviceOffsetInDeviceExtension = (ULONG_PTR)offset;
|
||
|
|
||
|
// Routine to handle the System Control in W2K
|
||
|
NTSTATUS
|
||
|
WPPSystemControlDispatch(
|
||
|
IN PDEVICE_OBJECT pDO,
|
||
|
IN PIRP Irp
|
||
|
);
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text( PAGE, WPPSystemControlDispatch)
|
||
|
#endif // ALLOC_PRAGMA
|
||
|
|
||
|
// Routine to handle the System Control in W2K
|
||
|
NTSTATUS
|
||
|
WPPSystemControlDispatch(
|
||
|
IN PDEVICE_OBJECT pDO,
|
||
|
IN PIRP Irp
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
ULONG BufferSize = irpSp->Parameters.WMI.BufferSize;
|
||
|
PVOID Buffer = irpSp->Parameters.WMI.Buffer;
|
||
|
ULONG ReturnSize = 0;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
PWNODE_HEADER Wnode=NULL;
|
||
|
HANDLE ThreadHandle;
|
||
|
|
||
|
WppDebug(0,("WPPSYSTEMCONTROL\n"));
|
||
|
|
||
|
if (pDO == (PDEVICE_OBJECT)irpSp->Parameters.WMI.ProviderId) {
|
||
|
#if defined(WPP_TRACE_W2K_COMPATABILITY)
|
||
|
//To differentiate between the case where wmilib has already filled in parts of the buffer
|
||
|
if (irpSp->MinorFunction == IRP_MN_REGINFO) RtlZeroMemory(Buffer, BufferSize);
|
||
|
#endif
|
||
|
Status = WppTraceCallback((UCHAR)(irpSp->MinorFunction),
|
||
|
NULL,
|
||
|
BufferSize,
|
||
|
Buffer,
|
||
|
&WPP_CB[0],
|
||
|
&ReturnSize);
|
||
|
|
||
|
WppDebug(0,("WPPSYSTEMCONTROL Status 0x%08X\n",Status));
|
||
|
|
||
|
Irp->IoStatus.Status = Status;
|
||
|
Irp->IoStatus.Information = ReturnSize;
|
||
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
return Status;
|
||
|
} else if (WPP_Global_NextDeviceOffsetInDeviceExtension != -1) {
|
||
|
|
||
|
ULONG_PTR t;
|
||
|
|
||
|
WppDebug(0,("WPPSYSTEMCONTROL - not for us\n"));
|
||
|
|
||
|
//
|
||
|
// Set current stack back one.
|
||
|
//
|
||
|
IoSkipCurrentIrpStackLocation( Irp );
|
||
|
//
|
||
|
// Pass the call to the next driver.
|
||
|
//
|
||
|
t = (ULONG_PTR)pDO->DeviceExtension;
|
||
|
t += WPP_Global_NextDeviceOffsetInDeviceExtension;
|
||
|
return IoCallDriver((PDEVICE_OBJECT)t,Irp);
|
||
|
|
||
|
} else {
|
||
|
//unable to pass down -- what to do?
|
||
|
//don't change irp status - IO defaults to failure
|
||
|
return Irp->IoStatus.Status;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif // #if !defined(WPP_TRACE_W2K_COMPATABILITY)
|