windows-nt/Source/XPSP1/NT/printscan/print/spooler/perflib/wmi.c

409 lines
10 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990-1999 Microsoft Corporation
All rights reserved
Module Name:
wmi.c
Abstract:
Holds the internal operations for wmi instrumenation
Author:
Stuart de Jong (sdejong) 15-Oct-99
Environment:
User Mode -Win32
Revision History:
--*/
#include "precomp.h"
//
// WMI files
//
#include <wmistr.h>
#include <evntrace.h>
#include "wmi.h"
#include "wmidata.h"
// End WMI
//
// How it works:
//
// There are similar guids defined in the sdktools tracecounter programs, and also
// descriptions there of the information we send them. This is used by them to print out
// and format the data we send.
//
// When we start up we register ourselves with WMI and provide a callback into our control
// code. This allows an external tool to call the start trace code in WMI with our guid, which
// then has WMI call us, and start tracing.
//
// Stopping a trace is also done through the callback. the data is then analyzed by the WMI tools
// and output in human readable form, or it could be further analyzed from there.
//
MODULE_DEBUG_INIT ( DBG_ERROR, DBG_ERROR );
// These Guid's correspond to the definitions in \nt\sdktools\trace\tracedmp\mofdata.guid
//
// Identifies the PrintJob data logged by the delete job event.
//
GUID WmiPrintJobGuid = { /* 127eb555-3b06-46ea-a08b-5dc2c3c57cfd */
0x127eb555, 0x3b06, 0x46ea, 0xa0, 0x8b, 0x5d, 0xc2, 0xc3, 0xc5, 0x7c, 0xfd
};
//
// Identifies the RenderedJob data logged by the job rendered event.
//
GUID WmiRenderedJobGuid = { /* 1d32b239-92a6-485a-96d2-dc3659fb803e */
0x1d32b239, 0x92a6, 0x485a, 0x96, 0xd2, 0xdc, 0x36, 0x59, 0xfb, 0x80, 0x3e
};
//
// Used by the control app. to find the callback that turns spooler tracing on
// and off.
//
GUID WmiSpoolerControlGuid = { /* 94a984ef-f525-4bf1-be3c-ef374056a592 */
0x94a984ef, 0xf525, 0x4bf1, 0xbe, 0x3c, 0xef, 0x37, 0x40, 0x56, 0xa5, 0x92 };
#define szWmiResourceName TEXT("Spooler")
TRACE_GUID_REGISTRATION WmiTraceGuidReg[] =
{
{ (LPGUID)&WmiPrintJobGuid,
NULL
},
{ (LPGUID)&WmiRenderedJobGuid,
NULL
}
};
//
// The mof fields point to the following data.
// DWORD JobId; // Unique ID for the transaction of printing a job
// WMI_SPOOL_DATA Data; // See splcom.h
//
typedef struct _WMI_SPOOL_EVENT {
EVENT_TRACE_HEADER Header;
MOF_FIELD MofData[2];
} WMI_SPOOL_EVENT, *PWMI_SPOOL_EVENT;
static TRACEHANDLE WmiRegistrationHandle;
static TRACEHANDLE WmiLoggerHandle;
static LONG ulWmiEnableLevel = 0;
static HANDLE hWmiRegisterThread = NULL;
static DWORD dwWmiRegisterThreadId = 0;
static ULONG bWmiTraceOnFlag = FALSE;
static ULONG bWmiIsInitialized = FALSE;
ULONG
WmiControlCallback(
IN WMIDPREQUESTCODE RequestCode,
IN PVOID Context,
IN OUT ULONG *InOutBufferSize,
IN OUT PVOID Buffer
);
/*++
Routine Name:
WmiRegisterTrace()
Routine Description:
Thread routine that registers us with the WMI tools
Arguments:
LPVOID Arg : Not used.
--*/
DWORD
WmiRegisterTrace(
IN LPVOID arg
)
{
ULONG Status = ERROR_SUCCESS;
WCHAR szImagePath[MAX_PATH];
Status = GetModuleFileName(NULL, szImagePath, COUNTOF(szImagePath));
if (Status == 0) {
Status = ERROR_FILE_NOT_FOUND;
}
else {
Status = RegisterTraceGuids(
WmiControlCallback,
NULL,
(LPGUID)&WmiSpoolerControlGuid,
1,
WmiTraceGuidReg,
szImagePath,
szWmiResourceName,
&WmiRegistrationHandle);
if (Status == ERROR_SUCCESS) {
DBGMSG(DBG_TRACE, ("WmiInitializeTrace: SPOOLER WMI INITIALIZED.\n"));
InterlockedExchange(&bWmiIsInitialized, TRUE);
}
else {
DBGMSG(DBG_TRACE, ("WmiInitializeTrace: SPOOLER WMI INITIALIZE FAILED: %u.\n",
Status));
}
}
return Status;
}
/*++
Routine Name:
WmiInitializeTrace()
Routine Description:
Initialises the Trace structures and registers the callback with WMI.
This creates a thread and calls WmiRegisterTrace, since the registering may take
a long time (up to minutes)
Arguments:
Returns ERROR_SUCCESS if it succeeds or ERROR_ALREADY_EXISTS otherwise
--*/
ULONG
WmiInitializeTrace(VOID)
{
ULONG Status = ERROR_ALREADY_EXISTS;
if (!hWmiRegisterThread)
{
InterlockedExchange(&bWmiIsInitialized, FALSE);
//
// Registering can block for a long time (I've seen minutes
// occationally), so it must be done in its own thread.
//
if (hWmiRegisterThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)WmiRegisterTrace,
0,
0,
&dwWmiRegisterThreadId))
{
CloseHandle(hWmiRegisterThread);
Status = ERROR_SUCCESS;
}
else
{
Status = GetLastError();
}
}
return Status;
}
/*++
Routine Name:
WmiTerminateTrace()
Routine Description:
Deregisters us from the WMI tools
Arguments:
Returns ERROR_SUCCESS on success. a Winerror otherwise.
--*/
ULONG
WmiTerminateTrace(VOID)
{
ULONG Status = ERROR_SUCCESS;
DWORD dwExitCode;
if (bWmiIsInitialized) {
InterlockedExchange(&bWmiIsInitialized, FALSE);
Status = UnregisterTraceGuids(WmiRegistrationHandle);
if (Status == ERROR_SUCCESS) {
DBGMSG(DBG_TRACE, ("WmiTerminateTrace: SPOOLER WMI UNREGISTERED.\n"));
}
else {
DBGMSG(DBG_TRACE, ("WmiTerminateTrace: SPOOLER WMI UNREGISTER FAILED.\n"));
}
}
return Status;
}
/*++
Routine Name:
SplWmiTraceEvent()
Routine Description:
If tracing is turned on, this sends the event to the WMI subsystem.
Arguments:
DWORD JobId : the JobID this is related to.
UCHAR EventTraceType : The type of event that happened
PWMI_SPOOL_DATA Data : The Event Data, could be NULL
Returns ERROR_SUCCESS if it doesn't need to do anything, or if it succeeds.
--*/
ULONG
LogWmiTraceEvent(
IN DWORD JobId,
IN UCHAR EventTraceType,
IN PWMI_SPOOL_DATA Data OPTIONAL
)
{
WMI_SPOOL_EVENT WmiSpoolEvent;
ULONG Status;
if (!bWmiTraceOnFlag)
return ERROR_SUCCESS;
//
// Level 1 tracing just traces response time of individual jobs with job data.
// Default level is 0.
//
if (ulWmiEnableLevel == 1) {
switch (EventTraceType) {
//
// Save overhead by not tracking resource usage.
//
case EVENT_TRACE_TYPE_SPL_TRACKTHREAD:
case EVENT_TRACE_TYPE_SPL_ENDTRACKTHREAD:
return ERROR_SUCCESS;
default:
//
// Job data.
//
break;
}
}
//
// Record data.
//
RtlZeroMemory(&WmiSpoolEvent, sizeof(WmiSpoolEvent));
WmiSpoolEvent.Header.Size = sizeof(WMI_SPOOL_EVENT);
WmiSpoolEvent.Header.Flags = (WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR);
WmiSpoolEvent.Header.Class.Type = EventTraceType;
WmiSpoolEvent.Header.Guid = WmiPrintJobGuid;
WmiSpoolEvent.MofData[0].DataPtr = (ULONG64)&JobId;
WmiSpoolEvent.MofData[0].Length = sizeof(DWORD);
WmiSpoolEvent.MofData[1].DataPtr = (ULONG64)Data;
if (Data) {
switch (EventTraceType) {
case EVENT_TRACE_TYPE_SPL_DELETEJOB:
WmiSpoolEvent.MofData[1].Length = sizeof(struct _WMI_JOBDATA);
break;
case EVENT_TRACE_TYPE_SPL_JOBRENDERED:
WmiSpoolEvent.Header.Guid = WmiRenderedJobGuid;
WmiSpoolEvent.MofData[1].Length = sizeof(struct _WMI_EMFDATA);
break;
default:
DBGMSG(DBG_TRACE, ("SplWmiTraceEvent: FAILED to log WMI Trace Event Unexpected Data JobId:%u Type:%u\n",
JobId, (ULONG) EventTraceType));
return ERROR_INVALID_DATA;
}
}
Status = TraceEvent(
WmiLoggerHandle,
(PEVENT_TRACE_HEADER) &WmiSpoolEvent);
//
// logger buffers out of memory should not prevent provider from
// generating events. This will only cause events lost.
//
if (Status == ERROR_NOT_ENOUGH_MEMORY) {
DBGMSG(DBG_TRACE, ("SplWmiTraceEvent: FAILED to log WMI Trace Event No Memory JobId:%u Type:%u\n",
JobId, (ULONG) EventTraceType));
}
else if (Status != ERROR_SUCCESS) {
DBGMSG(DBG_TRACE, ("SplWmiTraceEvent: FAILED to log WMI Trace Event JobId:%u Type:%u Status:%u\n",
JobId, (ULONG) EventTraceType, Status));
}
return Status;
}
/*++
Routine Name:
SplWmiControlCallback()
Routine Description:
This is the function we provite to the WMI subsystem as a callback, it is used to
start and stop the trace events.
Arguments:
IN WMIDPREQUESTCODE RequestCode : The function to provide (enable/disable)
IN PVOID Context : Not used by us.
IN OUT ULONG *InOutBufferSize : The Buffersize
IN OUT PVOID Buffer : The buffer to use for the events
Returns ERROR_SUCCESS on success, or an error code.
--*/
ULONG
WmiControlCallback(
IN WMIDPREQUESTCODE RequestCode,
IN PVOID Context,
IN OUT ULONG *InOutBufferSize,
IN OUT PVOID Buffer
)
{
ULONG Status;
if (!bWmiIsInitialized) {
DBGMSG(DBG_TRACE, ("SplWmiControlCallback: SPOOLER WMI NOT INITIALIZED.\n"));
return ERROR_GEN_FAILURE;
}
Status = ERROR_SUCCESS;
switch (RequestCode)
{
case WMI_ENABLE_EVENTS:
{
WmiLoggerHandle = GetTraceLoggerHandle( Buffer );
ulWmiEnableLevel = GetTraceEnableLevel( WmiLoggerHandle );
InterlockedExchange(&bWmiTraceOnFlag, TRUE);
DBGMSG(DBG_TRACE, ("SplWmiControlCallback: SPOOLER WMI ENABLED LEVEL %u.\n",
ulWmiEnableLevel));
break;
}
case WMI_DISABLE_EVENTS:
{
DBGMSG(DBG_TRACE, ("SplWmiControlCallback: SPOOLER WMI DISABLED.\n"));
InterlockedExchange(&bWmiTraceOnFlag, FALSE);
WmiLoggerHandle = 0;
break;
}
default:
{
Status = ERROR_INVALID_PARAMETER;
break;
}
}
*InOutBufferSize = 0;
return(Status);
}