//==========================================================================; // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR // PURPOSE. // // Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. // //--------------------------------------------------------------------------; // For every module and executable we store a debugging level and flags // for the types of output that are desired. Constants for the types are // defined in WXDEBUG.H and more can be added. // The keys are stored in the registry under the // HKEY_LOCAL_MACHINE\SOFTWARE\Debug\<Module Name>\Type and // HKEY_LOCAL_MACHINE\SOFTWARE\Debug\<Module Name>\Level key values // // There are also global values under SOFTWARE\Debug\Global which are loaded // after the module-specific values. The Types specified there are OR'ed with // the module specific types and m_dwLevel is set to the greater of the global // and the module specific settings. #include <stdarg.h> #include <stdio.h> #include "extdll.h" #include "util.h" #include "wxdebug.h" #include <tchar.h> #ifdef _DEBUG void WINAPI DbgInitModuleName(void); void WINAPI DbgInitModuleSettings(void); void WINAPI DbgInitGlobalSettings(void); void WINAPI DbgInitLogTo(HKEY hKey); void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel); const INT iDEBUGINFO = 512; // Used to format strings HINSTANCE m_hInst; // Module instance handle TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name //CRITICAL_SECTION m_CSDebug; // Controls access to list BOOL m_bInit = FALSE; // Have we been initialised HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here DWORD m_dwTypes = 0; DWORD m_dwLevel = 0; const TCHAR *m_pBaseKey = TEXT("SOFTWARE\\Debug"); const TCHAR *m_pGlobalKey = TEXT("GLOBAL"); TCHAR *pKeyNames[] = { TEXT("Types"), TEXT("Level") }; // DbgInitialize // This sets the instance handle that the debug library uses to find // the module's file name from the Win32 GetModuleFileName function void WINAPI DbgInitialise(HINSTANCE hInst) { if (!m_bInit) { //InitializeCriticalSection(&m_CSDebug); m_bInit = TRUE; m_hInst = hInst; DbgInitModuleName(); DbgInitModuleSettings(); DbgInitGlobalSettings(); } } // DbgTerminate // This is called to clear up any resources the debug library uses - at the // moment we delete our critical section and the handle of the output file. void WINAPI DbgTerminate() { if (m_bInit) { if (m_hOutput != INVALID_HANDLE_VALUE) { DBGASSERTEXECUTE(CloseHandle(m_hOutput)); m_hOutput = INVALID_HANDLE_VALUE; } //DeleteCriticalSection(&m_CSDebug); m_bInit = FALSE; } } // DbgInitModuleName // Initialise the module file name void WINAPI DbgInitModuleName() { TCHAR FullName[iDEBUGINFO]; // Load the full path and module name TCHAR *pName; // Searches from the end for a backslash GetModuleFileName(m_hInst,FullName,iDEBUGINFO); pName = _tcsrchr(FullName,'\\'); if (pName == NULL) { pName = FullName; } else { pName++; } lstrcpy(m_ModuleName,pName); } // DbgInitModuleSettings // Retrieve the module-specific settings void WINAPI DbgInitModuleSettings() { LONG lReturn; // Create key return value TCHAR szInfo[iDEBUGINFO]; // Constructs key names HKEY hModuleKey; // Module key handle // Construct the base key name wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_ModuleName); // Create or open the key for this module lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key szInfo, // Address of subkey name (DWORD)0, // Reserved value NULL, // Address of class name (DWORD)0, // Special options flags KEY_ALL_ACCESS, // Desired security access NULL, // Key security descriptor &hModuleKey, // Opened handle buffer NULL); // What really happened if (lReturn != ERROR_SUCCESS) { DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access module key")); return; } DbgInitLogTo(hModuleKey); DbgInitKeyLevels(hModuleKey, &m_dwTypes, &m_dwLevel); RegCloseKey(hModuleKey); } // DbgInitGlobalSettings // This is called by DbgInitialize to read the global debug settings for // Level and Type from the registry. The Types are OR'ed together and m_dwLevel // is set to the greater of the global and module-specific values. void WINAPI DbgInitGlobalSettings() { LONG lReturn; // Create key return value TCHAR szInfo[iDEBUGINFO]; // Constructs key names HKEY hGlobalKey; // Global override key DWORD dwTypes = 0; DWORD dwLevel = 0; // Construct the global base key name wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_pGlobalKey); // Create or open the key for this module lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key szInfo, // Address of subkey name (DWORD)0, // Reserved value NULL, // Address of class name (DWORD)0, // Special options flags KEY_ALL_ACCESS, // Desired security access NULL, // Key security descriptor &hGlobalKey, // Opened handle buffer NULL); // What really happened if (lReturn != ERROR_SUCCESS) { DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access GLOBAL module key")); return; } DbgInitKeyLevels(hGlobalKey, &dwTypes, &dwLevel); RegCloseKey(hGlobalKey); m_dwTypes |= dwTypes; if (dwLevel > m_dwLevel) m_dwLevel = dwLevel; } // DbgInitLogTo // Called by DbgInitModuleSettings to setup alternate logging destinations void WINAPI DbgInitLogTo(HKEY hKey) { LONG lReturn; DWORD dwKeyType; DWORD dwKeySize; TCHAR szFile[MAX_PATH] = {0}; static const TCHAR cszKey[] = TEXT("LogToFile"); dwKeySize = MAX_PATH; lReturn = RegQueryValueEx( hKey, // Handle to an open key cszKey, // Subkey name derivation NULL, // Reserved field &dwKeyType, // Returns the field type (LPBYTE) szFile, // Returns the field's value &dwKeySize); // Number of bytes transferred // create an empty key if it does not already exist if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) { dwKeySize = 1; lReturn = RegSetValueEx( hKey, // Handle of an open key cszKey, // Address of subkey name (DWORD) 0, // Reserved field REG_SZ, // Type of the key field (PBYTE)szFile, // Value for the field dwKeySize); // Size of the field buffer } // if an output-to was specified. try to open it. if (m_hOutput != INVALID_HANDLE_VALUE) { DBGASSERTEXECUTE(CloseHandle(m_hOutput)); m_hOutput = INVALID_HANDLE_VALUE; } if (szFile[0] != 0) { if (!lstrcmpi(szFile, TEXT("Console"))) { m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); if (m_hOutput == INVALID_HANDLE_VALUE) { AllocConsole(); m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); } SetConsoleTitle (TEXT("Valve Debug Output")); } else if (szFile[0] && lstrcmpi(szFile, TEXT("Debug")) && lstrcmpi(szFile, TEXT("Debugger")) && lstrcmpi(szFile, TEXT("Deb"))) { m_hOutput = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != m_hOutput) { static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); SetFilePointer (m_hOutput, 0, NULL, FILE_END); DbgOutString (cszBar); } } } } // DbgInitKeyLevels // This is called by DbgInitModuleSettings and DbgInitGlobalSettings to read // settings for Types and Level from the registry void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel) { LONG lReturn; // Create key return value DWORD dwKeySize; // Size of the key value DWORD dwKeyType; // Receives it's type // Get the Types value dwKeySize = sizeof(DWORD); lReturn = RegQueryValueEx( hKey, // Handle to an open key pKeyNames[0], // Subkey name derivation NULL, // Reserved field &dwKeyType, // Returns the field type (LPBYTE)pdwTypes, // Returns the field's value &dwKeySize ); // Number of bytes transferred // If either the key was not available or it was not a DWORD value // then we ensure only the high priority debug logging is output // but we try and update the field to a zero filled DWORD value if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { *pdwTypes = 0; lReturn = RegSetValueEx( hKey, // Handle of an open key pKeyNames[0], // Address of subkey name (DWORD)0, // Reserved field REG_DWORD, // Type of the key field (PBYTE)pdwTypes, // Value for the field sizeof(DWORD)); // Size of the field buffer if (lReturn != ERROR_SUCCESS) { DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[0]); *pdwTypes = 0; } } // Get the Level value dwKeySize = sizeof(DWORD); lReturn = RegQueryValueEx( hKey, // Handle to an open key pKeyNames[1], // Subkey name derivation NULL, // Reserved field &dwKeyType, // Returns the field type (LPBYTE)pdwLevel, // Returns the field's value &dwKeySize ); // Number of bytes transferred // If either the key was not available or it was not a DWORD value // then we ensure only the high priority debug logging is output // but we try and update the field to a zero filled DWORD value if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { *pdwLevel = 0; lReturn = RegSetValueEx( hKey, // Handle of an open key pKeyNames[1], // Address of subkey name (DWORD)0, // Reserved field REG_DWORD, // Type of the key field (PBYTE)pdwLevel, // Value for the field sizeof(DWORD)); // Size of the field buffer if (lReturn != ERROR_SUCCESS) { DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[1]); *pdwLevel = 0; } } } // DbgOutString void WINAPI DbgOutString(LPCTSTR psz) { if (!m_bInit) return; if (m_hOutput != INVALID_HANDLE_VALUE) { UINT cb = lstrlen(psz); DWORD dw; WriteFile (m_hOutput, psz, cb, &dw, NULL); } else { OutputDebugString (psz); } } // DbgLogInfo // Print a formatted string to the debugger prefixed with this module's name // Because the debug code is linked statically every module loaded will // have its own copy of this code. It therefore helps if the module name is // included on the output so that the offending code can be easily found void WINAPI DbgLogInfo(DWORD Type, DWORD Level, const TCHAR *pFormat,...) { if (!m_bInit) return; // Check the current level for this type combination */ if (((Type & m_dwTypes) == 0) || (m_dwLevel < Level)) return; TCHAR szInfo[2000]; // Format the variable length parameter list va_list va; va_start(va, pFormat); //lstrcpy(szInfo, m_ModuleName); //lstrcat(szInfo, TEXT(": ")); wvsprintf(szInfo /* + lstrlen(szInfo) */, pFormat, va); //lstrcat(szInfo, TEXT("\r\n")); DbgOutString(szInfo); va_end(va); } // DbgKernelAssert // If we are executing as a pure kernel filter we cannot display message // boxes to the user, this provides an alternative which puts the error // condition on the debugger output with a suitable eye catching message void WINAPI DbgKernelAssert(const TCHAR *pCondition, const TCHAR *pFileName, INT iLine) { if (!m_bInit) return; DbgLogInfo(LOG_ERROR, 0, TEXT(m_ModuleName)); DbgLogInfo(LOG_ERROR, 0, TEXT(": Assertion FAILED (%s) at line %d in file %s\r\n"), pCondition, iLine, pFileName); DebugBreak(); } #endif // _DEBUG