/*++ © 1998 Seagate Software, Inc. All rights reserved Module Name: WsbTrace.cpp Abstract: These functions are used to provide an ability to trace the flow of the application for debugging purposes. Author: Chuck Bardeen [cbardeen] 29-Oct-1996 Revision History: Brian Dodd [brian] 09-May-1996 - Added event logging --*/ #include "stdafx.h" #include "stdio.h" #undef WsbThrow #define WsbThrow(hr) throw(hr) #define WSB_INDENT_STRING OLESTR(" ") #define WSB_APP_EVENT_LOG OLESTR("\\System32\\config\\AppEvent.evt") #define WSB_APP_EVENT_LOG_BKUP OLESTR("\\System32\\config\\AppEvent.bkp") #define WSB_APP_EVENT_LOG_NAME OLESTR("\\AppEvent.evt") #define WSB_SYS_EVENT_LOG OLESTR("\\System32\\config\\SysEvent.evt") #define WSB_SYS_EVENT_LOG_BKUP OLESTR("\\System32\\config\\SysEvent.bkp") #define WSB_SYS_EVENT_LOG_NAME OLESTR("\\SysEvent.evt") #define WSB_RS_TRACE_FILES OLESTR("Trace\\*.*") #define WSB_RS_TRACE_PATH OLESTR("Trace\\") #define BOGUS_TLS_INDEX 0xFFFFFFFF // Per-thread data: typedef struct { ULONG TraceOffCount; // Trace only if this is zero LONG IndentLevel; char *LogModule; DWORD LogModuleLine; DWORD LogNTBuild; DWORD LogRSBuild; } THREAD_DATA; static DWORD TlsIndex = BOGUS_TLS_INDEX; // Per-thread data index // The globals that control the tracing LONGLONG g_WsbTraceModules = WSB_TRACE_BIT_NONE; IWsbTrace *g_pWsbTrace = 0; BOOL g_WsbTraceEntryExit = TRUE; // The globals that control the event logging and printing WORD g_WsbLogLevel = WSB_LOG_LEVEL_DEFAULT; BOOL g_WsbLogSnapShotOn = FALSE; WORD g_WsbLogSnapShotLevel = 0; OLECHAR g_pWsbLogSnapShotPath[250]; BOOL g_WsbLogSnapShotResetTrace = FALSE; WORD g_WsbPrintLevel = WSB_LOG_LEVEL_DEFAULT; // // WsbTraceCount is a running count of the trace output count: normally we // use the shared count among the processes, but if we can't get access to // the shared var., we use this // LONG g_WsbTraceCount = 0; // Helper function static HRESULT OutputTraceString(ULONG indentLevel, OLECHAR* introString, OLECHAR* format, va_list vaList); static HRESULT GetThreadDataPointer(THREAD_DATA** ppTD); static void SnapShotTraceAndEvent( SYSTEMTIME stime ); void WsbTraceInit( void ) /*++ Routine Description: Initialize this trace module Arguments: None. Return Value: None. --*/ { // Get an index for the thread local storage TlsIndex = TlsAlloc(); } void WsbTraceCleanupThread( void ) /*++ Routine Description: Cleanup information for this thread (which is going away) Arguments: None. Return Value: None. --*/ { THREAD_DATA* pThreadData = NULL; if (BOGUS_TLS_INDEX != TlsIndex) { pThreadData = static_cast(TlsGetValue(TlsIndex)); if (pThreadData) { WsbFree(pThreadData); TlsSetValue(TlsIndex, NULL); } } } void WsbTraceEnter( OLECHAR* methodName, OLECHAR* argString, ... ) /*++ Routine Description: This routine prints out trace information indicating that the method specified has been entered, and the values of its arguements (if supplied). Arguments: methodName - The name of the method that was entered. argString - A printf style string indicating the number of arguments and how they should be formatted. Return Value: None. --*/ { HRESULT hr = S_OK; OLECHAR tmpString[WSB_TRACE_BUFF_SIZE]; va_list vaList; try { THREAD_DATA* pThreadData = NULL; WsbAffirmHr(GetThreadDataPointer(&pThreadData)); // Make sure we are supposed to trace WsbAffirm( 0 != g_pWsbTrace, S_OK); WsbAffirm(0 == pThreadData->TraceOffCount, S_OK); // Identify the function. swprintf(tmpString, OLESTR("Enter <%ls> : "), methodName); // Format & print out va_start(vaList, argString); WsbAffirmHr(OutputTraceString(pThreadData->IndentLevel, tmpString, argString, vaList)); va_end(vaList); // Increment the indentation level pThreadData->IndentLevel++; } WsbCatch (hr); } void WsbTraceExit( OLECHAR* methodName, OLECHAR* argString, ... ) /*++ Routine Description: This routine prints out trace information indicating that the method specified has been exitted, and the values it is returning (if supplied). Arguments: methodName - The name of the method that was exitted. argString - A printf style string indicating the number of arguments and how they should be formatted. Return Value: None. --*/ { HRESULT hr = S_OK; OLECHAR tmpString[WSB_TRACE_BUFF_SIZE]; va_list vaList; try { THREAD_DATA* pThreadData = NULL; WsbAffirmHr(GetThreadDataPointer(&pThreadData)); // Make sure we are supposed to trace WsbAffirm( 0 != g_pWsbTrace, S_OK); WsbAffirm(0 == pThreadData->TraceOffCount, S_OK); // Decrement the indentation level. if (pThreadData->IndentLevel > 0) { pThreadData->IndentLevel--; } else { g_pWsbTrace->Print(OLESTR("WARNING: Badly matched TraceIn/TraceOut\r\n")); } // Identify the function. swprintf(tmpString, OLESTR("Exit <%ls> : "), methodName); // Format & print out va_start(vaList, argString); WsbAffirmHr(OutputTraceString(pThreadData->IndentLevel, tmpString, argString, vaList)); va_end(vaList); } WsbCatch( hr ); } void WsbTracef( OLECHAR* argString, ... ) /*++ Routine Description: This routine prints out trace information from a printf style string. A carriage return should be add to the format string if desired. Arguments: argString - A printf style string indicating the number of arguments and how they should be formatted. Return Value: None. --*/ { HRESULT hr = S_OK; va_list vaList; try { THREAD_DATA* pThreadData = NULL; WsbAffirmHr(GetThreadDataPointer(&pThreadData)); // Make sure we are supposed to trace WsbAffirm( 0 != g_pWsbTrace, S_OK); WsbAffirm(0 == pThreadData->TraceOffCount, S_OK); // Format & print out va_start(vaList, argString); WsbAffirmHr(OutputTraceString(pThreadData->IndentLevel, NULL, argString, vaList)); va_end(vaList); } WsbCatch (hr); } void WsbSetEventInfo( char *fileName, DWORD lineNo, DWORD ntBuild, DWORD rsBuild ) /*++ Routine Description: This routine sets information used in logging events. Arguments: fileName - The name of the module that logged the event. lineNo - The source line number of the statement that logged the event ntBuild - The NT Build version rsBuild - The RS Build version Return Value: None. Notes: ntBuild, and rsBuild are passed in with each call to get the build version for the modules actually logging the event. --*/ { THREAD_DATA* pThreadData = NULL; if (S_OK == GetThreadDataPointer(&pThreadData)) { pThreadData->LogModule = fileName; pThreadData->LogModuleLine = lineNo; pThreadData->LogNTBuild = ntBuild; pThreadData->LogRSBuild = rsBuild; } } void WsbTraceAndLogEvent( DWORD eventId, DWORD dataSize, LPVOID data, ... ) /*++ Routine Description: This routine writes a message into the system event log. The message is also written to the application trace file. Arguments: eventId - The message Id to log. dataSize - Size of arbitrary data. data - Arbitrary data buffer to display with the message. Inserts - Message inserts that are merged with the message description specified by eventId. The number of inserts must match the number specified by the message description. The last insert must be NULL to indicate the end of the insert list. Return Value: None. --*/ { HRESULT hr = S_OK; try { va_list vaList; va_start(vaList, data); WsbTraceAndLogEventV( eventId, dataSize, data, &vaList ); va_end(vaList); } WsbCatch( hr ); } void WsbTraceAndLogEventV( DWORD eventId, DWORD dataSize, LPVOID data, va_list * inserts ) /*++ Routine Description: This routine writes a message into the system event log. The message is also written to the application trace file. The file name and line number is appended to the log data, if any. Arguments: eventId - The message Id to log. dataSize - Size of arbitrary data. data - Arbitrary data buffer to display with the message. inserts - An array of message inserts that are merged with the message description specified by eventId. The number of inserts must match the number specified by the message description. The last insert must be NULL, to indicate the end of the insert list. Return Value: None. --*/ { HRESULT hr = S_OK; char *newData = NULL, *fileName; DWORD newDataSize=0; OLECHAR ** logString=0; WORD count=0; SYSTEMTIME stime; try { WsbAssertPointer( inserts ); WORD logType; const OLECHAR * facilityName = 0; WORD category = 0; va_list vaList; BOOL bLog; BOOL bSnapShot; THREAD_DATA* pThreadData = NULL; // Get space for the passed in data plus the file and line number. If we fail to allocate // memory for this we just log the data they passed in (without file and line) GetThreadDataPointer(&pThreadData); if (pThreadData) { fileName = strrchr(pThreadData->LogModule, '\\'); } else { fileName = NULL; } if (fileName) { fileName++; // Point at just the source file name (no path) int len = strlen(fileName); newData = (char *) malloc(dataSize + len + 128); if (newData) { if (data) { memcpy(newData, data, dataSize); } // Align the record data on even 8 byte boundary for viewing len = (len>8) ? 16 : 8; sprintf(&newData[dataSize], "%-*.*s@%7luNt%6luRs%6.6ls", len, len, fileName, pThreadData->LogModuleLine, pThreadData->LogNTBuild, RsBuildVersionAsString(pThreadData->LogRSBuild) ); newDataSize = dataSize + strlen(&newData[dataSize]); } } // // Determine type of event // switch ( eventId & 0xc0000000 ) { case ERROR_SEVERITY_INFORMATIONAL: logType = EVENTLOG_INFORMATION_TYPE; bLog = (g_WsbLogLevel >= WSB_LOG_LEVEL_INFORMATION) ? TRUE : FALSE; bSnapShot = (g_WsbLogSnapShotLevel >= WSB_LOG_LEVEL_INFORMATION) ? TRUE : FALSE; break; case ERROR_SEVERITY_WARNING: logType = EVENTLOG_WARNING_TYPE; bLog = (g_WsbLogLevel >= WSB_LOG_LEVEL_WARNING) ? TRUE : FALSE; bSnapShot = (g_WsbLogSnapShotLevel >= WSB_LOG_LEVEL_WARNING) ? TRUE : FALSE; break; case ERROR_SEVERITY_ERROR: logType = EVENTLOG_ERROR_TYPE; bLog = (g_WsbLogLevel >= WSB_LOG_LEVEL_ERROR) ? TRUE : FALSE; bSnapShot = (g_WsbLogSnapShotLevel >= WSB_LOG_LEVEL_ERROR) ? TRUE : FALSE; break; default: logType = EVENTLOG_INFORMATION_TYPE; bLog = (g_WsbLogLevel >= WSB_LOG_LEVEL_COMMENT) ? TRUE : FALSE; bSnapShot = (g_WsbLogSnapShotLevel >= WSB_LOG_LEVEL_COMMENT) ? TRUE : FALSE; break; } WsbAffirm ( bLog, S_OK ); WsbTracef(OLESTR("\r\n")); WsbTracef(OLESTR("!!!!! EVENT !!!!! - File: %hs @ Line: %d (%lu-%ls)\r\n"), (pThreadData ? pThreadData->LogModule : ""), (pThreadData ? pThreadData->LogModuleLine : 0), (pThreadData ? pThreadData->LogNTBuild : 0), RsBuildVersionAsString((pThreadData ? pThreadData->LogRSBuild : 0)) ); // // Determine source facility and category of message // switch ( HRESULT_FACILITY( eventId ) ) { case WSB_FACILITY_PLATFORM: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_PLATFORM; break; case WSB_FACILITY_RMS: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_RMS; break; case WSB_FACILITY_HSMENG: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_HSMENG; break; case WSB_FACILITY_JOB: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_JOB; break; case WSB_FACILITY_HSMTSKMGR: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_HSMTSKMGR; break; case WSB_FACILITY_FSA: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_FSA; break; case WSB_FACILITY_GUI: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_GUI; break; case WSB_FACILITY_MOVER: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_MOVER; break; case WSB_FACILITY_LAUNCH: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_LAUNCH; break; case WSB_FACILITY_USERLINK: facilityName = WSB_FACILITY_PLATFORM_NAME; category = WSB_CATEGORY_USERLINK; break; case WSB_FACILITY_TEST: facilityName = WSB_FACILITY_TEST_NAME; category = WSB_CATEGORY_TEST; break; case HRESULT_FACILITY(FACILITY_NT_BIT): facilityName = WSB_FACILITY_NTDLL_NAME; eventId &= ~FACILITY_NT_BIT; break; default: facilityName = WSB_FACILITY_NTDLL_NAME; break; } // // Trace the message // if ( g_pWsbTrace ) { if ( facilityName ) { OLECHAR * messageText = 0; // NOTE: Positional parameters in the inserts are not processed. These // are done by ReportEvent() only. vaList = *inserts; HMODULE hModule; hModule = LoadLibraryEx( facilityName, NULL, LOAD_LIBRARY_AS_DATAFILE ); if (hModule) { FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER, hModule, eventId, MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPTSTR) &messageText, 0, &vaList ); if ( messageText ) { WsbTracef( OLESTR("%ls"), messageText ); // Format messages come with \n LocalFree( messageText ); } else { WsbTracef( OLESTR("!!!!! EVENT !!!!! - Message <0x%08lx> could not be translated.\r\n"), eventId ); } FreeLibrary(hModule); } else { WsbTracef( OLESTR("!!!!! EVENT !!!!! - Could not load facility name DLL %ls. \r\n"), facilityName); } } else { WsbTracef( OLESTR("!!!!! EVENT !!!!! - Message File for <0x%08lx> could not be found.\r\n"), eventId ); } if ( data && dataSize > 0 ) WsbTraceBufferAsBytes( dataSize, data ); } // Prepare arguments for ReportEvent // First count the number of arguments vaList = *inserts; for( count = 0; (va_arg( vaList, OLECHAR *)) != NULL; count++ ); if ( count ) { OLECHAR* tmpArg; // Allocate a array to hold the string arguments. // // IMPORTANT NOTE: Don't try anything fancy here. va_list is different // on various platforms. We'll need to build the string // argument required by ReportEvent (too bad ReportEvent // doesn't take va_list like FormatMessage does. // logString = (OLECHAR **)malloc( count*sizeof(OLECHAR *) ); WsbAffirmAlloc( logString ); // load in the strings vaList = *inserts; for( count = 0; (tmpArg = va_arg( vaList, OLECHAR *)) != NULL; count++ ) { logString[count] = tmpArg; } } // Get a handle to the event source HANDLE hEventSource = RegisterEventSource(NULL, WSB_LOG_SOURCE_NAME ); // Get the time in case we need to snap shot this event's logs and traces GetLocalTime(&stime); if (hEventSource != NULL) { // Write to event log DWORD recordDataSize = (newData) ? newDataSize : dataSize; LPVOID recordData = (newData) ? newData : data; if ( ReportEvent(hEventSource, logType, category, eventId, NULL, count, recordDataSize, (LPCTSTR *)&logString[0], recordData) ) { WsbTracef( OLESTR("!!!!! EVENT !!!!! - Event <0x%08lx> was logged.\r\n"), eventId ); WsbTracef( OLESTR("\r\n") ); } else { WsbTracef( OLESTR("!!!!! EVENT !!!!! - Event <0x%08lx> could not be logged due to the following error: %ls\r\n"), eventId, WsbHrAsString(HRESULT_FROM_WIN32(GetLastError())) ); WsbTracef( OLESTR("\r\n") ); } DeregisterEventSource(hEventSource); } try { HRESULT hr2 = S_OK; // // See if we are to take a snap shot of the event and trace logs when an event of this level is logged. // if ( (TRUE == bSnapShot) && (TRUE == g_WsbLogSnapShotOn) ) { SnapShotTraceAndEvent(stime); } } WsbCatchAndDo(hr, hr=S_OK; ); } WsbCatch( hr ); if (newData) { free(newData); } if (logString) { free(logString); } } const OLECHAR* WsbBoolAsString( BOOL boolean ) /*++ Routine Description: This routine provides a string repesentation (e.g. TRUE, FALSE) for the value of the boolean supplied. NOTE: This method does not support localization of the strings. Arguments: boolean - A boolean value. Return Value: A string representation of the value of the boolean. --*/ { return(boolean ? OLESTR("TRUE") : OLESTR("FALSE")); } const OLECHAR* WsbLongAsString( LONG inLong ) /*++ Routine Description: This routine provides a string repesentation for the value of the long supplied. NOTE: This method shares memory between subsequent calls of the function. Arguments: long - A long value Return Value: A string representation of the value of the GUID. --*/ { static OLECHAR defaultString[40]; swprintf( defaultString, OLESTR("%ld"), inLong ); return(defaultString); } const OLECHAR* WsbFiletimeAsString( IN BOOL isRelative, IN FILETIME time ) /*++ Routine Description: This routine provides a string repesentation for the value of the FILETIME supplied. NOTE: This method shares memory between subsequent calls of the function. Arguments: isRelatice - A boolean that indicates whether the time is absolute (e.g 1/1/1987 ...) or relative (e.g. 1 hour). time - A FILETIME. Return Value: A string representation of the value of the FILETIME. --*/ { static OLECHAR defaultString[80]; OLECHAR* tmpString = 0; HRESULT hr; hr = WsbFTtoWCS(isRelative, time, &tmpString, sizeof(defaultString)); if (hr == S_OK) { wcscpy(defaultString, tmpString); } else { wcscpy(defaultString, L"BADFILETIME"); } WsbFree(tmpString); return(defaultString); } const OLECHAR* WsbGuidAsString( GUID guid ) /*++ Routine Description: This routine provides a string repesentation for the value of the GUID supplied. NOTE: This method shares memory between subsequent calls of the function. Arguments: guid - A GUID. Return Value: A string representation of the value of the GUID. --*/ { static OLECHAR defaultString[40]; swprintf( defaultString, OLESTR("{%.8x-%.4x-%.4hx-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}"), guid.Data1, (UINT)guid.Data2, (UINT)guid.Data3, (UINT) guid.Data4[0], (UINT) guid.Data4[1], (UINT) guid.Data4[2], (UINT) guid.Data4[3], (UINT) guid.Data4[4], (UINT) guid.Data4[5], (UINT) guid.Data4[6], (UINT) guid.Data4[7]); return(defaultString); } const OLECHAR* WsbHrAsString( HRESULT hr ) /*++ Routine Description: This routine provides a string repesentation (e.g. S_OK, E_POINTER) for the value of the HRESULT supplied. NOTE: This method shares memory between subsequent calls of the function. Arguments: hr - An HRESULT. Return Value: A string representation of the value of the HRESULT. --*/ { const OLECHAR *returnString = 0; const OLECHAR *facilityName = 0; const DWORD cSize = 1024; DWORD stringSize = (cSize - 20); static OLECHAR defaultString[cSize]; DWORD lastError; // Handle a few special cases which are not in the message table resource switch ( hr ) { case S_OK: returnString = OLESTR("Ok"); // This overloads Win32 NO_ERROR. break; case S_FALSE: returnString = OLESTR("False"); // This overloads Win32 ERROR_INVALID_FUNCTION break; default: break; } if ( 0 == returnString ) { returnString = defaultString; swprintf( defaultString, OLESTR("0x%08lx"), hr ); // // First, try getting the message from the system // if ( 0 == FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ), defaultString, stringSize, NULL ) ) { lastError = GetLastError(); // For debugging // Next, try the module executing this code. if ( 0 == FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, NULL, hr, MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ), defaultString, stringSize, NULL ) ) { lastError = GetLastError(); // For debugging // Finally, try to identify the module based on the facility code switch ( HRESULT_FACILITY( hr ) ) { case WSB_FACILITY_PLATFORM: case WSB_FACILITY_RMS: case WSB_FACILITY_HSMENG: case WSB_FACILITY_JOB: case WSB_FACILITY_HSMTSKMGR: case WSB_FACILITY_FSA: case WSB_FACILITY_GUI: case WSB_FACILITY_MOVER: case WSB_FACILITY_LAUNCH: case WSB_FACILITY_USERLINK: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_TEST: facilityName = WSB_FACILITY_TEST_NAME; break; case HRESULT_FACILITY(FACILITY_NT_BIT): facilityName = WSB_FACILITY_NTDLL_NAME; hr &= ~FACILITY_NT_BIT; break; default: facilityName = WSB_FACILITY_NTDLL_NAME; break; } if ( facilityName ) { HMODULE hModule; hModule = LoadLibraryEx( facilityName, NULL, LOAD_LIBRARY_AS_DATAFILE ); if (hModule) { FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, hModule, hr, MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ), defaultString, stringSize, NULL ); FreeLibrary(hModule); } else { WsbTracef( OLESTR("!!!!! EVENT !!!!! - Could not load facility name DLL %ls. \r\n"), facilityName); } } } } // // remove trailing \r\n ( this makes things nice for tracing and asserts ) // if ( defaultString[ wcslen(defaultString)-1 ] == OLESTR('\n') ) { defaultString[ wcslen(defaultString)-1 ] = OLESTR('\0'); if ( defaultString[ wcslen(defaultString)-1 ] == OLESTR('\r') ) { defaultString[ wcslen(defaultString)-1 ] = OLESTR('\0'); swprintf( &defaultString[ wcslen(defaultString) ], OLESTR(" (0x%08lx)"), hr ); } } } return ( returnString ); } const OLECHAR* WsbLonglongAsString( LONGLONG llong ) /*++ Routine Description: This routine provides a string repesentation for the value of the LONGLONG supplied. NOTE: This method shares memory between subsequent calls of the function. Arguments: llong - A LONGLONG value. Return Value: A string representation of the value. --*/ { static OLECHAR defaultString[128]; OLECHAR* ptr = &defaultString[0]; WsbLLtoWCS(llong, &ptr, 128); return(defaultString); } const OLECHAR* WsbStringAsString( OLECHAR* pStr ) /*++ Routine Description: This routine provides a string repesentation for the value of the String supplied. NOTE: This method shares memory between subsequent calls of the function. Arguments: pStr - A string value. Return Value: A string representation of the value. --*/ { OLECHAR* returnString; if (0 == pStr) { returnString = OLESTR("NULL"); } else { returnString = pStr; } return(returnString); } const OLECHAR* WsbPtrToBoolAsString( BOOL* pBool ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a BOOL supplied. NOTE: This method does not support localization of the strings. Arguments: pBool - A pointer to a BOOL or NULL. Return Value: A string representation of the value of the BOOL or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; if (0 == pBool) { returnString = OLESTR("NULL"); } else { returnString = (OLECHAR*) WsbBoolAsString(*pBool); } return(returnString); } const OLECHAR* WsbPtrToFiletimeAsString( IN BOOL isRelative, IN FILETIME *pTime ) /*++ Routine Description: This routine provides a string repesentation for the value of the FILETIME supplied. NOTE: This method shares memory between subsequent calls of the function. Arguments: iselatice - A boolean that indicates whether the time is absolute (e.g 1/1/1987 ...) or relative (e.g. 1 hour). pTime - A pointer to a FILETIME. Return Value: A string representation of the value of the FILETIME. --*/ { OLECHAR* returnString; if (0 == pTime) { returnString = OLESTR("NULL"); } else { returnString = (OLECHAR*) WsbFiletimeAsString(isRelative, *pTime); } return(returnString); } const OLECHAR* WsbPtrToGuidAsString( GUID* pGuid ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a GUID supplied. NOTE: This method does not support localization of the strings. Arguments: pGuid - A pointer to a GUID or NULL. Return Value: A string representation of the value of the GUID or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; if (0 == pGuid) { returnString = OLESTR("NULL"); } else { returnString = (OLECHAR*) WsbGuidAsString(*pGuid); } return(returnString); } const OLECHAR* WsbPtrToHrAsString( HRESULT * pHr ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a HRESULT supplied. NOTE: This method does not support localization of the strings. Arguments: pHr - A pointer to an HRESULT. Return Value: A string representation of the value of the HRESULT. --*/ { OLECHAR* returnString; if (0 == pHr) { returnString = OLESTR("NULL"); } else { returnString = (OLECHAR*) WsbHrAsString(*pHr); } return(returnString); } const OLECHAR* WsbPtrToLonglongAsString( LONGLONG* pLlong ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a LONGLONG supplied. NOTE: This method does not support localization of the strings. Arguments: pLonglong - A pointer to a LONGLONG or NULL. Return Value: A string representation of the value of the LONGLONG or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; if (0 == pLlong) { returnString = OLESTR("NULL"); } else { returnString = (OLECHAR*) WsbLonglongAsString(*pLlong); } return(returnString); } const OLECHAR* WsbPtrToLongAsString( LONG* pLong ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a LONG supplied. NOTE: This method does not support localization of the strings, and shares memory between subsequent calls of the function. Arguments: pLong - A pointer to a LONG or NULL. Return Value: A string representation of the value of the LONG or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; static OLECHAR defaultString[20]; if (0 == pLong) { returnString = OLESTR("NULL"); } else { swprintf(defaultString, OLESTR("%ld"), *pLong); returnString = defaultString; } return(returnString); } const OLECHAR* WsbPtrToShortAsString( SHORT* pShort ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a SHORT supplied. NOTE: This method does not support localization of the strings, and shares memory between subsequent calls of the function. Arguments: pShort - A pointer to a SHORT or NULL. Return Value: A string representation of the value of the SHORT or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; static OLECHAR defaultString[20]; if (0 == pShort) { returnString = OLESTR("NULL"); } else { swprintf(defaultString, OLESTR("%d"), *pShort); returnString = defaultString; } return(returnString); } const OLECHAR* WsbPtrToByteAsString( BYTE* pByte ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a BYTE supplied. NOTE: This method does not support localization of the strings, and shares memory between subsequent calls of the function. Arguments: pByte - A pointer to a BYTE or NULL. Return Value: A string representation of the value of the BYTE or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; static OLECHAR defaultString[20]; if (0 == pByte) { returnString = OLESTR("NULL"); } else { swprintf(defaultString, OLESTR("%d"), *pByte); returnString = defaultString; } return(returnString); } const OLECHAR* WsbPtrToStringAsString( OLECHAR** pString ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a string supplied. NOTE: This method does not support localization ofthe strings. Arguments pString - A pointer to a OLECHAR* or NULL. Return Value: The string or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; if( (0 == pString) || (0 == *pString) ) { returnString = OLESTR("NULL"); } else { returnString = *pString; } return(returnString); } const OLECHAR* WsbPtrToUliAsString( ULARGE_INTEGER* pUli ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a ULARGE_INTEGER supplied. NOTE: This method does not support localization of the strings, and shares memory between subsequent calls of the function. Arguments: pUli - A pointer to a ULARGE_INTEGER or NULL. Return Value: A string representation of the value of the ULARGE_INTEGER or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; if (0 == pUli) { returnString = OLESTR("NULL"); } else { returnString = (OLECHAR*) WsbLonglongAsString( pUli->QuadPart ); } return(returnString); } const OLECHAR* WsbPtrToUlongAsString( ULONG* pUlong ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a ULONG supplied. NOTE: This method does not support localization of the strings, and shares memory between subsequent calls of the function. Arguments: pUlong - A pointer to a ULONG or NULL. Return Value: A string representation of the value of the ULONG or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; static OLECHAR defaultString[20]; if (0 == pUlong) { returnString = OLESTR("NULL"); } else { swprintf(defaultString, OLESTR("%lu"), *pUlong); returnString = defaultString; } return(returnString); } const OLECHAR* WsbPtrToUshortAsString( USHORT* pUshort ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a USHORT supplied. NOTE: This method does not support localization of the strings, and shares memory between subsequent calls of the function. Arguments: pUshort - A pointer to a USHORT or NULL. Return Value: A string representation of the value of the USHORT or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; static OLECHAR defaultString[20]; if (0 == pUshort) { returnString = OLESTR("NULL"); } else { swprintf(defaultString, OLESTR("%u"), *pUshort); returnString = defaultString; } return(returnString); } const OLECHAR* WsbPtrToPtrAsString( void** ppVoid ) /*++ Routine Description: This routine provides a string repesentation for the value of the pointer to a ULONG supplied. NOTE: This method does not support localization of the strings, and shares memory between subsequent calls of the function. Arguments: pUlong - A pointer to a ULONG or NULL. Return Value: A string representation of the value of the ULONG or "NULL" if the pointer was null. --*/ { OLECHAR* returnString; static OLECHAR defaultString[20]; if (0 == ppVoid) { returnString = OLESTR("NULL"); } else { swprintf(defaultString, OLESTR("0x%p"), *ppVoid); returnString = defaultString; } return(returnString); } const OLECHAR* WsbAbbreviatePath( const OLECHAR* path, USHORT length ) /*++ Routine Description: This routine condenses a path from it's original length to the requested length by chopping out it's middle characters NOTE: This method does not support localization of the strings, and shares memory between subsequent calls of the function. Arguments: path - A pointer to the path length - The condensed path length including the \0 Return Value: A string representation of the value of the BYTE or "NULL" if the pointer was null. This function also returns "NULL" if the length is less than 4 bytes. --*/ { HRESULT hr = S_OK; OLECHAR* returnString; static CWsbStringPtr tmpString; returnString = OLESTR("ERROR"); try { // // Check to see if we have anything to work with // if ((0 == path) || (length < 4)) { returnString = OLESTR("NULL"); } else { // // Get enough space for the return // USHORT pathlen; pathlen = (USHORT)wcslen(path); hr = tmpString.Realloc(length); if (S_OK != hr) { returnString = OLESTR("No memory"); WsbAffirmHr(hr); } if (pathlen < length) { swprintf(tmpString, OLESTR("%s"), path); } else { USHORT partlength = (USHORT) ( (length - 4) / 2 ); wcsncpy(tmpString, path, partlength); tmpString[(int) partlength] = L'\0'; wcscat(tmpString, OLESTR("...")); wcscat(tmpString, &(path[pathlen - partlength])); } returnString = tmpString; } } WsbCatch(hr); return(returnString); } void WsbTraceBufferAsBytes( DWORD size, LPVOID data ) /*++ Routine Description: This routine traces an arbitrary size buffer of bytes in hex and asci. A similar routine could be written trace a buffer in words. Arguments: size - The size of buffer to trace. data - The data to trace. Return Value: None. --*/ { HRESULT hr = S_OK; try { // Make sure we are supposed to trace WsbAffirm( 0 != g_pWsbTrace, S_OK); // Make sure we have something to trace WsbAssertPointer( data ); CWsbStringPtr traceString; char *output; unsigned char *bufferP = (unsigned char *)data; // IMPORTANT NOTE: Changing these may mean the last line processing need to be changed. char *beginAsci = " ["; char *endAsci = "]"; char *charFmt = "%02x"; char *addFmt = "%04x:"; char *between8 = " "; char *between4 = " "; char noPrintChar = 0x2e; const int ll = 16; // IMPORTANT NOTE: line length, a multiple of 8 - if this changes, the last line processing needs to be fixed. int lineCount = 0; output = (char *)malloc( (/*address*/6+/*data*/(ll*3)+/*asci*/4+ll+3/*between*/+7+1)*sizeof(char) ); WsbAffirmAlloc( output ); if ( size > 0 ) { unsigned long i, ii, j, k; long repeat; unsigned char c; for ( i = 0; i < size; i++ ) { if ( (0 == i % ll) && (i != 0) ) { // print asci interpretation sprintf( output, beginAsci ); traceString.Append(output); for ( j = 0; j < ll; j++ ) { c = bufferP[i-ll+j]; if ( c < ' ' || c > '~' ) { c = noPrintChar; } sprintf( output, "%c", c ); traceString.Append(output); } sprintf( output, endAsci ); traceString.Append(output); WsbTracef( OLESTR("%ls\n"), (WCHAR *) traceString ); lineCount++; // now check if the next line is the same as the one just printed repeat = 0; ii = i; while ( (0 == memcmp( &bufferP[ii-ll], &bufferP[ii], ll )) && (ii+ll < size) ) { repeat++; ii += ll; } if ( repeat > 1 ) { sprintf( output, " previous line repeats %ld times", repeat); traceString = output; WsbTracef( OLESTR("%ls\n"), (WCHAR *) traceString ); lineCount++; i = ii; } } if ( 0 == i % ll ) { // print address sprintf( output, addFmt, i ); traceString = output; } // add alignment spacing if ( (0 == (i + 8) % ll) ) { sprintf( output, between8 ); traceString.Append(output); } else if ( 0 == i % 4 ) { sprintf( output, between4 ); traceString.Append(output); } else { sprintf( output, " " ); traceString.Append(output); } // print byte in hex sprintf( output, charFmt, bufferP[i] ); traceString.Append(output); } // handle the last line; i allways > 0 here // NOTE: This is only good for upto 16 chars per line. if ( i % ll ) { k = (ll - (i % ll)) * 3 + ( (i % ll) < 5 ? 1 : 0 )+ ( (i % ll) < 9 ? 2 : 0 )+ ( (i % ll) < 13 ? 1 : 0 ); for ( j = 0; j < k ; j++ ) { sprintf( output, " "); traceString.Append(output); } } k = (i % ll) ? (i % ll) : ll ; sprintf( output, beginAsci ); traceString.Append(output); for ( j = 0; j < k; j++ ) { c = bufferP[i-k+j]; if ( c < ' ' || c > '~' ) { c = noPrintChar; } sprintf( output, "%c", c ); traceString.Append(output); } sprintf( output, endAsci); lineCount++; traceString.Append(output); WsbTracef( OLESTR("%ls\n"), (WCHAR *) traceString ); } } WsbCatch( hr ); } void WsbTraceTerminate( void ) /*++ Routine Description: Terminate (cleanup) this module because the process is ending Arguments: None. Return Value: None. --*/ { if (BOGUS_TLS_INDEX != TlsIndex) { TlsFree(TlsIndex); TlsIndex = BOGUS_TLS_INDEX; } } ULONG WsbTraceThreadOff( void ) /*++ Routine Description: Increment the trace-off count for this thread Arguments: None. Return Value: The final trace-off count. --*/ { ULONG count = 0; THREAD_DATA* pThreadData = NULL; if (S_OK == GetThreadDataPointer(&pThreadData)) { count = ++(pThreadData->TraceOffCount); } return(count); } ULONG WsbTraceThreadOffCount( void ) /*++ Routine Description: Return the current trace-off count for this thread Arguments: None. Return Value: The current trace-off count. --*/ { ULONG count = 0; THREAD_DATA* pThreadData = NULL; if (S_OK == GetThreadDataPointer(&pThreadData)) { count = pThreadData->TraceOffCount; } return(count); } ULONG WsbTraceThreadOn( void ) /*++ Routine Description: Decrement the trace-off count for this thread Arguments: None. Return Value: The final trace-off count. --*/ { ULONG count = 0; THREAD_DATA* pThreadData = NULL; if (S_OK == GetThreadDataPointer(&pThreadData)) { if (0 < pThreadData->TraceOffCount) { pThreadData->TraceOffCount--; } count = pThreadData->TraceOffCount; } return(count); } static HRESULT OutputTraceString( IN ULONG indentLevel, IN OLECHAR* introString, IN OLECHAR* format, IN va_list vaList ) /*++ Routine Description: Build and output the trace string. Arguments: indentLevel - Count of indentation strings to output introString - String to add before variable list vaList - Variable list to format Return Value: The data pointer. --*/ { HRESULT hr = S_OK; OLECHAR traceString[WSB_TRACE_BUFF_SIZE]; try { LONG incSize; LONG traceSize = 0; // Initialize the string swprintf(traceString, OLESTR("")); // Add indentation incSize = wcslen(WSB_INDENT_STRING); for(ULONG level = 0; level < indentLevel; level++) { if ((traceSize + incSize) < WSB_TRACE_BUFF_SIZE) { wcscat(traceString, WSB_INDENT_STRING); traceSize += incSize; } } // Add the intro string if (introString) { incSize = wcslen(introString); } else { incSize = 0; } if (incSize && ((traceSize + incSize) < WSB_TRACE_BUFF_SIZE)) { wcscat(traceString, introString); traceSize += incSize; } // Format the arguments (leave room for EOL and EOS) incSize = _vsnwprintf(&traceString[traceSize], (WSB_TRACE_BUFF_SIZE - traceSize - 3), format, vaList); if (incSize < 0) { // This means we filled the buffer and would have overflowed // Need to add EOS traceString[WSB_TRACE_BUFF_SIZE - 3] = OLECHAR('\0'); traceSize = WSB_TRACE_BUFF_SIZE - 3; } else { traceSize += incSize; } // Add EOL if needed if (introString) { wcscat(&traceString[traceSize], OLESTR("\r\n")); } WsbAffirmHr(g_pWsbTrace->Print(traceString)); } WsbCatch (hr); return(hr); } static HRESULT GetThreadDataPointer( OUT THREAD_DATA** ppTD ) /*++ Routine Description: Return a pointer to the data specific to the current thread. This function will allocate space for the thread data (and initialize it) if needed. Arguments: ppTD - Pointer to pointer to thread data. Return Value: The data pointer. --*/ { HRESULT hr = E_FAIL; THREAD_DATA* pThreadData = NULL; // Make sure the TLS index is valid if (BOGUS_TLS_INDEX != TlsIndex) { // Try to get the data pointer for this thread pThreadData = static_cast(TlsGetValue(TlsIndex)); if (pThreadData) { hr = S_OK; } else { // Allocate data for this thread yet pThreadData = static_cast(WsbAlloc(sizeof(THREAD_DATA))); if (pThreadData) { if (TlsSetValue(TlsIndex, pThreadData)) { // Initialize the data for this thread pThreadData->TraceOffCount = 0; pThreadData->IndentLevel = 0; pThreadData->LogModule = NULL; pThreadData->LogModuleLine = 0; pThreadData->LogNTBuild = 0; pThreadData->LogRSBuild = 0; hr = S_OK; } else { // TlsSetValue failed! WsbFree(pThreadData); pThreadData = NULL; } } } } *ppTD = pThreadData; return(hr); } static void SnapShotTraceAndEvent( SYSTEMTIME stime ) /*++ Routine Description: This routine saves the trace files and event logs Arguments: Return Value: None. --*/ { HRESULT hr = S_OK; try { OLECHAR dataString[256]; OLECHAR tmpString[50]; OLECHAR mutexName[50] = L"WsbTraceSnapShotMutex"; DWORD sizeGot; HANDLE mutexHandle = INVALID_HANDLE_VALUE; // // The level is one to snap shot and snap shot is on. Now make sure there is a // path specified where we are to copy the logs // WsbAffirm(0 != g_pWsbLogSnapShotPath, E_POINTER); WsbAffirm(0 != wcslen(g_pWsbLogSnapShotPath), E_POINTER); // // Get the system root string from the registry // WsbAffirmHr(WsbGetRegistryValueString(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY, WSB_SYSTEM_ROOT_REGISTRY_VALUE, dataString, 256, &sizeGot)); CWsbStringPtr snapShotSubDir; CWsbStringPtr snapShotFile; snapShotSubDir = g_pWsbLogSnapShotPath; // // Make sure there is a "\" at the end of the path // int len; len = wcslen(snapShotSubDir); if (snapShotSubDir[len] != '\\') { snapShotSubDir.Append(L"\\"); } // Build the path to the subdirectory that will contain the logs from the input path // and the time of the event. swprintf(tmpString, OLESTR("%2.02u.%2.02u-%2.2u.%2.2u.%2.2u.%3.3u"), stime.wMonth, stime.wDay, stime.wHour, stime.wMinute, stime.wSecond, stime.wMilliseconds); snapShotSubDir.Append(tmpString); // // Make sure the subdirectory can be created // WsbAffirmHr(WsbCreateAllDirectories(snapShotSubDir)); // // We need to synchronize around the creating of the // event backup files and copying them. Since all three // services will access this code, use a mutex to // synchronize them. mutexHandle = CreateMutex(NULL, TRUE, mutexName); if (mutexHandle) { // // Copy the event logs // First back them up and then copy the backup file. // HANDLE eventLogHandle = INVALID_HANDLE_VALUE; try { CWsbStringPtr computerName; CWsbStringPtr logName; WsbAffirmHr( WsbGetComputerName( computerName ) ); // // Open the application event log and back it up // logName = dataString; logName.Append(WSB_APP_EVENT_LOG); eventLogHandle = OpenEventLog((LPCTSTR)computerName, (LPCTSTR)logName); if (INVALID_HANDLE_VALUE != eventLogHandle) { logName = dataString; logName.Append(WSB_APP_EVENT_LOG_BKUP); DeleteFile(logName); WsbAffirmStatus(BackupEventLog(eventLogHandle, (LPCTSTR)logName)); WsbAffirmStatus(CloseEventLog(eventLogHandle)); snapShotFile = snapShotSubDir; snapShotFile.Append(WSB_APP_EVENT_LOG_NAME); // // Now copy the backup file // WsbAffirmStatus(CopyFile(logName, snapShotFile, FALSE)); } // // Open the system event log and back it up // logName = dataString; logName.Append(WSB_SYS_EVENT_LOG); eventLogHandle = OpenEventLog((LPCTSTR)computerName, (LPCTSTR)logName); if (INVALID_HANDLE_VALUE != eventLogHandle) { logName = dataString; logName.Append(WSB_SYS_EVENT_LOG_BKUP); DeleteFile(logName); WsbAffirmStatus(BackupEventLog(eventLogHandle, (LPCTSTR)logName)); WsbAffirmStatus(CloseEventLog(eventLogHandle)); snapShotFile = snapShotSubDir; snapShotFile.Append(WSB_SYS_EVENT_LOG_NAME); // // Now copy the backup file // WsbAffirmStatus(CopyFile(logName, snapShotFile, FALSE)); } } WsbCatchAndDo(hr,if (INVALID_HANDLE_VALUE != eventLogHandle) { CloseEventLog(eventLogHandle);}; hr = S_OK; ); (void)ReleaseMutex(mutexHandle); } // // Copy the trace files if there are any // try { WIN32_FIND_DATA findData; HANDLE handle; CWsbStringPtr traceFile; CWsbStringPtr searchString; BOOL foundFile; // // Find the file(s) // WsbAffirmHr(WsbGetMetaDataPath(searchString)); searchString.Append(WSB_RS_TRACE_FILES); handle = FindFirstFile(searchString, &findData); snapShotFile = snapShotSubDir; snapShotFile.Append(L"\\"); WsbAffirmHr(WsbGetMetaDataPath(traceFile)); traceFile.Append(WSB_RS_TRACE_PATH); WsbAffirmHr(snapShotFile.Append((OLECHAR *)(findData.cFileName))); WsbAffirmHr(traceFile.Append((OLECHAR *)(findData.cFileName))); // If we found a file, then remember the scan handle and // return the scan item. foundFile = TRUE; while ((INVALID_HANDLE_VALUE != handle) && (foundFile == TRUE)) { if ((FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes) != FILE_ATTRIBUTE_DIRECTORY) { WsbAffirmStatus(CopyFile(traceFile, snapShotFile, FALSE)); } foundFile = FindNextFile(handle, &findData); snapShotFile = snapShotSubDir; snapShotFile.Append(L"\\"); WsbAffirmHr(WsbGetMetaDataPath(traceFile)); traceFile.Append(WSB_RS_TRACE_PATH); WsbAffirmHr(snapShotFile.Append((OLECHAR *)(findData.cFileName))); WsbAffirmHr(traceFile.Append((OLECHAR *)(findData.cFileName))); } } WsbCatchAndDo(hr, hr = S_OK; ); } WsbCatch( hr ); } #include "winnls.h" #include "resource.h" #define HIDWORD(_qw) (DWORD)((_qw)>>32) #define LODWORD(_qw) (DWORD)(_qw) #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) LPTSTR AddCommas(DWORD dw, LPTSTR pszResult, int nResLen); const int pwOrders[] = {IDS_WSB_BYTES, IDS_WSB_ORDERKB, IDS_WSB_ORDERMB, IDS_WSB_ORDERGB, IDS_WSB_ORDERTB, IDS_WSB_ORDERPB, IDS_WSB_ORDEREB}; HRESULT WsbShortSizeFormat64(__int64 dw64, LPTSTR szBuf) /*++ Routine Description: Converts numbers into sort formats 532 -> 523 bytes 1340 -> 1.3KB 23506 -> 23.5KB -> 2.4MB -> 5.2GB Arguments: Return Value: Note: This code is cloned from MS source /shell/shelldll/util.c - AHB --*/ { int i; UINT wInt, wLen, wDec; TCHAR szTemp[10], szOrder[20], szFormat[5]; HMODULE hModule; if (dw64 < 1000) { wsprintf(szTemp, TEXT("%d"), LODWORD(dw64)); i = 0; goto AddOrder; } for (i = 1; i= 1000L * 1024L; dw64 >>= 10, i++); /* do nothing */ wInt = LODWORD(dw64 >> 10); AddCommas(wInt, szTemp, 10); wLen = lstrlen(szTemp); if (wLen < 3) { wDec = LODWORD(dw64 - (__int64)wInt * 1024L) * 1000 / 1024; // At this point, wDec should be between 0 and 1000 // we want get the top one (or two) digits. wDec /= 10; if (wLen == 2) wDec /= 10; // Note that we need to set the format before getting the // intl char. lstrcpy(szFormat, TEXT("%02d")); szFormat[2] = (TCHAR)( TEXT('0') + 3 - wLen ); GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szTemp+wLen, ARRAYSIZE(szTemp)-wLen); wLen = lstrlen(szTemp); wLen += wsprintf(szTemp+wLen, szFormat, wDec); } AddOrder: hModule = LoadLibraryEx(WSB_FACILITY_PLATFORM_NAME, NULL, LOAD_LIBRARY_AS_DATAFILE); if (hModule) { LoadString(hModule, pwOrders[i], szOrder, ARRAYSIZE(szOrder)); wsprintf(szBuf, szOrder, (LPTSTR)szTemp); FreeLibrary(hModule); } return S_OK; } LPTSTR AddCommas(DWORD dw, LPTSTR pszResult, int nResLen) /*++ Routine Description: Takes a DWORD add commas etc to it and puts the result in the buffer Arguments: Return Value: Note: This code is cloned from MS source /shell/shelldll/util.c - AHB --*/ { TCHAR szTemp[20]; // more than enough for a DWORD TCHAR szSep[5]; NUMBERFMT nfmt; nfmt.NumDigits=0; nfmt.LeadingZero=0; GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep)); nfmt.Grouping = _tcstol(szSep, NULL, 10); GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep)); nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep; nfmt.NegativeOrder= 0; wsprintf(szTemp, TEXT("%lu"), dw); if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, nResLen) == 0) lstrcpy(pszResult, szTemp); return pszResult; } void WsbTraceAndPrint( DWORD eventId, ... ) /*++ Routine Description: This routine writes a message into standard output. The message is also written to the application trace file. Arguments: eventId - The message Id to log. Inserts - Message inserts that are merged with the message description specified by eventId. The number of inserts must match the number specified by the message description. The last insert must be NULL to indicate the end of the insert list. Return Value: None. --*/ { HRESULT hr = S_OK; try { va_list vaList; va_start(vaList, eventId); WsbTraceAndPrintV(eventId, &vaList ); va_end(vaList); } WsbCatch( hr ); } void WsbTraceAndPrintV( DWORD eventId, va_list * inserts ) /*++ Routine Description: This routine writes a message into standard output. The message is also written to the application trace file. Arguments: eventId - The message Id to log. inserts - An array of message inserts that are merged with the message description specified by eventId. The number of inserts must match the number specified by the message description. The last insert must be NULL, to indicate the end of the insert list. Return Value: None. --*/ { HRESULT hr = S_OK; try { WsbAssertPointer( inserts ); const OLECHAR * facilityName = 0; BOOL bPrint; OLECHAR * messageText = 0; // // Determine type of event // switch ( eventId & 0xc0000000 ) { case ERROR_SEVERITY_INFORMATIONAL: bPrint = (g_WsbPrintLevel >= WSB_LOG_LEVEL_INFORMATION) ? TRUE : FALSE; break; case ERROR_SEVERITY_WARNING: bPrint = (g_WsbPrintLevel >= WSB_LOG_LEVEL_WARNING) ? TRUE : FALSE; break; case ERROR_SEVERITY_ERROR: bPrint = (g_WsbPrintLevel >= WSB_LOG_LEVEL_ERROR) ? TRUE : FALSE; break; default: bPrint = (g_WsbPrintLevel >= WSB_LOG_LEVEL_COMMENT) ? TRUE : FALSE; break; } WsbAffirm (bPrint, S_OK); // // Determine source facility of message // switch ( HRESULT_FACILITY( eventId ) ) { case WSB_FACILITY_PLATFORM: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_RMS: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_HSMENG: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_JOB: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_HSMTSKMGR: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_FSA: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_GUI: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_MOVER: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_LAUNCH: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_USERLINK: facilityName = WSB_FACILITY_PLATFORM_NAME; break; case WSB_FACILITY_CLI: facilityName = WSB_FACILITY_CLI_NAME; break; case WSB_FACILITY_TEST: facilityName = WSB_FACILITY_TEST_NAME; break; case HRESULT_FACILITY(FACILITY_NT_BIT): facilityName = WSB_FACILITY_NTDLL_NAME; eventId &= ~FACILITY_NT_BIT; break; default: facilityName = WSB_FACILITY_NTDLL_NAME; break; } if ( facilityName ) { HMODULE hModule; hModule = LoadLibraryEx( facilityName, NULL, LOAD_LIBRARY_AS_DATAFILE ); if (hModule) { // // Load and format the message // FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER, hModule, eventId, MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPTSTR) &messageText, 0, inserts); if ( messageText ) { // // Print the message // wprintf( messageText ); // Format messages come with \n // TEMPORARY: Should we convert here using WideCharToMultiByte ??? // // Trace the message // if ( g_pWsbTrace ) { WsbTracef( OLESTR("!!!!! PRINT - Event <0x%08lx> is printed\n"), eventId ); WsbTracef( OLESTR("%ls"), messageText ); // Format messages come with \n } LocalFree( messageText ); } else { if ( g_pWsbTrace ) { WsbTracef( OLESTR("!!!!! PRINT !!!!! - Message <0x%08lx> could not be translated.\r\n"), eventId ); } } FreeLibrary(hModule); } else { WsbTracef( OLESTR("!!!!! EVENT !!!!! - Could not load facility name DLL %ls. \r\n"), facilityName); } } else { if ( g_pWsbTrace ) { WsbTracef( OLESTR("!!!!! PRINT !!!!! - Message File for <0x%08lx> could not be found.\r\n"), eventId ); } } } WsbCatch( hr ); }