// begin_sdk /*++ Copyright (c) 1997-1999 Microsoft Corporation Module Name: tracelog.c Abstract: Sample trace control program. Allows user to start, stop event tracing // end_sdk Author: Jee Fung Pang (jeepang) 03-Dec-1997 Revision History: Insung Park (insungp) 28-Nov-2000 Now tracelog can be used to set the registry keys to start or stop GlobalLogger. Other options also works except a few (such as -enable). e.g. tracelog -start GlobalLogger tracelog -stop GlobalLogger tracelog -q GlobalLogger However, "-start" option does not start GlobalLogger immediately. The machine must be rebooted. "-stop" option resets the registry keys and stop GlobalLogger. Users can use other options to customize the GlobalLogger sessions such as minimum and maximum buffers, buffer size, flush timer, and so on. One catch is, if any of the enable flags is set, GlobalLogger turns into NT Kernel Logger and its instance vanishes. Any attempt to access GlobalLogger with its name will fail with ERROR_WMI_INSTANCE_NOT_FOUND. "-stop" option will still reset registry keys so that the next time the machine boots GlobalLogger will not start. If any of the flags is set, users should access NT Kernel Logger to control it. Modified/updated functions include GetGlobalLoggerSettings, SetGlobalLoggerSettings, main, PrintLoggerStatus. Insung Park (insungp) 19-Dec-2000 Changed trace function calls so that tracelog can be used on Win2K. FlushTrace and EnumTraceGuids are not implemented on Win2K, but they do not stop the execution of tracelog. An attempt to use FlushTrace or EnumTraceGuids on W2K will generate an error message. Fixed "-flags -1" bug. tracelog does not accept any flag with MSB=1. Insung Park (insungp) 21-Dec-2000 Added a version display. Fixed PrintHelpMessage() so that options not available on Win2K will not be printed. ("-paged", "-flush", "-enumguid", "-append", "-newfile", "-eflag", "-ls", "-gs") Cleaned up the if blocks in main() so that tracelog frees allocated space properly before exiting regardless of error status. // begin_sdk --*/ #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #include #include // end_sdk #include #include #include // begin_sdk #include #include #include #include #include #include #include #include // end_sdk #include // begin_sdk #define MAXSTR 1024 #define DEFAULT_LOGFILE_NAME _T("C:\\LogFile.Etl") // end_sdk #define GLOBAL_LOGGER _T("GlobalLogger") #define EVENT_LOGGER _T("WMI Event Logger") #define MAXENABLEFLAGS 10 // begin_sdk #define MAXIMUM_LOGGERS_W2K 32 #define MAXIMUM_LOGGERS_XP 64 #define MAXGUIDS 128 #define ACTION_QUERY 0 #define ACTION_START 1 #define ACTION_STOP 2 #define ACTION_UPDATE 3 #define ACTION_LIST 4 #define ACTION_ENABLE 5 #define ACTION_HELP 6 #define ACTION_FLUSH 7 #define ACTION_ENUM_GUID 8 // end_sdk #define ACTION_REMOVE 9 // begin_sdk #define ACTION_UNDEFINED 10 #define IsEqualGUID(rguid1, rguid2) (!memcmp(rguid1, rguid2, sizeof(GUID))) #define WSTRSIZE(str) (ULONG) ( (str) ? ((PCHAR) &str[wcslen(str)] - (PCHAR)str) + sizeof(UNICODE_NULL) : 0 ) // Functions not implemented on Win2K need to be searched and loaded separately. // To make further accesses easy, an array of function pointers will be used. // The following list serves as indices to that array. // // If new functions are added to evntrace.h, the following list should be updated // as well as the array initialization routine at the beginning of main(). #define FUNC_FLUSH_TRACE 0 #define FUNC_ENUM_TRACE_GUIDS 1 // Funtion pointer array for unimplemented functions on Win2K. // Note: This may not work if this code is ported to C++, because // all the function pointers may be typedefed differently. #define MAXFUNC 10 FARPROC FuncArray[MAXFUNC]; HINSTANCE advapidll; BOOLEAN XP; //keep track of whether or not the kernel debugging option has been turned on to assure the buffer size is no greater than 3 kb BOOLEAN kdOn = FALSE; void PrintLoggerStatus( IN PEVENT_TRACE_PROPERTIES LoggerInfo, // end_sdk IN ULONG GlobalLoggerStartValue, // begin_sdk IN ULONG Status, IN BOOL PrintStatus ); #define PRINTSTATUS TRUE #define NOPRINTSTATUS FALSE LPTSTR DecodeStatus( IN ULONG Status ); LONG GetGuids( IN LPTSTR GuidFile, OUT LPGUID *GuidArray ); ULONG ahextoi( IN TCHAR *s ); void StringToGuid( IN TCHAR *str, OUT LPGUID guid ); PTCHAR GuidToString( IN OUT PTCHAR s, IN LPGUID piid ); TCHAR ErrorMsg[MAXSTR]; void PrintHelpMessage(); // end_sdk ULONG SetGlobalLoggerSettings( IN DWORD StartValue, IN PEVENT_TRACE_PROPERTIES LoggerInfo, IN DWORD ClockType ); ULONG GetGlobalLoggerSettings( IN OUT PEVENT_TRACE_PROPERTIES LoggerInfo, OUT PULONG ClockType, OUT PDWORD pdwStart ); // begin_sdk // // main function // __cdecl main(argc, argv) int argc; char **argv; /*++ Routine Description: It is the main function. Arguments: Return Value: Error Code defined in winerror.h : If the function succeeds, it returns ERROR_SUCCESS (== 0). --*/{ ULONG i, j; LONG GuidCount; USHORT Action = ACTION_UNDEFINED; ULONG Status = 0; LPTSTR LoggerName; LPTSTR LogFileName; TCHAR GuidFile[MAXSTR]; PEVENT_TRACE_PROPERTIES pLoggerInfo; TRACEHANDLE LoggerHandle = 0; LPTSTR *targv, *utargv = NULL; LPGUID *GuidArray; char *Space; char *save; BOOL bKill = FALSE; BOOL bForceKill = FALSE ; BOOL bEnable = TRUE; ULONG iLevel = 0; ULONG iFlags = 0; ULONG SizeNeeded = 0; ULONG specialLogger = 0; ULONG GlobalLoggerStartValue = 0; PULONG pFlags = NULL; BOOL bProcess = TRUE; BOOL bThread = TRUE; BOOL bDisk = TRUE; BOOL bNetwork = TRUE; OSVERSIONINFO OSVersion; OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); XP = FALSE; if (GetVersionEx(&OSVersion)) { XP = (OSVersion.dwMajorVersion > 5) || ((OSVersion.dwMajorVersion == 5) && (OSVersion.dwMinorVersion > 0)); } // Load functions that are not implemented on Win2K for (i = 0; i < MAXFUNC; ++i) FuncArray[i] = NULL; if (XP) { advapidll = LoadLibrary(_T("advapi32.dll")); if (advapidll != NULL) { #ifdef UNICODE FuncArray[FUNC_FLUSH_TRACE] = GetProcAddress(advapidll, "FlushTraceW"); #else FuncArray[FUNC_FLUSH_TRACE] = GetProcAddress(advapidll, "FlushTraceA"); #endif FuncArray[FUNC_ENUM_TRACE_GUIDS] = GetProcAddress(advapidll, "EnumerateTraceGuids"); } } // Initialize structure first SizeNeeded = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR); // end_sdk SizeNeeded += MAXENABLEFLAGS * sizeof(ULONG); // for extension enable flags // begin_sdk pLoggerInfo = (PEVENT_TRACE_PROPERTIES) malloc(SizeNeeded); if (pLoggerInfo == NULL) { if (advapidll != NULL) FreeLibrary(advapidll); return (ERROR_OUTOFMEMORY); } RtlZeroMemory(pLoggerInfo, SizeNeeded); pLoggerInfo->Wnode.BufferSize = SizeNeeded; pLoggerInfo->Wnode.Flags = WNODE_FLAG_TRACED_GUID; pLoggerInfo->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); pLoggerInfo->LogFileNameOffset = pLoggerInfo->LoggerNameOffset + MAXSTR * sizeof(TCHAR); LoggerName = (LPTSTR)((char*)pLoggerInfo + pLoggerInfo->LoggerNameOffset); LogFileName = (LPTSTR)((char*)pLoggerInfo + pLoggerInfo->LogFileNameOffset); _tcscpy(LoggerName, KERNEL_LOGGER_NAME); Space = (char*) malloc( (MAXGUIDS * sizeof(GuidArray)) + (MAXGUIDS * sizeof(GUID) )); if (Space == NULL) { free(pLoggerInfo); if (advapidll != NULL) FreeLibrary(advapidll); return(ERROR_OUTOFMEMORY); } save = Space; GuidArray = (LPGUID *) Space; Space += MAXGUIDS * sizeof(GuidArray); for (GuidCount=0; GuidCountEnableFlags; // // Add default flags. Should consider options to control this independently // while (--argc > 0) { ++targv; if (**targv == '-' || **targv == '/') { // argument found if(targv[0][0] == '/' ) targv[0][0] = '-'; if (!_tcsicmp(targv[0], _T("-start"))) { Action = ACTION_START; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-enable"))) { Action = ACTION_ENABLE; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-disable"))) { Action = ACTION_ENABLE; bEnable = FALSE; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-stop"))) { Action = ACTION_STOP; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-update"))) { Action = ACTION_UPDATE; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } // end_sdk else if (!_tcsicmp(targv[0], _T("-remove"))) { Action = ACTION_REMOVE; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } // if it is not GlobalLogger, nothing happens. } // begin_sdk else if (!_tcsicmp(targv[0], _T("-q"))) { Action = ACTION_QUERY; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-flush"))) { Action = ACTION_FLUSH; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-enumguid"))) { Action = ACTION_ENUM_GUID; } else if (!_tcsicmp(targv[0], _T("-f"))) { if (argc > 1) { if (XP) _tcscpy(LogFileName, targv[1]); else _tfullpath(LogFileName, targv[1], MAXSTR); ++targv; --argc; // _tprintf(_T("Setting log file to: %s\n"), LogFileName); } } else if (!_tcsicmp(targv[0], _T("-append"))) { // _tprintf(_T("Appending log file: %s\n"), LogFileName); pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_APPEND; } else if (!_tcsicmp(targv[0], _T("-prealloc"))) { // _tprintf(_T("Preallocating log file: %s\n"), LogFileName); pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_PREALLOCATE; } else if (!_tcsicmp(targv[0], _T("-kb"))) { // _tprintf(_T("Using KBytes for maximum file size\n")); pLoggerInfo->LogFileMode |= EVENT_TRACE_USE_KBYTES_FOR_SIZE; } else if (!_tcsicmp(targv[0], _T("-guid"))) { if (argc > 1) { if (targv[1][0] == _T('#')) { StringToGuid(&targv[1][1], GuidArray[0]); ++targv; --argc; GuidCount = 1; } else if (targv[1][0] != '-' && targv[1][0] != '/') { _tfullpath(GuidFile, targv[1], MAXSTR); ++targv; --argc; // _tprintf(_T("Getting guids from %s\n"), GuidFile); GuidCount = GetGuids(GuidFile, GuidArray); if (GuidCount < 0) { _tprintf( _T("Error: %s does no exist\n"), GuidFile ); } else if (GuidCount == 0){ _tprintf( _T("Error: %s is invalid\n"), GuidFile ); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } } } } // end_sdk else if (!_tcsicmp(targv[0], _T("-UsePerfCounter"))) { pLoggerInfo->Wnode.ClientContext = 1; } else if (!_tcsicmp(targv[0], _T("-UseSystemTime"))) { pLoggerInfo->Wnode.ClientContext = 2; } else if (!_tcsicmp(targv[0], _T("-UseCPUCycle"))) { pLoggerInfo->Wnode.ClientContext = 3; } // begin_sdk else if (!_tcsicmp(targv[0], _T("-seq"))) { if (argc > 1) { pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_SEQUENTIAL; pLoggerInfo->MaximumFileSize = _ttoi(targv[1]); ++targv; --argc; // _tprintf(_T("Setting maximum sequential logfile size to: %d\n"), // pLoggerInfo->MaximumFileSize); } } else if (!_tcsicmp(targv[0], _T("-newfile"))) { if (argc > 1) { pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_NEWFILE; pLoggerInfo->MaximumFileSize = _ttoi(targv[1]); ++targv; --argc; // _tprintf(_T("Setting maximum logfile size to: %d\n"), // pLoggerInfo->MaximumFileSize); } } else if (!_tcsicmp(targv[0], _T("-cir"))) { if (argc > 1) { pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_CIRCULAR; pLoggerInfo->MaximumFileSize = _ttoi(targv[1]); ++targv; --argc; // _tprintf(_T("Setting maximum circular logfile size to: %d\n"), // pLoggerInfo->MaximumFileSize); } } else if (!_tcsicmp(targv[0], _T("-b"))) { if (argc > 1) { ULONG ulSize = _ttoi(targv[1]); if (kdOn && ulSize > 3) { _tprintf(_T("Kernel Debugging has been enabled: Buffer size has been set to 3kBytes\n")); ulSize = 3; } pLoggerInfo->BufferSize = ulSize; ++targv; --argc; // _tprintf(_T("Changing buffer size to %d\n"), // pLoggerInfo->BufferSize); } } else if (!_tcsicmp(targv[0], _T("-flag")) || !_tcsicmp(targv[0], _T("-flags"))) { if (argc > 1) { if (targv[1][1] == _T('x') || targv[1][1] == _T('X')) { pLoggerInfo->EnableFlags |= ahextoi(targv[1]); } else { pLoggerInfo->EnableFlags |= _ttoi(targv[1]); } iFlags = pLoggerInfo->EnableFlags ; // Copy for EnableTrace ++targv; --argc; // Do not accept flags with MSB = 1. if (0x80000000 & pLoggerInfo->EnableFlags) { _tprintf(_T("Invalid Flags: 0x%0X(%d.)\n"), pLoggerInfo->EnableFlags, pLoggerInfo->EnableFlags); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } // _tprintf(_T("Setting logger flags to 0x%0X(%d.)\n"), // pLoggerInfo->EnableFlags, pLoggerInfo->EnableFlags ); } } // end_sdk else if (!_tcsicmp(targv[0], _T("-eflag"))) { if (argc > 2) { USHORT nFlag = (USHORT) _ttoi(targv[1]); USHORT offset; PTRACE_ENABLE_FLAG_EXTENSION FlagExt; ++targv; --argc; if (nFlag > MAXENABLEFLAGS || nFlag < 1) { _tprintf(_T("Error: Invalid number of enable flags\n")); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } offset = (USHORT) (SizeNeeded - (sizeof(ULONG) * MAXENABLEFLAGS)); pLoggerInfo->EnableFlags = EVENT_TRACE_FLAG_EXTENSION; FlagExt = (PTRACE_ENABLE_FLAG_EXTENSION) &pLoggerInfo->EnableFlags; FlagExt->Offset = offset; FlagExt->Length = (UCHAR) nFlag; pFlags = (PULONG) ( offset + (PCHAR) pLoggerInfo ); for (i=0; i 1; i++) { if (targv[1][0] == '/' || targv[1][0] == '-') { // Correct the number of eflags when the user // types an incorrect number. // However, this does not work if the next // argument is Logger Name. break; } pFlags[i] = ahextoi(targv[1]); ++targv; --argc; // _tprintf(_T("Setting logger flags to 0x%0X(%d.)\n"), // pFlags[i], pFlags[i] ); } nFlag = (USHORT)i; for ( ; i < MAXENABLEFLAGS; i++) { pFlags[i] = 0; } if (FlagExt->Length != (UCHAR)nFlag) { // _tprintf(_T("Correcting the number of eflags to %d\n"), i), FlagExt->Length = (UCHAR)nFlag; } } } else if (!_tcsicmp(targv[0], _T("-pids"))) { if (argc > 2) { USHORT nFlag = (USHORT) _ttoi(targv[1]); USHORT offset; PTRACE_ENABLE_FLAG_EXTENSION FlagExt; ++targv; --argc; if (nFlag > MAXENABLEFLAGS || nFlag < 1) { _tprintf(_T("Error: Invalid number of enable flags\n")); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } offset = (USHORT) (SizeNeeded - (sizeof(ULONG) * MAXENABLEFLAGS)); pLoggerInfo->EnableFlags = EVENT_TRACE_FLAG_EXTENSION; FlagExt = (PTRACE_ENABLE_FLAG_EXTENSION) &pLoggerInfo->EnableFlags; FlagExt->Offset = offset; FlagExt->Length = (UCHAR) nFlag; pFlags = (PULONG) ( offset + (PCHAR) pLoggerInfo ); for (i=0; i 1; i++) { if (targv[1][0] == '/' || targv[1][0] == '-') { // Correct the number of eflags when the user // types an incorrect number. // However, this does not work if the next // argument is Logger Name. break; } pFlags[i] = _ttol((PTCHAR)targv[1]); ++targv; --argc; // _tprintf(_T("Setting logger flags to 0x%0X(%d.)\n"), // pFlags[i], pFlags[i] ); } nFlag = (USHORT)i; for ( ; i < MAXENABLEFLAGS; i++) { pFlags[i] = 0; } if (FlagExt->Length != (UCHAR)nFlag) { // _tprintf(_T("Correcting the number of eflags to %d\n"), i), FlagExt->Length = (UCHAR)nFlag; } } } else if (!_tcsicmp(targv[0],_T("-heap"))) { GuidCount = 1; RtlCopyMemory(GuidArray[0], &HeapGuid, sizeof(HeapGuid)); pLoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE; } else if (!_tcsicmp(targv[0],_T("-critsec"))) { GuidCount = 1; RtlCopyMemory(GuidArray[0], &CritSecGuid, sizeof(CritSecGuid)); pLoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE; } else if (!_tcsicmp(targv[0],_T("-ls"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_USE_LOCAL_SEQUENCE ; } else if (!_tcsicmp(targv[0],_T("-gs"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_USE_GLOBAL_SEQUENCE ; } // begin_sdk else if (!_tcsicmp(targv[0], _T("-min"))) { if (argc > 1) { pLoggerInfo->MinimumBuffers = _ttoi(targv[1]); ++targv; --argc; // _tprintf(_T("Changing Minimum Number of Buffers to %d\n"), // pLoggerInfo->MinimumBuffers); } } else if (!_tcsicmp(targv[0], _T("-max"))) { if (argc > 1) { pLoggerInfo->MaximumBuffers = _ttoi(targv[1]); ++targv; --argc; // _tprintf(_T("Changing Maximum Number of Buffers to %d\n"), // pLoggerInfo->MaximumBuffers); } } else if (!_tcsicmp(targv[0], _T("-level"))) { if (argc > 1) { iLevel = _ttoi(targv[1]); ++targv; --argc; // _tprintf(_T("Setting tracing level to %d\n"), iLevel); } } else if (!_tcsicmp(targv[0], _T("-ft"))) { if (argc > 1) { pLoggerInfo->FlushTimer = _ttoi(targv[1]); ++targv; --argc; // _tprintf(_T("Setting buffer flush timer to %d seconds\n"), // pLoggerInfo->FlushTimer); } } else if (!_tcsicmp(targv[0], _T("-um"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE; // _tprintf(_T("Setting Private Logger Flags\n")); } else if (!_tcsicmp(targv[0], _T("-paged"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_USE_PAGED_MEMORY; // _tprintf(_T("Setting Paged Memory Flag\n")); } else if (!_tcsicmp(targv[0], _T("-rt"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_REAL_TIME_MODE; // _tprintf(_T("Setting real time mode\n")); // end_sdk if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; if (targv[0][0] == 'b') pLoggerInfo->LogFileMode |= EVENT_TRACE_BUFFERING_MODE; } } // begin_sdk } else if(!_tcsicmp(targv[0], _T("-kd"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_KD_FILTER_MODE; pLoggerInfo->BufferSize = 3; kdOn = TRUE; } else if (!_tcsicmp(targv[0], _T("-age"))) { if (argc > 1) { pLoggerInfo->AgeLimit = _ttoi(targv[1]); ++targv; --argc; // _tprintf(_T("Changing Aging Decay Time to %d\n"), // pLoggerInfo->AgeLimit); } } else if (!_tcsicmp(targv[0], _T("-l"))) { Action = ACTION_LIST; bKill = FALSE; } else if (!_tcsicmp(targv[0], _T("-x"))) { Action = ACTION_LIST; bKill = TRUE; } else if (!_tcsicmp(targv[0], _T("-xf"))) { Action = ACTION_LIST; bKill = TRUE; bForceKill = TRUE ; } else if (!_tcsicmp(targv[0], _T("-noprocess"))) { bProcess = FALSE; } else if (!_tcsicmp(targv[0], _T("-nothread"))) { bThread = FALSE; } else if (!_tcsicmp(targv[0], _T("-nodisk"))) { bDisk = FALSE; } else if (!_tcsicmp(targv[0], _T("-nonet"))) { bNetwork = FALSE; } else if (!_tcsicmp(targv[0], _T("-dbg"))) { //comment out for now until this functionality is supported /* if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_DBGPRINT; } */ } else if (!_tcsicmp(targv[0], _T("-ntsuccess"))){ //comment out for now until this functionality is supported /*if(pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_NTSUCCESS; } */ } else if (!_tcsicmp(targv[0], _T("-fio"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_DISK_FILE_IO; } else { _tprintf(_T("Option -fio cannot be used with -eflags. Ignored\n")); } } else if (!_tcsicmp(targv[0], _T("-pf"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS; } else { _tprintf(_T("Option -pf cannot be used with -eflags. Ignored\n")); } } else if (!_tcsicmp(targv[0], _T("-hf"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS; } else { _tprintf(_T("Option -hf cannot be used with -eflags. Ignored\n")); } } else if (!_tcsicmp(targv[0], _T("-img"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_IMAGE_LOAD; } else { _tprintf(_T("Option -img cannot be used with -eflags. Ignored\n")); } } else if (!_tcsicmp(targv[0], _T("-cm"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_REGISTRY; } else { _tprintf(_T("Option -cm cannot be used with -eflags. Ignored\n")); } } else if ( targv[0][1] == 'h' || targv[0][1] == 'H' || targv[0][1] == '?'){ Action = ACTION_HELP; PrintHelpMessage(); goto CleanupExit; } else Action = ACTION_UNDEFINED; } else { // get here if "-" or "/" given _tprintf(_T("Invalid option given: %s\n"), targv[0]); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } } if (!_tcscmp(LoggerName, KERNEL_LOGGER_NAME)) { if (pFlags == &pLoggerInfo->EnableFlags) { if (bProcess) *pFlags |= EVENT_TRACE_FLAG_PROCESS; if (bThread) *pFlags |= EVENT_TRACE_FLAG_THREAD; if (bDisk) *pFlags |= EVENT_TRACE_FLAG_DISK_IO; if (bNetwork) *pFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP; } pLoggerInfo->Wnode.Guid = SystemTraceControlGuid; // defaults to OS specialLogger = 1; } // end_sdk if (!_tcscmp(LoggerName, GLOBAL_LOGGER)) { pLoggerInfo->Wnode.Guid = GlobalLoggerGuid; specialLogger = 3; } else if (!_tcscmp(LoggerName, EVENT_LOGGER)) { pLoggerInfo->Wnode.Guid = WmiEventLoggerGuid; specialLogger = 2; } // begin_sdk if ( !(pLoggerInfo->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) ) { if (specialLogger != 3 && _tcslen(LogFileName) <= 0 && Action == ACTION_START) { _tcscpy(LogFileName, DEFAULT_LOGFILE_NAME); // for now... } } switch (Action) { case ACTION_START: { if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { if (GuidCount != 1) { _tprintf(_T("Need exactly one GUID for PRIVATE loggers\n")); Status = ERROR_INVALID_PARAMETER; break; } pLoggerInfo->Wnode.Guid = *GuidArray[0]; } if (pLoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_PREALLOCATE && pLoggerInfo->MaximumFileSize == 0) { _tprintf(_T("Need file size for preallocated log file\n")); Status = ERROR_INVALID_PARAMETER; break; } // end_sdk if (specialLogger == 3) { // Global Logger Status = SetGlobalLoggerSettings(1L, pLoggerInfo, pLoggerInfo->Wnode.ClientContext); if (Status != ERROR_SUCCESS) break; Status = GetGlobalLoggerSettings(pLoggerInfo, &pLoggerInfo->Wnode.ClientContext, &GlobalLoggerStartValue); break; } // begin_sdk if(pLoggerInfo->EnableFlags & EVENT_TRACE_FLAG_EXTENSION){ if(IsEqualGUID(&CritSecGuid,GuidArray[0]) || IsEqualGUID(&HeapGuid,GuidArray[0])){ pLoggerInfo->Wnode.HistoricalContext = 0x1000001; } } Status = StartTrace(&LoggerHandle, LoggerName, pLoggerInfo); if (Status != ERROR_SUCCESS) { _tprintf(_T("Could not start logger: %s\n") _T("Operation Status: %uL\n") _T("%s\n"), LoggerName, Status, DecodeStatus(Status)); break; } _tprintf(_T("Logger Started...\n")); case ACTION_ENABLE: if (Action == ACTION_ENABLE ){ if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { if (GuidCount != 1) { _tprintf(_T("Need one GUID for PRIVATE loggers\n")); Status = ERROR_INVALID_PARAMETER; break; } pLoggerInfo->Wnode.Guid = *GuidArray[0]; } Status = ControlTrace((TRACEHANDLE) 0, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY); if( Status != ERROR_SUCCESS ){ if( Status != ERROR_SUCCESS ){ if( IsEqualGUID(&HeapGuid,&pLoggerInfo->Wnode.Guid) || IsEqualGUID(&CritSecGuid,&pLoggerInfo->Wnode.Guid) ){ //do nothing } else { _tprintf( _T("ERROR: Logger not started\n") _T("Operation Status: %uL\n") _T("%s\n"), Status, DecodeStatus(Status)); break; } } } LoggerHandle = pLoggerInfo->Wnode.HistoricalContext; } if ( (GuidCount > 0) && (specialLogger == 0)) { _tprintf(_T("Enabling trace to logger %d\n"), LoggerHandle); for (i=0; i<(ULONG)GuidCount; i++) { Status = EnableTrace ( bEnable, iFlags, iLevel, GuidArray[i], LoggerHandle); // // If the Guid can not be enabled, it is a benign // failure. Print Warning message and continue. // if (Status == 4317) { _tprintf(_T("WARNING: Could not enable some guids.\n")); _tprintf(_T("Check your Guids file\n")); Status = ERROR_SUCCESS; } if (Status != ERROR_SUCCESS) { _tprintf(_T("ERROR: Failed to enable Guid [%d]...\n"), i); _tprintf(_T("Operation Status: %uL\n"), Status); _tprintf(_T("%s\n"),DecodeStatus(Status)); break; } } } else { if (GuidCount > 0) { _tprintf(_T("ERROR: System Logger does not accept application guids...\n")); Status = ERROR_INVALID_PARAMETER; } } break; } case ACTION_STOP : LoggerHandle = (TRACEHANDLE) 0; if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { if (GuidCount != 1) { _tprintf(_T("Need exactly one GUID for PRIVATE loggers\n")); Status = ERROR_INVALID_PARAMETER; break; } pLoggerInfo->Wnode.Guid = *GuidArray[0]; } // end_sdk if (specialLogger == 3) Status = GetGlobalLoggerSettings(pLoggerInfo, &pLoggerInfo->Wnode.ClientContext, &GlobalLoggerStartValue); // begin_sdk if ( (GuidCount > 0) && !( IsEqualGUID(&HeapGuid,GuidArray[0]) || IsEqualGUID(&CritSecGuid,GuidArray[0]) )) { if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY); if (Status != ERROR_SUCCESS) break; LoggerHandle = pLoggerInfo->Wnode.HistoricalContext; Status = EnableTrace( FALSE, EVENT_TRACE_PRIVATE_LOGGER_MODE, 0, GuidArray[0], LoggerHandle ); } else { Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY); if (Status == ERROR_WMI_INSTANCE_NOT_FOUND) break; LoggerHandle = pLoggerInfo->Wnode.HistoricalContext; for (i=0; i<(ULONG)GuidCount; i++) { Status = EnableTrace( FALSE, 0, 0, GuidArray[i], LoggerHandle); } } } Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_STOP); break; // end_sdk case ACTION_REMOVE : if (specialLogger == 3) { // Global Logger Status = SetGlobalLoggerSettings(0L, pLoggerInfo, pLoggerInfo->Wnode.ClientContext); if (Status != ERROR_SUCCESS) break; Status = GetGlobalLoggerSettings(pLoggerInfo, &pLoggerInfo->Wnode.ClientContext, &GlobalLoggerStartValue); if (Status != ERROR_SUCCESS) break; } break; // begin_sdk case ACTION_LIST : { ULONG returnCount ; ULONG ListSizeNeeded; PEVENT_TRACE_PROPERTIES pListLoggerInfo[MAXIMUM_LOGGERS_XP]; PEVENT_TRACE_PROPERTIES pStorage; PVOID Storage; ListSizeNeeded = MAXIMUM_LOGGERS_XP * (sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR)); Storage = malloc(ListSizeNeeded); if (Storage == NULL) { Status = ERROR_OUTOFMEMORY; break; } RtlZeroMemory(Storage, ListSizeNeeded); pStorage = (PEVENT_TRACE_PROPERTIES)Storage; for (i=0; iWnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR); pStorage->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + MAXSTR * sizeof(TCHAR); pStorage->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); pListLoggerInfo[i] = pStorage; pStorage = (PEVENT_TRACE_PROPERTIES) ( (char*)pStorage + pStorage->Wnode.BufferSize); } if (XP) { Status = QueryAllTraces(pListLoggerInfo, MAXIMUM_LOGGERS_XP, & returnCount); } else { Status = QueryAllTraces(pListLoggerInfo, MAXIMUM_LOGGERS_W2K, & returnCount); } if (Status == ERROR_SUCCESS) { for (j= 0; j < returnCount; j++) { LPTSTR ListLoggerName; TCHAR asked = _T('?') ; BOOL StatusPrint = FALSE ; if (bKill) { ListLoggerName = (LPTSTR) ((char*)pListLoggerInfo[j] + pListLoggerInfo[j]->LoggerNameOffset); if (!bForceKill) { while (!(asked == _T('y')) && !(asked == _T('n'))) { ULONG ReadChars = 0; _tprintf(_T("Do you want to kill Logger \"%s\" (Y or N)?"), ListLoggerName); ReadChars = _tscanf(_T(" %c"), &asked); if (ReadChars == 0 || ReadChars == EOF) { continue; } if (asked == _T('Y')) { asked = _T('y') ; } else if (asked == _T('N')) { asked = _T('n') ; } } } else { asked = _T('y'); } if (asked == _T('y')) { if (!IsEqualGUID(& pListLoggerInfo[j]->Wnode.Guid, & SystemTraceControlGuid)) { LoggerHandle = pListLoggerInfo[j]->Wnode.HistoricalContext; Status = EnableTrace( FALSE, (pListLoggerInfo[j]->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) ? (EVENT_TRACE_PRIVATE_LOGGER_MODE) : (0), 0, & pListLoggerInfo[j]->Wnode.Guid, LoggerHandle); } Status = ControlTrace((TRACEHANDLE) 0, ListLoggerName, pListLoggerInfo[j], EVENT_TRACE_CONTROL_STOP); _tprintf(_T("Logger \"%s\" has been killed\n"), ListLoggerName); StatusPrint = TRUE ; } else { _tprintf(_T("Logger \"%s\" has not been killed, current Status is\n"), ListLoggerName); StatusPrint = FALSE ; } } PrintLoggerStatus(pListLoggerInfo[j], // end_sdk 0, // begin_sdk Status, StatusPrint); _tprintf(_T("\n")); } } free(Storage); break; } case ACTION_UPDATE : case ACTION_FLUSH : case ACTION_QUERY : if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { if (GuidCount != 1) { _tprintf(_T("Need exactly one GUID for PRIVATE loggers\n")); Status = ERROR_INVALID_PARAMETER; break; } pLoggerInfo->Wnode.Guid = *GuidArray[0]; } if (Action == ACTION_QUERY) { // end_sdk if (specialLogger == 3) { Status = GetGlobalLoggerSettings(pLoggerInfo, &pLoggerInfo->Wnode.ClientContext, &GlobalLoggerStartValue); } // begin_sdk Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY); } else if (Action == ACTION_UPDATE) { // end_sdk if (specialLogger == 3) { Status = GetGlobalLoggerSettings(pLoggerInfo, &pLoggerInfo->Wnode.ClientContext, &GlobalLoggerStartValue); } // begin_sdk Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_UPDATE); } else if (Action == ACTION_FLUSH) { // Since FlushTrace is not implemented on Win2K, use the function pointer // loaded from advapi32.dll separately. // Originally, this block had one line: // Status = FlushTrace(LoggerHandle, LoggerName, pLoggerInfo); if (FuncArray[FUNC_FLUSH_TRACE] == NULL) { _tprintf(_T("Flush Trace is not supported on this system\n")); Status = ERROR_INVALID_PARAMETER; break; } Status = (ULONG)(*FuncArray[FUNC_FLUSH_TRACE])(LoggerHandle, LoggerName, pLoggerInfo); } break; case ACTION_ENUM_GUID: { ULONG PropertyArrayCount=10; PTRACE_GUID_PROPERTIES *GuidPropertiesArray; ULONG EnumGuidCount; ULONG SizeStorage; PVOID StorageNeeded; PTRACE_GUID_PROPERTIES CleanStorage; TCHAR str[MAXSTR]; // Since EnumTraceGuids is not implemented on Win2K, use the function pointer // loaded from advapi32.dll separately. if (FuncArray[FUNC_ENUM_TRACE_GUIDS] == NULL) { _tprintf(_T("Enumerating trace GUIDS is not supported on this system\n")); Status = ERROR_INVALID_PARAMETER; break; } Retry: SizeStorage = PropertyArrayCount * (sizeof(TRACE_GUID_PROPERTIES) + sizeof(PTRACE_GUID_PROPERTIES)); StorageNeeded = malloc(SizeStorage); if (StorageNeeded== NULL) { Status = ERROR_OUTOFMEMORY; break; } RtlZeroMemory(StorageNeeded, SizeStorage); GuidPropertiesArray = (PTRACE_GUID_PROPERTIES *)StorageNeeded; CleanStorage = (PTRACE_GUID_PROPERTIES)((char*)StorageNeeded + PropertyArrayCount * sizeof(PTRACE_GUID_PROPERTIES)); for (i=0; i < PropertyArrayCount; i++) { GuidPropertiesArray[i] = CleanStorage; CleanStorage = (PTRACE_GUID_PROPERTIES) ( (char*)CleanStorage + sizeof(TRACE_GUID_PROPERTIES) ); } // Use function pointer for EnumTraceGuids Status = (ULONG)(*FuncArray[FUNC_ENUM_TRACE_GUIDS])(GuidPropertiesArray,PropertyArrayCount,&EnumGuidCount); if(Status == ERROR_MORE_DATA) { PropertyArrayCount=EnumGuidCount; free(StorageNeeded); goto Retry; } // // print the GUID_PROPERTIES and Free Strorage // _tprintf(_T(" Guid Enabled LoggerId Level Flags\n")); _tprintf(_T("------------------------------------------------------------\n")); for (i=0; i < EnumGuidCount; i++) { _tprintf(_T("%s %5s %d %d %d\n"), GuidToString(&str[0],&GuidPropertiesArray[i]->Guid), (GuidPropertiesArray[i]->IsEnable) ? _T("TRUE") : _T("FALSE"), GuidPropertiesArray[i]->LoggerId, GuidPropertiesArray[i]->EnableLevel, GuidPropertiesArray[i]->EnableFlags ); } free(StorageNeeded); } break; case ACTION_HELP: PrintHelpMessage(); break; default : _tprintf(_T("Error: no action specified\n")); PrintHelpMessage(); break; } if ((Action != ACTION_HELP) && (Action != ACTION_ENUM_GUID) && (Action != ACTION_UNDEFINED) && (Action != ACTION_LIST)) PrintLoggerStatus(pLoggerInfo, // end_sdk GlobalLoggerStartValue, // begin_sdk Status, PRINTSTATUS); CleanupExit: SetLastError(Status); if (utargv != NULL) { GlobalFree(utargv); } free(pLoggerInfo); free(save); if (advapidll != NULL) FreeLibrary(advapidll); return(Status); } void PrintLoggerStatus( IN PEVENT_TRACE_PROPERTIES LoggerInfo, // end_sdk IN ULONG GlobalLoggerStartValue, // begin_sdk IN ULONG Status, IN BOOL PrintStatus ) /*++ Routine Description: Prints out the status of the specified logger. Arguments: LoggerInfo - The pointer to the resident EVENT_TRACE_PROPERTIES that has the information about the current logger. // end_sdk GlobalLoggerStartValue - The Start value for GlobalLogger (not used if it is not GlobalLogger). // begin_sdk Status - The returned status of the last executed command or the operation status of the current logger. PrintStatus - Determines which type of status it is using. Return Value: None --*/ { LPTSTR LoggerName, LogFileName; if ((LoggerInfo->LoggerNameOffset > 0) && (LoggerInfo->LoggerNameOffset < LoggerInfo->Wnode.BufferSize)) { LoggerName = (LPTSTR) ((char*)LoggerInfo + LoggerInfo->LoggerNameOffset); } else LoggerName = NULL; if ((LoggerInfo->LogFileNameOffset > 0) && (LoggerInfo->LogFileNameOffset < LoggerInfo->Wnode.BufferSize)) { LogFileName = (LPTSTR) ((char*)LoggerInfo + LoggerInfo->LogFileNameOffset); } else LogFileName = NULL; if (PrintStatus) { _tprintf(_T("Operation Status: %uL\t"), Status); _tprintf(_T("%s\n"), DecodeStatus(Status)); } _tprintf(_T("Logger Name: %s\n"), (LoggerName == NULL) ? _T(" ") : LoggerName); // end_sdk if (LoggerName == NULL || !_tcscmp(LoggerName, GLOBAL_LOGGER)) { // Logger ID _tprintf(_T("Status: %s\n"), GlobalLoggerStartValue ? _T("Registry set to start") : _T("Registry set to stop")); _tprintf(_T("Logger Id: %I64x\n"), LoggerInfo->Wnode.HistoricalContext); _tprintf(_T("Logger Thread Id: %p\n"), LoggerInfo->LoggerThreadId); if (LoggerInfo->BufferSize == 0) _tprintf(_T("Buffer Size: default value\n")); else _tprintf(_T("Buffer Size: %d Kb\n"), LoggerInfo->BufferSize); if (LoggerInfo->MaximumBuffers == 0) _tprintf(_T("Maximum Buffers: default value\n")); else _tprintf(_T("Maximum Buffers: %d\n"), LoggerInfo->MaximumBuffers); if (LoggerInfo->MinimumBuffers == 0) _tprintf(_T("Minimum Buffers: default value\n")); else _tprintf(_T("Minimum Buffers: %d\n"), LoggerInfo->MinimumBuffers); _tprintf(_T("Number of Buffers: %d\n"), LoggerInfo->NumberOfBuffers); _tprintf(_T("Free Buffers: %d\n"), LoggerInfo->FreeBuffers); _tprintf(_T("Buffers Written: %d\n"), LoggerInfo->BuffersWritten); _tprintf(_T("Events Lost: %d\n"), LoggerInfo->EventsLost); _tprintf(_T("Log Buffers Lost: %d\n"), LoggerInfo->LogBuffersLost); _tprintf(_T("Real Time Buffers Lost: %d\n"), LoggerInfo->RealTimeBuffersLost); _tprintf(_T("AgeLimit: %d\n"), LoggerInfo->AgeLimit); if (LogFileName == NULL) { _tprintf(_T("Buffering Mode: ")); } else { _tprintf(_T("Log File Mode: ")); } if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) { _tprintf(_T("Append ")); } if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) { _tprintf(_T("Circular\n")); } else if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL) { _tprintf(_T("Sequential\n")); } else { _tprintf(_T("Sequential\n")); } if (LoggerInfo->MaximumFileSize > 0) { if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_KBYTES_FOR_SIZE) _tprintf(_T("Maximum File Size: %d Kb\n"), LoggerInfo->MaximumFileSize); else _tprintf(_T("Maximum File Size: %d Mb\n"), LoggerInfo->MaximumFileSize); } if (LoggerInfo->FlushTimer > 0) _tprintf(_T("Buffer Flush Timer: %d secs\n"), LoggerInfo->FlushTimer); if (LoggerInfo->EnableFlags != 0) { _tprintf(_T("Enabled tracing: ")); if ((LoggerName != NULL) && (!_tcscmp(LoggerName, KERNEL_LOGGER_NAME))) { if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_PROCESS) _tprintf(_T("Process ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_THREAD) _tprintf(_T("Thread ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_DISK_IO) _tprintf(_T("Disk ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO) _tprintf(_T("File ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS) _tprintf(_T("PageFaults ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS) _tprintf(_T("HardFaults ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) _tprintf(_T("ImageLoad ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP) _tprintf(_T("TcpIp ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_REGISTRY) _tprintf(_T("Registry ")); } else { _tprintf(_T("0x%08x"), LoggerInfo->EnableFlags ); } _tprintf(_T("\n")); } if (LogFileName == NULL || _tcslen(LogFileName) == 0) { _tprintf(_T("Log Filename: default location\n")); _tprintf(_T(" %%SystemRoot%%\\System32\\LogFiles\\WMI\\trace.log\n")); } else _tprintf(_T("Log Filename: %s\n"), LogFileName); if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_LOCAL_SEQUENCE) { _tprintf(_T("Local Sequence numbers in use\n")); } else if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_GLOBAL_SEQUENCE) { _tprintf(_T("Global Sequence numbers in use\n")); } } else { // begin_sdk _tprintf(_T("Logger Id: %I64x\n"), LoggerInfo->Wnode.HistoricalContext); _tprintf(_T("Logger Thread Id: %p\n"), LoggerInfo->LoggerThreadId); if (Status != 0) return; _tprintf(_T("Buffer Size: %d Kb"), LoggerInfo->BufferSize); if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_PAGED_MEMORY) { _tprintf(_T(" using paged memory\n")); } else { _tprintf(_T("\n")); } _tprintf(_T("Maximum Buffers: %d\n"), LoggerInfo->MaximumBuffers); _tprintf(_T("Minimum Buffers: %d\n"), LoggerInfo->MinimumBuffers); _tprintf(_T("Number of Buffers: %d\n"), LoggerInfo->NumberOfBuffers); _tprintf(_T("Free Buffers: %d\n"), LoggerInfo->FreeBuffers); _tprintf(_T("Buffers Written: %d\n"), LoggerInfo->BuffersWritten); _tprintf(_T("Events Lost: %d\n"), LoggerInfo->EventsLost); _tprintf(_T("Log Buffers Lost: %d\n"), LoggerInfo->LogBuffersLost); _tprintf(_T("Real Time Buffers Lost: %d\n"), LoggerInfo->RealTimeBuffersLost); _tprintf(_T("AgeLimit: %d\n"), LoggerInfo->AgeLimit); if (LogFileName == NULL) { _tprintf(_T("Buffering Mode: ")); } else { _tprintf(_T("Log File Mode: ")); } if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) { _tprintf(_T("Append ")); } if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) { _tprintf(_T("Circular\n")); } else if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL) { _tprintf(_T("Sequential\n")); } else { _tprintf(_T("Sequential\n")); } if (LoggerInfo->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) { _tprintf(_T("Real Time mode enabled")); // end_sdk if (LoggerInfo->LogFileMode & EVENT_TRACE_BUFFERING_MODE) { _tprintf(_T(": buffering only")); } // begin_sdk _tprintf(_T("\n")); } if (LoggerInfo->MaximumFileSize > 0) { if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_KBYTES_FOR_SIZE) _tprintf(_T("Maximum File Size: %d Kb\n"), LoggerInfo->MaximumFileSize); else _tprintf(_T("Maximum File Size: %d Mb\n"), LoggerInfo->MaximumFileSize); } if (LoggerInfo->FlushTimer > 0) _tprintf(_T("Buffer Flush Timer: %d secs\n"), LoggerInfo->FlushTimer); if (LoggerInfo->EnableFlags != 0) { _tprintf(_T("Enabled tracing: ")); if ((LoggerName != NULL) && (!_tcscmp(LoggerName, KERNEL_LOGGER_NAME))) { if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_PROCESS) _tprintf(_T("Process ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_THREAD) _tprintf(_T("Thread ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_DISK_IO) _tprintf(_T("Disk ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO) _tprintf(_T("File ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS) _tprintf(_T("PageFaults ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS) _tprintf(_T("HardFaults ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) _tprintf(_T("ImageLoad ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP) _tprintf(_T("TcpIp ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_REGISTRY) _tprintf(_T("Registry ")); }else{ _tprintf(_T("0x%08x"), LoggerInfo->EnableFlags ); } _tprintf(_T("\n")); } if (LogFileName != NULL) { _tprintf(_T("Log Filename: %s\n"), LogFileName); } // end_sdk if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_LOCAL_SEQUENCE) { _tprintf(_T("Local Sequence numbers in use\n")); } else if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_GLOBAL_SEQUENCE) { _tprintf(_T("Global Sequence numbers in use\n")); } } // begin_sdk } LPTSTR DecodeStatus( IN ULONG Status ) /*++ Routine Description: Decodes WIN32 error into a string in the default language. Arguments: Status - The error status from the last executed command or the operation status of the current logger. Return Value: LPTSTR - String containing the decoded message. --*/ { memset( ErrorMsg, 0, MAXSTR ); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) ErrorMsg, MAXSTR, NULL ); return ErrorMsg; } LONG GetGuids( IN LPTSTR GuidFile, IN OUT LPGUID *GuidArray ) /*++ Routine Description: Reads GUIDs from a file and stores them in an GUID array. Arguments: GuidFile - The file containing GUIDs. GuidArray - The GUID array that will have GUIDs read from the file. Return Value: ULONG - The number of GUIDs processed. --*/ { FILE *f; TCHAR line[MAXSTR], arg[MAXSTR]; LPGUID Guid; int i, n; f = _tfopen((TCHAR*)GuidFile, _T("r")); if (f == NULL) return -1; n = 0; while ( _fgetts(line, MAXSTR, f) != NULL ) { if (_tcslen(line) < 36) continue; if (line[0] == ';' || line[0] == '\0' || line[0] == '#' || line[0] == '/') continue; Guid = (LPGUID) GuidArray[n]; n ++; StringToGuid(line, Guid); } fclose(f); return (ULONG)n; } 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( IN TCHAR *str, IN OUT LPGUID guid ) /*++ Routine Description: Converts a string into a GUID. Arguments: str - A string in TCHAR. guid - The pointer to a GUID that will have the converted GUID. Return Value: None. --*/ { TCHAR temp[10]; int i; try { _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); } } except (EXCEPTION_EXECUTE_HANDLER) { _tprintf( _T("Error: Invalid GuidFile!\n") ); exit(0); } } void DisplayVersionInfo() /*++ Routine Description: prints out a version information. Arguments: None. Return Value: None. --*/ { TCHAR buffer[512]; TCHAR strProgram[MAXSTR]; DWORD dw; BYTE* pVersionInfo; LPTSTR pVersion = NULL; LPTSTR pProduct = NULL; LPTSTR pCopyRight = NULL; dw = GetModuleFileName(NULL, strProgram, MAXSTR); if( dw>0 ){ dw = GetFileVersionInfoSize( strProgram, &dw ); if( dw > 0 ){ pVersionInfo = (BYTE*)malloc(dw); if( NULL != pVersionInfo ){ if(GetFileVersionInfo( strProgram, 0, dw, pVersionInfo )){ LPDWORD lptr = NULL; VerQueryValue( pVersionInfo, _T("\\VarFileInfo\\Translation"), (void**)&lptr, (UINT*)&dw ); if( lptr != NULL ){ _stprintf( buffer, _T("\\StringFileInfo\\%04x%04x\\%s"), LOWORD(*lptr), HIWORD(*lptr), _T("ProductVersion") ); VerQueryValue( pVersionInfo, buffer, (void**)&pVersion, (UINT*)&dw ); _stprintf( buffer, _T("\\StringFileInfo\\%04x%04x\\%s"), LOWORD(*lptr), HIWORD(*lptr), _T("OriginalFilename") ); VerQueryValue( pVersionInfo, buffer, (void**)&pProduct, (UINT*)&dw ); _stprintf( buffer, _T("\\StringFileInfo\\%04x%04x\\%s"), LOWORD(*lptr), HIWORD(*lptr), _T("LegalCopyright") ); VerQueryValue( pVersionInfo, buffer, (void**)&pCopyRight, (UINT*)&dw ); } if( pProduct != NULL && pVersion != NULL && pCopyRight != NULL ){ _tprintf( _T("\nMicrosoft (R) %s (%s)\n%s\n\n"), pProduct, pVersion, pCopyRight ); } } free( pVersionInfo ); } } } } void PrintHelpMessage() /*++ Routine Description: prints out a help message. Arguments: None. Return Value: None. --*/ { // end_sdk DisplayVersionInfo(); // begin_sdk _tprintf(_T("Usage: tracelog [actions] [options] | [-h | -help | -?]\n")); _tprintf(_T("\n actions:\n")); _tprintf(_T("\t-start [LoggerName] Starts up the [LoggerName] trace session\n")); _tprintf(_T("\t-stop [LoggerName] Stops the [LoggerName] trace session\n")); _tprintf(_T("\t-update [LoggerName] Updates the [LoggerName] trace session\n")); _tprintf(_T("\t-enable [LoggerName] Enables providers for the [LoggerName] session\n")); _tprintf(_T("\t-disable [LoggerName] Disables providers for the [LoggerName] session\n")); if (XP) _tprintf(_T("\t-flush [LoggerName] Flushes the [LoggerName] active buffers\n")); // end_sdk _tprintf(_T("\t-remove GlobalLogger Removes registry keys that activate GlobalLogger\n")); // begin_sdk if (XP) _tprintf(_T("\t-enumguid Enumerate Registered Trace Guids\n")); _tprintf(_T("\t-q [LoggerName] Query status of [LoggerName] trace session\n")); _tprintf(_T("\t-l List all trace sessions\n")); _tprintf(_T("\t-x Stops all active trace sessions\n")); _tprintf(_T("\n options:\n")); _tprintf(_T("\t-b Sets buffer size to Kbytes\n")); _tprintf(_T("\t-min Sets minimum buffers\n")); _tprintf(_T("\t-max Sets maximum buffers\n")); _tprintf(_T("\t-f Log to file \n")); if (XP) { _tprintf(_T("\t-append Append to file\n")); _tprintf(_T("\t-prealloc Pre-allocate\n")); } _tprintf(_T("\t-seq Sequential logfile of up to n Mbytes\n")); _tprintf(_T("\t-cir Circular logfile of n Mbytes\n")); if (XP) _tprintf(_T("\t-newfile Log to a new file after every n Mbytes\n")); _tprintf(_T("\t-ft Set flush timer to n seconds\n")); if (XP) _tprintf(_T("\t-paged Use pageable memory for buffers\n")); _tprintf(_T("\t-noprocess Disable Process Start/End tracing\n")); _tprintf(_T("\t-nothread Disable Thread Start/End tracing\n")); _tprintf(_T("\t-nodisk Disable Disk I/O tracing\n")); _tprintf(_T("\t-nonet Disable Network TCP/IP tracing\n")); _tprintf(_T("\t-fio Enable file I/O tracing\n")); _tprintf(_T("\t-pf Enable page faults tracing\n")); _tprintf(_T("\t-hf Enable hard faults tracing\n")); _tprintf(_T("\t-img Enable image load tracing\n")); _tprintf(_T("\t-cm Enable registry calls tracing\n")); _tprintf(_T("\t-um Enable Process Private tracing\n")); _tprintf(_T("\t-guid Start tracing for providers in file\n")); _tprintf(_T("\t-rt Enable tracing in real time mode\n")); _tprintf(_T("\t-kd Enable tracing in kernel debugger\n")); // _tprintf(_T("\t-dbg Enable debug tracing in DbgPrint(Ex) statements\n")); // _tprintf(_T("\t-ntsuccess Enable debug tracing in NT_SUCCESS macro\n")); _tprintf(_T("\t-age Modify aging decay time to n minutes\n")); _tprintf(_T("\t-level Enable Level passed to the providers\n")); _tprintf(_T("\t-flag Enable Flags passed to the providers\n")); // end_sdk if (XP) { _tprintf(_T("\t-eflag Enable flags (several) to providers\n")); _tprintf(_T("\t-ls Generate Local Sequence Numbers\n")); _tprintf(_T("\t-gs Generate Global Squence Numbers\n")); _tprintf(_T("\t-heap Use this for Heap Guid\n")); _tprintf(_T("\t-critsec Use this for CritSec Guid\n")); _tprintf(_T("\t-pids \n")); _tprintf(_T("\t Tracing for Heap and CritSec for different process\n")); } // begin_sdk _tprintf(_T("\n")); _tprintf(_T("\t-h\n")); _tprintf(_T("\t-help\n")); _tprintf(_T("\t-? Display usage information\n")); } PTCHAR GuidToString( IN OUT PTCHAR s, LPGUID piid ) /*++ Routine Description: Converts a GUID into a string. Arguments: s - A string in TCHAR that will have the converted GUID. piid - The pointer to a GUID. Return Value: PTCHAR - The string containig the convereted GUID. --*/ { _stprintf(s, _T("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"), piid->Data1, piid->Data2, piid->Data3, piid->Data4[0], piid->Data4[1], piid->Data4[2], piid->Data4[3], piid->Data4[4], piid->Data4[5], piid->Data4[6], piid->Data4[7]); return(s); } // end_sdk LPCWSTR cszGlobalLoggerKey = L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\WMI\\GlobalLogger"; LPCWSTR cszStartValue = L"Start"; LPCWSTR cszBufferSizeValue = L"BufferSize"; LPCWSTR cszMaximumBufferValue = L"MaximumBuffers"; LPCWSTR cszMinimumBufferValue = L"MinimumBuffers"; LPCWSTR cszFlushTimerValue = L"FlushTimer"; LPCWSTR cszFileNameValue = L"FileName"; LPCWSTR cszEnableKernelValue = L"EnableKernelFlags"; LPCWSTR cszClockTypeValue = L"ClockType"; // // GlobalLogger functions // ULONG SetGlobalLoggerSettings( IN DWORD StartValue, IN PEVENT_TRACE_PROPERTIES LoggerInfo, IN DWORD ClockType ) /*++ Since it is a standalone utility, there is no need for extensive comments. Routine Description: Depending on the value given in "StartValue", it sets or resets event trace registry. If the StartValue is 0 (Global logger off), it deletes all the keys (that the user may have set previsouly). Users are allowed to set or reset individual keys using this function, but only when "-start GlobalLogger" is used. The section that uses non NTAPIs is not guaranteed to work. Arguments: StartValue - The "Start" value to be set in the registry. 0: Global logger off 1: Global logger on LoggerInfo - The poniter to the resident EVENT_TRACE_PROPERTIES instance. whose members are used to set registry keys. ClockType - The type of the clock to be set. Return Value: Error Code defined in winerror.h : If the function succeeds, it returns ERROR_SUCCESS. --*/ { DWORD dwValue; NTSTATUS status; HANDLE KeyHandle; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeLoggerKey, UnicodeString; ULONG Disposition, TitleIndex; RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES)); RtlInitUnicodeString((&UnicodeLoggerKey),(cszGlobalLoggerKey)); InitializeObjectAttributes( &ObjectAttributes, &UnicodeLoggerKey, OBJ_CASE_INSENSITIVE, NULL, NULL ); // instead of opening, create a new key because it may not exist. // if one exists already, that handle will be passed. // if none exists, it will create one. status = NtCreateKey(&KeyHandle, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes, 0L, // not used within this call anyway. NULL, REG_OPTION_NON_VOLATILE, &Disposition); if(!NT_SUCCESS(status)) { return RtlNtStatusToDosError(status); } TitleIndex = 0L; if (StartValue == 1) { // ACTION_START: set filename only when it is given by a user. // setting BufferSize if (LoggerInfo->BufferSize > 0) { dwValue = LoggerInfo->BufferSize; RtlInitUnicodeString((&UnicodeString),(cszBufferSizeValue)); status = NtSetValueKey( KeyHandle, &UnicodeString, TitleIndex, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } TitleIndex++; } // setting MaximumBuffers if (LoggerInfo->MaximumBuffers > 0) { dwValue = LoggerInfo->MaximumBuffers; RtlInitUnicodeString((&UnicodeString),(cszMaximumBufferValue)); status = NtSetValueKey( KeyHandle, &UnicodeString, TitleIndex, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } TitleIndex++; } // setting MinimumBuffers if (LoggerInfo->MinimumBuffers > 0) { dwValue = LoggerInfo->MinimumBuffers; RtlInitUnicodeString((&UnicodeString),(cszMinimumBufferValue)); status = NtSetValueKey( KeyHandle, &UnicodeString, TitleIndex, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } TitleIndex++; } // setting FlushTimer if (LoggerInfo->FlushTimer > 0) { dwValue = LoggerInfo->FlushTimer; RtlInitUnicodeString((&UnicodeString),(cszFlushTimerValue)); status = NtSetValueKey( KeyHandle, &UnicodeString, TitleIndex, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } TitleIndex++; } // setting EnableFlags if (LoggerInfo->EnableFlags > 0) { dwValue = LoggerInfo->EnableFlags; RtlInitUnicodeString((&UnicodeString),(cszEnableKernelValue)); status = NtSetValueKey( KeyHandle, &UnicodeString, TitleIndex, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } TitleIndex++; } dwValue = 0; if (LoggerInfo->LogFileNameOffset > 0) { UNICODE_STRING UnicodeFileName; #ifndef UNICODE WCHAR TempString[MAXSTR]; MultiByteToWideChar(CP_ACP, 0, (PCHAR)(LoggerInfo->LogFileNameOffset + (PCHAR) LoggerInfo), strlen((PCHAR)(LoggerInfo->LogFileNameOffset + (PCHAR) LoggerInfo)), TempString, MAXSTR ); RtlInitUnicodeString((&UnicodeFileName), TempString); #else RtlInitUnicodeString((&UnicodeFileName), (PWCHAR)(LoggerInfo->LogFileNameOffset + (PCHAR) LoggerInfo)); #endif RtlInitUnicodeString((&UnicodeString),(cszFileNameValue)); status = NtSetValueKey( KeyHandle, &UnicodeString, TitleIndex, REG_SZ, UnicodeFileName.Buffer, UnicodeFileName.Length + sizeof(UNICODE_NULL) ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } TitleIndex++; } } else { // if ACTION_STOP then delete the keys that users might have set previously. // delete buffer size RtlInitUnicodeString((&UnicodeString),(cszBufferSizeValue)); status = NtDeleteValueKey( KeyHandle, &UnicodeString ); if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } // delete maximum buffers RtlInitUnicodeString((&UnicodeString),(cszMaximumBufferValue)); status = NtDeleteValueKey( KeyHandle, &UnicodeString ); if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } // delete minimum buffers RtlInitUnicodeString((&UnicodeString),(cszMinimumBufferValue)); status = NtDeleteValueKey( KeyHandle, &UnicodeString ); if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } // delete flush timer RtlInitUnicodeString((&UnicodeString),(cszFlushTimerValue)); status = NtDeleteValueKey( KeyHandle, &UnicodeString ); if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } // delete enable falg RtlInitUnicodeString((&UnicodeString),(cszEnableKernelValue)); status = NtDeleteValueKey( KeyHandle, &UnicodeString ); if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } // delete filename RtlInitUnicodeString((&UnicodeString),(cszFileNameValue)); status = NtDeleteValueKey( KeyHandle, &UnicodeString ); if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } } // setting ClockType if (ClockType > 0) { dwValue = ClockType; RtlInitUnicodeString((&UnicodeString),(cszClockTypeValue)); status = NtSetValueKey( KeyHandle, &UnicodeString, TitleIndex, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } TitleIndex++; } // Setting StartValue dwValue = StartValue; RtlInitUnicodeString((&UnicodeString),(cszStartValue)); status = NtSetValueKey( KeyHandle, &UnicodeString, TitleIndex, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); return RtlNtStatusToDosError(status); } TitleIndex++; NtClose(KeyHandle); return 0; } ULONG GetGlobalLoggerSettings( IN OUT PEVENT_TRACE_PROPERTIES LoggerInfo, OUT PULONG ClockType, OUT PDWORD pdwStart ) /*++ Routine Description: It reads registry for golbal logger and updates LoggerInfo. It uses NtEnumerateValueKey() to retrieve the values of the required subkeys. The section that uses non NTAPIs is not guaranteed to work. Arguments: LoggerInfo - The poniter to the resident EVENT_TRACE_PROPERTIES instance. whose members are updated as the result. ClockType - The type of the clock to be updated. pdwStart - The "Start" value of currently retained in the registry. Return Value: WINERROR - Error Code defined in winerror.h. If the function succeeds, it returns ERROR_SUCCESS. --*/ { ULONG i, j; NTSTATUS status; HANDLE KeyHandle; WCHAR SubKeyName[MAXSTR]; PVOID Buffer; ULONG BufferLength, RequiredLength, KeyNameLength, KeyDataOffset, KeyDataLength; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeLoggerKey; *pdwStart = 0; RtlInitUnicodeString((&UnicodeLoggerKey),(cszGlobalLoggerKey)); RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES)); InitializeObjectAttributes( &ObjectAttributes, &UnicodeLoggerKey, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = NtOpenKey( &KeyHandle, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes ); if(!NT_SUCCESS(status)) return RtlNtStatusToDosError(status); // KEY_VALUE_FULL_INFORMATION + name (1 WSTR) + data. BufferLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 2 * MAXSTR * sizeof(TCHAR); Buffer = (PVOID) malloc(BufferLength); if (Buffer == NULL) { NtClose(KeyHandle); return (ERROR_OUTOFMEMORY); } i = 0; do { // Using Key Enumeration status = NtEnumerateValueKey( KeyHandle, i++, KeyValueFullInformation, Buffer, BufferLength, &RequiredLength ); if (!NT_SUCCESS(status)) { if (status == STATUS_NO_MORE_ENTRIES) break; else if (status == STATUS_BUFFER_OVERFLOW) { free(Buffer); Buffer = malloc(RequiredLength); if (Buffer == NULL) { NtClose(KeyHandle); return (ERROR_OUTOFMEMORY); } status = NtEnumerateValueKey( KeyHandle, i++, KeyValueFullInformation, Buffer, BufferLength, &RequiredLength ); if (!NT_SUCCESS(status)) { NtClose(KeyHandle); free(Buffer); return RtlNtStatusToDosError(status); } } else { NtClose(KeyHandle); free(Buffer); return RtlNtStatusToDosError(status); } } KeyNameLength = ((PKEY_VALUE_FULL_INFORMATION)Buffer)->NameLength; RtlCopyMemory(SubKeyName, (PUCHAR)(((PKEY_VALUE_FULL_INFORMATION)Buffer)->Name), KeyNameLength ); KeyNameLength /= sizeof(WCHAR); SubKeyName[KeyNameLength] = L'\0'; KeyDataOffset = ((PKEY_VALUE_FULL_INFORMATION)Buffer)->DataOffset; KeyDataLength = ((PKEY_VALUE_FULL_INFORMATION)Buffer)->DataLength; // Find out what the key is if (!_wcsicmp(SubKeyName, cszStartValue)) { //StartValue RtlCopyMemory(pdwStart, (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); } else if (!_wcsicmp(SubKeyName, cszBufferSizeValue)) { // BufferSizeValue RtlCopyMemory(&(LoggerInfo->BufferSize), (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); } else if (!_wcsicmp(SubKeyName, cszMaximumBufferValue)) { // MaximumBufferValue RtlCopyMemory(&(LoggerInfo->MaximumBuffers), (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); } else if (!_wcsicmp(SubKeyName, cszMinimumBufferValue)) { // MinimumBuffers RtlCopyMemory(&(LoggerInfo->MinimumBuffers), (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); } else if (!_wcsicmp(SubKeyName, cszFlushTimerValue)) { // FlushTimer RtlCopyMemory(&(LoggerInfo->FlushTimer), (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); } else if (!_wcsicmp(SubKeyName, cszEnableKernelValue)) { // EnableKernelValue RtlCopyMemory(&(LoggerInfo->EnableFlags), (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); } else if (!_wcsicmp(SubKeyName, cszClockTypeValue)) { // ClockTypeValue RtlCopyMemory(ClockType, (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); } else if (!_wcsicmp(SubKeyName, cszFileNameValue)) { // FileName #ifndef UNICODE WCHAR TempString[MAXSTR]; RtlCopyMemory(TempString, (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); WideCharToMultiByte(CP_ACP, 0, TempString, wcslen(TempString), (PUCHAR)LoggerInfo + LoggerInfo->LogFileNameOffset, KeyDataLength, NULL, NULL); #else RtlCopyMemory((PUCHAR)LoggerInfo + LoggerInfo->LogFileNameOffset, (PUCHAR)Buffer + KeyDataOffset, KeyDataLength); #endif } else { // Some other keys are in there _tprintf(_T("Warning: Unidentified Key in the trace registry: %s\n"), SubKeyName); } } while (1); NtClose(KeyHandle); free(Buffer); return 0; }