|
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
tracedp.c
Abstract:
Sample trace provider program.
// end_sdk
Author:
Jee Fung Pang (jeepang) 03-Dec-1997
Revision History:
Insung Park (insungp) 18-Jan-2001
Modified tracedp so that when tracedp generates User Mof Events with some sample strings, integers, floats, and arrays.
// begin_sdk
--*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <shellapi.h>
#include <tchar.h>
#include <wmistr.h>
#include <guiddef.h>
#include <evntrace.h>
#define MAXEVENTS 5000
#define MAXSTR 1024
#define MAXTHREADS 128
// sample string data
#define WIDE_DATA_STRING L"Sample Wide String"
#define COUNTED_DATA_STRING L"Sample Counted String"
TRACEHANDLE LoggerHandle; #define ResourceName _T("MofResource")
TCHAR ImagePath[MAXSTR];
GUID TransactionGuid = {0xce5b1020, 0x8ea9, 0x11d0, 0xa4, 0xec, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10}; GUID ControlGuid[2] = { {0xd58c126f, 0xb309, 0x11d1, 0x96, 0x9e, 0x00, 0x00, 0xf8, 0x75, 0xa5, 0xbc}, {0x7c6a708a, 0xba1e, 0x11d2, 0x8b, 0xbf, 0x00, 0x00, 0xf8, 0x06, 0xef, 0xe0} };
TRACE_GUID_REGISTRATION TraceGuidReg[] = { { (LPGUID)&TransactionGuid, NULL } };
typedef enum { TYPE_USER_EVENT, TYPE_INSTANCE_EVENT, TYPE_MOF_EVENT, TYPEPTR_GUID } TypeEventType;
typedef struct _USER_EVENT { EVENT_TRACE_HEADER Header; ULONG EventInfo; } USER_EVENT, *PUSER_EVENT;
typedef struct _USER_INSTANCE_EVENT { EVENT_INSTANCE_HEADER Header; ULONG mofData; } USER_INSTANCE_EVENT, *PUSER_INSTANCE_EVENT;
// customized event to use sample data that follow
typedef struct _USER_MOF_EVENT { EVENT_TRACE_HEADER Header; MOF_FIELD mofData; } USER_MOF_EVENT, *PUSER_MOF_EVENT;
// sample data structure
typedef struct _INTEGER_SAMPLE_EVENT { CHAR sc; UCHAR uc; SHORT sh; ULONG ul; } INTEGER_SAMPLE_EVENT, *PINTEGER_SAMPLE_EVENT;
typedef struct _FLOAT_SAMPLE_EVENT { float fl; double db; } FLOAT_SAMPLE_EVENT, *PFLOAT_SAMPLE_EVENT;
typedef struct _ARRAY_SAMPLE_EVENT { CHAR ca[9]; } ARRAY_SAMPLE_EVENT, *PARRAY_SAMPLE_EVENT;
TypeEventType EventType = TYPE_USER_EVENT; TRACEHANDLE RegistrationHandle[2]; BOOLEAN TraceOnFlag; ULONG EnableLevel = 0; ULONG EnableFlags = 0; BOOLEAN bPersistData = FALSE; ULONG nSleepTime = 0; ULONG EventCount = 0;
BOOLEAN bInstanceTrace=0, bUseGuidPtr=0, bUseMofPtr=0; BOOLEAN bIncorrect = FALSE; BOOLEAN bUseNullPtr = FALSE; BOOLEAN bFirstTime = TRUE;
ULONG InitializeTrace( void );
ULONG ControlCallback( IN WMIDPREQUESTCODE RequestCode, IN PVOID Context, IN OUT ULONG *InOutBufferSize, IN OUT PVOID Buffer );
LPTSTR DecodeStatus( IN ULONG Status, TCHAR *ErrorMsg, IN ULONG StringSize );
void LogProc();
ULONG ahextoi( IN TCHAR *s ); void StringToGuid( TCHAR *str, LPGUID guid );
ULONG MaxEvents = MAXEVENTS; ULONG gnMultiReg = 1;
ULONG ahextoi( IN TCHAR *s ) /*++
Routine Description:
Converts a hex string into a number.
Arguments:
s - A hex string in TCHAR.
Return Value:
ULONG - The number in the string.
--*/ { int len; ULONG num, base, hex;
len = _tcslen(s); hex = 0; base = 1; num = 0; while (--len >= 0) { if ( (s[len] == 'x' || s[len] == 'X') && (s[len-1] == '0') ) break; if (s[len] >= '0' && s[len] <= '9') num = s[len] - '0'; else if (s[len] >= 'a' && s[len] <= 'f') num = (s[len] - 'a') + 10; else if (s[len] >= 'A' && s[len] <= 'F') num = (s[len] - 'A') + 10; else continue;
hex += num * base; base = base * 16; } return hex; }
void StringToGuid( TCHAR *str, LPGUID guid ) /*++
Routine Description:
Converts a String into a GUID.
Arguments:
str - String representing a GUID. guid - Pointer to a GUID for ourput
Return Value:
None.
--*/ { TCHAR temp[10]; int i, n;
_tcsncpy(temp, str, 8); temp[8] = 0; guid->Data1 = ahextoi(temp); _tcsncpy(temp, &str[9], 4); temp[4] = 0; guid->Data2 = (USHORT) ahextoi(temp); _tcsncpy(temp, &str[14], 4); temp[4] = 0; guid->Data3 = (USHORT) ahextoi(temp);
for (i=0; i<2; i++) { _tcsncpy(temp, &str[19 + (i*2)], 2); temp[2] = 0; guid->Data4[i] = (UCHAR) ahextoi(temp); } for (i=2; i<8; i++) { _tcsncpy(temp, &str[20 + (i*2)], 2); temp[2] = 0; guid->Data4[i] = (UCHAR) ahextoi(temp); } }
__cdecl main(argc, argv) int argc; char **argv; /*++
Routine Description:
main() routine.
Arguments:
Usage: TraceDp [options] [number of events] -UseEventTraceHeader this is default. -UseEventInstanceHeader -UseMofPtrFlag -Thread [n] Sets the number of event-generating threads. -GuidPtr Use GUID pointer instead of GUID itself. -MofPtr Use MOF pointer for additional data. -GuidPtrMofPtr User GUID pointer and MOF pointer. -InCorrectMofPtr Use incorrect MOF pointer (Creates an error case). -NullMofPtr Use NULL MOF pointer (Creates an error case). -MultiReg Register multiple event GUIDS. -Sleep [n] Sets the sleep time before unregistering. [number of events] default is 5000
Return Value:
Error Code defined in winerror.h : If the function succeeds, it returns ERROR_SUCCESS (== 0).
--*/ { ULONG Status; LPGUID Guid = NULL; DWORD ThreadId; HANDLE hThreadVector[MAXTHREADS]; ULONG i; ULONG nThreads = 1; LPTSTR *targv, *utargv = NULL;
MaxEvents = MAXEVENTS; TraceOnFlag = FALSE;
#ifdef UNICODE
if ((targv = CommandLineToArgvW( GetCommandLineW(), // pointer to a command-line string
&argc // receives the argument count
)) == NULL) { return(GetLastError()); }; utargv = targv; #else
targv = argv; #endif
// process command line arguments to override defaults
//
while (--argc > 0) { targv ++; if (**targv == '-' || **targv == '/') { if(targv[0][0] == '/' ) targv[0][0] = '-'; if (!_tcsicmp(targv[0],_T("-UseEventTraceHeader"))) { EventType = TYPE_USER_EVENT; } else if (!_tcsicmp(targv[0],_T("-UseEventInstanceHeader"))) { EventType = TYPE_INSTANCE_EVENT; } else if (!_tcsicmp(targv[0],_T("-UseMofPtrFlag"))) { EventType = TYPE_MOF_EVENT; } // end_sdk
else if (!_tcsicmp(targv[0],_T("-Persist"))) { bPersistData = TRUE; } // begin_sdk
else if (!_tcsicmp(targv[0],_T("-Thread"))) { if (argc > 1) { targv++; --argc; nThreads = _ttoi(targv[0]); if (nThreads > MAXTHREADS) nThreads = MAXTHREADS; } } else if (!_tcsicmp(targv[0],_T("-GuidPtr"))) { bUseGuidPtr = TRUE; } else if (!_tcsicmp(targv[0],_T("-MofPtr"))) { bUseMofPtr = TRUE; } else if (!_tcsicmp(targv[0],_T("-GuidPtrMofPtr"))) { bUseGuidPtr = TRUE; bUseMofPtr = TRUE; } else if (!_tcsicmp(targv[0],_T("-InCorrectMofPtr"))) { bUseMofPtr = TRUE; bIncorrect = TRUE; } else if (!_tcsicmp(targv[0],_T("-NullMofPtr"))) { bUseMofPtr = TRUE; bUseNullPtr = TRUE; bIncorrect = TRUE;; } else if (!_tcsicmp(targv[0],_T("-MultiReg"))) { gnMultiReg = 2; } else if (!_tcsicmp(targv[0], _T("-Guid"))) { if (argc > 1) { if (targv[1][0] == _T('#')) { StringToGuid(&targv[1][1], &ControlGuid[0]); ++targv; --argc; } } } else if (!_tcsicmp(targv[0],_T("-Sleep"))) { if (argc > 1) { targv++; --argc; nSleepTime = _ttoi(targv[0]); } } else { printf("Usage: TraceDp [options] [number of events]\n"); printf("\t-UseEventTraceHeader this is default.\n"); printf("\t-UseEventInstanceHeader\n"); printf("\t-UseMofPtrFlag\n"); printf("\t-Thread [n]\n"); printf("\t-GuidPtr\n"); printf("\t-MofPtr\n"); printf("\t-GuidPtrMofPtr\n"); printf("\t-InCorrectMofPtr\n"); printf("\t-NullMofPtr\n"); printf("\t-MultiReg\n"); printf("\t-Guid #[guid] alternative control GUID\n"); printf("\t-Sleep [n]\n"); printf("\t[number of events] default is 5000\n");
return 0; } } else if (** targv >= '0' && ** targv <= '9') { MaxEvents = _ttoi(targv[0]); } }
if (utargv != NULL) { GlobalFree(utargv); }
Status = InitializeTrace(); if (Status != ERROR_SUCCESS) { return Status; }
_tprintf(_T("Testing Logger with %d events (%d,%d)\n"), MaxEvents, EventType, bPersistData);
while (! TraceOnFlag) _sleep(1000);
for (i=0; i < nThreads; i++) { hThreadVector[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) LogProc, NULL, 0, (LPDWORD)&ThreadId); }
WaitForMultipleObjects(nThreads, hThreadVector, TRUE, INFINITE);
if (nSleepTime > 0) { _sleep(nSleepTime * 1000); }
for (i=0; i<gnMultiReg; i++) { UnregisterTraceGuids(RegistrationHandle[i]); }
return ERROR_SUCCESS; }
LPTSTR DecodeStatus( IN ULONG Status, IN OUT TCHAR *ErrorMsg, IN ULONG StringSize ) /*++
Routine Description:
Decodes error status.
Arguments:
Status - Return status of function calls to be decoded.
Return Value:
Pointer to a decoded error message.
--*/ { RtlZeroMemory(ErrorMsg, (StringSize * sizeof(TCHAR))); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) ErrorMsg, StringSize, NULL ); return ErrorMsg; }
ULONG InitializeTrace( void ) /*++
Routine Description:
Register traces.
Arguments:
Return Value:
Error Status. ERROR_SUCCESS if successful.
--*/ { ULONG Status; ULONG i, j;
if (!GetModuleFileName(NULL, ImagePath, MAXSTR)) { return (ERROR_FILE_NOT_FOUND); }
for (i=0; i<gnMultiReg; i++) {
Status = RegisterTraceGuids( (WMIDPREQUEST)ControlCallback, //use same callback function
(PVOID)(INT_PTR)(0x12345678+i), // RequestContext
(LPCGUID)&ControlGuid[i], 1, &TraceGuidReg[i], (LPCTSTR)&ImagePath[0], (LPCTSTR)ResourceName, &RegistrationHandle[i] );
if (Status != ERROR_SUCCESS) { TCHAR ErrorMsg[MAXSTR];
_tprintf(_T("Trace registration failed\n")); if( i > 0) { for (j=0; j<i; j++) { UnregisterTraceGuids(RegistrationHandle[j]); } } _tprintf(_T("InitializeTrace failed. i=%d, status=%d, %s\n"), i, Status, DecodeStatus(Status, ErrorMsg, MAXSTR)); return(Status); } else { _tprintf(_T("Trace registered successfully\n")); } }
return(Status); }
ULONG ControlCallback( IN WMIDPREQUESTCODE RequestCode, IN PVOID Context, IN OUT ULONG *InOutBufferSize, IN OUT PVOID Buffer ) /*++
Routine Description:
Callback function when enabled.
Arguments:
RequestCode - Flag for either enable or disable. Context - User-defined context. InOutBufferSize - not used. Buffer - WNODE_HEADER for the logger session.
Return Value:
Error Status. ERROR_SUCCESS if successful.
--*/ { ULONG Status; ULONG RetSize;
Status = ERROR_SUCCESS;
switch (RequestCode) { case WMI_ENABLE_EVENTS: { RetSize = 0; LoggerHandle = GetTraceLoggerHandle( Buffer ); EnableLevel = GetTraceEnableLevel(LoggerHandle); EnableFlags = GetTraceEnableFlags(LoggerHandle); _tprintf(_T("Logging enabled to 0x%016I64x(%d,%d,%d)\n"), LoggerHandle, RequestCode, EnableLevel, EnableFlags); TraceOnFlag = TRUE; break; } case WMI_DISABLE_EVENTS: { TraceOnFlag = FALSE; RetSize = 0; LoggerHandle = 0; _tprintf(_T("\nLogging Disabled\n")); break; } default: { RetSize = 0; Status = ERROR_INVALID_PARAMETER; break; }
}
*InOutBufferSize = RetSize; return(Status); }
void LogProc() /*++
Routine Description:
Generates events. It is spawned as separate threads. Based on the options given by users, it generates different events.
Arguments:
Return Value:
None.
--*/ { USER_EVENT UserEvent; USER_INSTANCE_EVENT UserInstanceEvent; USER_MOF_EVENT UserMofEvent; EVENT_INSTANCE_INFO InstInfo; PMOF_FIELD mofField; ULONG i; PWNODE_HEADER Wnode; ULONG status; ULONG InstanceId; LPGUID Guid = NULL; ULONG nTemp; USHORT nSize, nStrEventSize; WCHAR wstrTemp[MAXSTR];
INTEGER_SAMPLE_EVENT ise; FLOAT_SAMPLE_EVENT fse; ARRAY_SAMPLE_EVENT ase; CHAR *sse, *ptr;
// some arbitrary data for MOF structs
ise.sc = 'x'; ise.uc = 'y'; ise.sh = (SHORT)rand(); ise.ul = (ULONG)rand();
nTemp = 0; while (nTemp == 0) { nTemp = rand(); }
fse.fl = ((float)rand() / (float)nTemp); fse.db = ((double)rand() / (double)nTemp);
ase.ca[0] = 'M'; ase.ca[1] = 'i'; ase.ca[2] = 'c'; ase.ca[3] = 'r'; ase.ca[4] = 'o'; ase.ca[5] = 's'; ase.ca[6] = 'o'; ase.ca[7] = 'f'; ase.ca[8] = 't';
nStrEventSize = ((wcslen(WIDE_DATA_STRING) + 1) * sizeof(WCHAR)) + sizeof(SHORT) + (wcslen(COUNTED_DATA_STRING) * sizeof(WCHAR)); sse = (PCHAR) malloc(nStrEventSize);
if (NULL != sse) { ptr = sse; wcscpy(wstrTemp, WIDE_DATA_STRING); wstrTemp[wcslen(WIDE_DATA_STRING)] = L'\0'; memcpy(ptr, wstrTemp, (wcslen(WIDE_DATA_STRING) + 1) * sizeof(WCHAR)); ptr += (wcslen(WIDE_DATA_STRING) + 1) * sizeof(WCHAR); nSize = (USHORT)(wcslen(COUNTED_DATA_STRING) * sizeof(WCHAR)); memcpy(ptr, &nSize, sizeof(USHORT)); ptr += sizeof(USHORT); wcscpy(wstrTemp, COUNTED_DATA_STRING); memcpy(ptr, wstrTemp, wcslen(COUNTED_DATA_STRING) * sizeof(WCHAR)); }
RtlZeroMemory(&UserEvent, sizeof(UserEvent)); Wnode = (PWNODE_HEADER) &UserEvent; UserEvent.Header.Size = sizeof(USER_EVENT); UserEvent.Header.Flags = WNODE_FLAG_TRACED_GUID; UserEvent.Header.Guid = TransactionGuid; if (bPersistData) UserEvent.Header.Flags |= WNODE_FLAG_PERSIST_EVENT;
RtlZeroMemory(&UserInstanceEvent, sizeof(UserInstanceEvent)); UserInstanceEvent.Header.Size = sizeof(UserInstanceEvent); UserInstanceEvent.Header.Flags = WNODE_FLAG_TRACED_GUID; if (bPersistData) UserInstanceEvent.Header.Flags |= WNODE_FLAG_PERSIST_EVENT;
RtlZeroMemory(&UserMofEvent, sizeof(UserMofEvent)); Wnode = (PWNODE_HEADER) &UserMofEvent; UserMofEvent.Header.Size = sizeof(UserMofEvent); UserMofEvent.Header.Flags = WNODE_FLAG_TRACED_GUID; UserMofEvent.Header.Guid = TransactionGuid; // end_sdk
if (bPersistData) UserMofEvent.Header.Flags |= WNODE_FLAG_PERSIST_EVENT; // begin_sdk
if (bUseGuidPtr) { UserEvent.Header.Flags |= WNODE_FLAG_USE_GUID_PTR; UserEvent.Header.GuidPtr = (ULONGLONG)&TransactionGuid; UserMofEvent.Header.Flags |= WNODE_FLAG_USE_GUID_PTR; UserMofEvent.Header.GuidPtr = (ULONGLONG)&TransactionGuid; }
i = 0; while (TraceOnFlag) { if ((i % 4) == 0) { UserEvent.Header.Class.Type = EVENT_TRACE_TYPE_START; UserInstanceEvent.Header.Class.Type = EVENT_TRACE_TYPE_START; UserMofEvent.Header.Class.Type = 3; } else if ((i % 4) == 1) { UserEvent.Header.Class.Type = EVENT_TRACE_TYPE_END; UserInstanceEvent.Header.Class.Type = EVENT_TRACE_TYPE_END; UserMofEvent.Header.Class.Type = 4; } else if ((i % 4) == 2) { UserEvent.Header.Class.Type = EVENT_TRACE_TYPE_START; UserInstanceEvent.Header.Class.Type = EVENT_TRACE_TYPE_START; UserMofEvent.Header.Class.Type = 5; } else { UserEvent.Header.Class.Type = EVENT_TRACE_TYPE_END; UserInstanceEvent.Header.Class.Type = EVENT_TRACE_TYPE_END; UserMofEvent.Header.Class.Type = 6; }
switch (EventType) { case TYPE_INSTANCE_EVENT: if (UserInstanceEvent.Header.Class.Type == EVENT_TRACE_TYPE_START) { status = CreateTraceInstanceId( (PVOID) TraceGuidReg[0].RegHandle, & InstInfo);
if (status != ERROR_SUCCESS) { TCHAR ErrorMsg[MAXSTR]; fprintf(stderr, "CreatTraceInstanceId() status=%d, %ws\n", status, DecodeStatus(status, ErrorMsg, MAXSTR) ); return; } } status = TraceEventInstance( LoggerHandle, (PEVENT_INSTANCE_HEADER) & UserInstanceEvent, & InstInfo, NULL); break;
case TYPE_USER_EVENT: UserEvent.EventInfo = InterlockedIncrement(&EventCount); status = TraceEvent( LoggerHandle, (PEVENT_TRACE_HEADER) & UserEvent); break;
case TYPE_MOF_EVENT: UserMofEvent.Header.Flags |= WNODE_FLAG_USE_MOF_PTR; mofField = (PMOF_FIELD) & UserMofEvent.mofData; if (UserMofEvent.Header.Class.Type == 4) { mofField->DataPtr = (ULONGLONG) (&ise); mofField->Length = sizeof(INTEGER_SAMPLE_EVENT); } else if (UserMofEvent.Header.Class.Type == 5) { mofField->DataPtr = (ULONGLONG) (&fse); mofField->Length = sizeof(FLOAT_SAMPLE_EVENT); } else if (UserMofEvent.Header.Class.Type == 6) { mofField->DataPtr = (ULONGLONG) (&ase); mofField->Length = sizeof(ARRAY_SAMPLE_EVENT); } else { mofField->DataPtr = (ULONGLONG) (sse); mofField->Length = nStrEventSize; } if (bUseNullPtr) mofField->DataPtr = (ULONGLONG) (NULL); if (bIncorrect) mofField->Length += 1000;
status = TraceEvent( LoggerHandle, (PEVENT_TRACE_HEADER) & UserMofEvent); if (status != ERROR_SUCCESS) { fprintf(stderr, "Error(%d) while writing event.\n", status); } break;
default: status = ERROR_SUCCESS; break; }
// logger buffers out of memory should not prevent provider from
// generating events. This will only cause events lost.
//
if (status == ERROR_NOT_ENOUGH_MEMORY) { status = ERROR_SUCCESS; }
if (status != ERROR_SUCCESS) { TCHAR ErrorMsg[MAXSTR]; _ftprintf(stderr, _T("\nError %s while writing event\n"), DecodeStatus(status, ErrorMsg, MAXSTR)); _ftprintf( stderr, _T("Logging terminated due to error\n")); free(sse); return; }
i++; if (i >= MaxEvents) break;
if (!(i % 100)) _tprintf(_T(".")); _sleep(1); }
free(sse); }
|