You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
489 lines
13 KiB
489 lines
13 KiB
#include "precomp.h"
|
|
|
|
|
|
#include "wiadbgp.h"
|
|
|
|
#ifdef WIA_DEBUG
|
|
CWiaDebugger *_global_pWiaDebugger = NULL;
|
|
#endif
|
|
|
|
CWiaDebugger::CWiaDebugger( HINSTANCE hInstance, LPTSTR pszModuleName, BOOL bDisplayUi, BOOL bLogFile, HANDLE hStartedEvent )
|
|
: m_bDisplayUi(bDisplayUi),
|
|
m_bLogFile(bLogFile),
|
|
m_hWnd(NULL),
|
|
m_hLogFile(NULL),
|
|
m_nStackLevel(0),
|
|
m_nFlags(DebugToWindow|DebugToFile|DebugToDebugger|DebugPrintThreadId),
|
|
m_hStartedEvent(hStartedEvent),
|
|
m_dwThreadId(0),
|
|
m_hInstance(hInstance)
|
|
{
|
|
if (pszModuleName)
|
|
lstrcpy( m_szModuleName, pszModuleName );
|
|
else lstrcpy( m_szModuleName, TEXT("") );
|
|
if (bLogFile)
|
|
{
|
|
TCHAR szLogFileName[MAX_PATH]=TEXT("");
|
|
LPTSTR pPtr=szLogFileName;
|
|
GetWindowsDirectory( szLogFileName, MAX_PATH );
|
|
while (*pPtr && *pPtr != TEXT('\\'))
|
|
pPtr++;
|
|
if (*pPtr == TEXT('\\'))
|
|
pPtr++;
|
|
else pPtr = szLogFileName;
|
|
lstrcpy( pPtr, pszModuleName );
|
|
for (int i=lstrlen(szLogFileName);i>0;i--)
|
|
{
|
|
if (szLogFileName[i-1]==TEXT('.'))
|
|
{
|
|
szLogFileName[i-1]=TEXT('\0');
|
|
break;
|
|
}
|
|
}
|
|
lstrcat(szLogFileName, TEXT(".log"));
|
|
if ((m_hLogFile = CreateFile(szLogFileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
m_hLogFile = NULL;
|
|
m_nFlags &= ~DebugToFile;
|
|
OutputDebugString( TEXT("WIADBG: Unable to create log file\n") );
|
|
}
|
|
else
|
|
{
|
|
m_nFlags |= DebugToFile;
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD CWiaDebugger::DebugLoop(void)
|
|
{
|
|
if (m_bDisplayUi)
|
|
{
|
|
m_hWnd = CWiaDebugWindow::Create( m_szModuleName, m_hInstance, true );
|
|
ShowWindow( m_hWnd, SW_SHOW );
|
|
UpdateWindow( m_hWnd );
|
|
}
|
|
SetEvent(m_hStartedEvent);
|
|
MSG msg;
|
|
while (GetMessage(&msg, 0, 0, 0))
|
|
{
|
|
if (!msg.hwnd)
|
|
{
|
|
if (msg.message==WM_CLOSE)
|
|
PostQuitMessage(0);
|
|
}
|
|
else
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD CWiaDebugger::ThreadProc( LPVOID pParam )
|
|
{
|
|
DWORD dwResult = 0;
|
|
CWiaDebugger *This = (CWiaDebugger*)pParam;
|
|
if (This)
|
|
{
|
|
dwResult = (DWORD)This->DebugLoop();
|
|
delete This;
|
|
}
|
|
return dwResult;
|
|
}
|
|
|
|
CWiaDebugger::~CWiaDebugger(void)
|
|
{
|
|
if (m_hThread)
|
|
CloseHandle( m_hThread );
|
|
}
|
|
|
|
|
|
CWiaDebugger * __stdcall CWiaDebugger::Create( HINSTANCE hInstance, LPTSTR pszModuleName, BOOL bDisplayUi, BOOL bLogFile )
|
|
{
|
|
CWiaDebugger *pDebugger = NULL;
|
|
HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
if (hEvent)
|
|
{
|
|
pDebugger = new CWiaDebugger( hInstance, pszModuleName, bDisplayUi, bLogFile, hEvent );
|
|
if (pDebugger)
|
|
{
|
|
pDebugger->m_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (PVOID)pDebugger, 0, &pDebugger->m_dwThreadId );
|
|
if (pDebugger->m_hThread)
|
|
{
|
|
// Wait for up to 5 seconds. If someone tries to create a debug
|
|
// context in the DLL startup code, the wait will fail and
|
|
// we'll output a debug message.
|
|
if (WAIT_TIMEOUT == WaitForSingleObject( hEvent, 5000 )) {
|
|
OutputDebugString(TEXT("Wait failed while creating a debug context. No context creation in DLL startup."));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete pDebugger;
|
|
pDebugger = NULL;
|
|
}
|
|
}
|
|
CloseHandle(hEvent);
|
|
}
|
|
return pDebugger;
|
|
}
|
|
|
|
int CWiaDebugger::AddString( LPCTSTR szStr, COLORREF cr )
|
|
{
|
|
if (!m_hWnd || !IsWindow(m_hWnd))
|
|
{
|
|
return -1;
|
|
}
|
|
LPTSTR pszStr = (LPTSTR)szStr;
|
|
if (pszStr)
|
|
{
|
|
pszStr = (LPTSTR)LocalAlloc(LPTR,(lstrlen(szStr)+1)*sizeof(TCHAR));
|
|
if (pszStr)
|
|
lstrcpy(pszStr,szStr);
|
|
}
|
|
SendMessage( m_hWnd, CWiaDebugWindow::sc_nMsgAddString, (WPARAM)pszStr, (LPARAM)cr);
|
|
return 1;
|
|
}
|
|
|
|
HANDLE CWiaDebugger::SetLogFileHandle( HANDLE hFile )
|
|
{
|
|
HANDLE hOld = m_hLogFile;
|
|
m_hLogFile = hFile;
|
|
return hOld;
|
|
}
|
|
|
|
HANDLE CWiaDebugger::GetLogFileHandle(void)
|
|
{
|
|
return m_hLogFile;
|
|
}
|
|
|
|
void CWiaDebugger::WiaTrace( LPCWSTR lpszFormat, ... )
|
|
{
|
|
WCHAR szMsg[m_nBufferMax];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, lpszFormat);
|
|
::wvsprintfW(szMsg, lpszFormat, arglist);
|
|
va_end(arglist);
|
|
|
|
RouteString( szMsg, RGB(0,0,0) );
|
|
}
|
|
|
|
void CWiaDebugger::WiaTrace( LPCSTR lpszFormat, ... )
|
|
{
|
|
CHAR szMsg[m_nBufferMax];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, lpszFormat);
|
|
::wvsprintfA(szMsg, lpszFormat, arglist);
|
|
va_end(arglist);
|
|
|
|
RouteString( szMsg, RGB(0,0,0) );
|
|
}
|
|
|
|
void CWiaDebugger::PrintColor( COLORREF crColor, LPCWSTR lpszMsg )
|
|
{
|
|
WCHAR szMsg[m_nBufferMax];
|
|
lstrcpyW( szMsg, lpszMsg );
|
|
RouteString( szMsg, crColor );
|
|
}
|
|
|
|
void CWiaDebugger::PrintColor( COLORREF crColor, LPCSTR lpszMsg )
|
|
{
|
|
CHAR szMsg[m_nBufferMax];
|
|
lstrcpyA( szMsg, lpszMsg );
|
|
RouteString( szMsg, crColor );
|
|
}
|
|
|
|
void CWiaDebugger::WiaTrace( HRESULT hr )
|
|
{
|
|
DWORD dwLen;
|
|
LPTSTR pMsgBuf;
|
|
|
|
dwLen = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&pMsgBuf, 0, NULL);
|
|
|
|
if (dwLen)
|
|
{
|
|
RouteString( pMsgBuf, RGB(0,0,0) );
|
|
LocalFree(pMsgBuf);
|
|
}
|
|
else
|
|
WiaTrace( TEXT("WiaError: Can't format WiaError message 0x%08X"), hr );
|
|
}
|
|
|
|
void CWiaDebugger::WiaError( LPCWSTR lpszFormat, ... )
|
|
{
|
|
WCHAR szMsg[m_nBufferMax];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, lpszFormat);
|
|
::wvsprintfW( szMsg, lpszFormat, arglist);
|
|
va_end(arglist);
|
|
|
|
RouteString( szMsg, RGB(255,0,0) );
|
|
}
|
|
|
|
void CWiaDebugger::WiaError( HRESULT hr )
|
|
{
|
|
ULONG ulLen;
|
|
LPTSTR pMsgBuf;
|
|
|
|
ulLen = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&pMsgBuf, 0, NULL);
|
|
|
|
if (ulLen)
|
|
{
|
|
RouteString( pMsgBuf, RGB(255,0,0) );
|
|
LocalFree(pMsgBuf);
|
|
}
|
|
else
|
|
WiaError( TEXT("WiaError: Can't format WiaError message 0x%08X"), hr );
|
|
}
|
|
|
|
void CWiaDebugger::WiaError( LPCSTR lpszFormat, ... )
|
|
{
|
|
CHAR szMsg[m_nBufferMax];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, lpszFormat);
|
|
::wvsprintfA(szMsg, lpszFormat, arglist);
|
|
va_end(arglist);
|
|
|
|
RouteString( szMsg, RGB(255,0,0) );
|
|
}
|
|
|
|
LPTSTR CWiaDebugger::RemoveTrailingCrLf( LPTSTR lpszStr )
|
|
{
|
|
for (int i=lstrlen(lpszStr);i>0;i--)
|
|
if (lpszStr[i-1]==TEXT('\n') || lpszStr[i-1]==TEXT('\r'))
|
|
lpszStr[i-1]=TEXT('\0');
|
|
else break;
|
|
return lpszStr;
|
|
}
|
|
|
|
LPSTR CWiaDebugger::UnicodeToAnsi( LPSTR lpszAnsi, LPTSTR lpszUnicode )
|
|
{
|
|
#if defined(_UNICODE) || defined(UNICODE)
|
|
WideCharToMultiByte( CP_ACP, 0, lpszUnicode, -1, lpszAnsi, lstrlen(lpszUnicode)+1, NULL, NULL );
|
|
#else
|
|
lstrcpy( lpszAnsi, lpszUnicode );
|
|
#endif
|
|
return lpszAnsi;
|
|
}
|
|
|
|
void CWiaDebugger::WriteMessageToFile( LPTSTR lpszMsg )
|
|
{
|
|
HANDLE hFile = GetLogFileHandle();
|
|
if (hFile != NULL && hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwBytes;
|
|
CHAR lpszAnsiMsg[m_nBufferMax];
|
|
UnicodeToAnsi( lpszAnsiMsg, lpszMsg );
|
|
ULONG ulLength = lstrlenA(lpszAnsiMsg);
|
|
WriteFile(hFile, lpszAnsiMsg, ulLength, &dwBytes, NULL);
|
|
FlushFileBuffers(hFile);
|
|
}
|
|
}
|
|
|
|
static BOOL ContainsNonWhitespace( LPTSTR lpszMsg )
|
|
{
|
|
for (LPTSTR lpszPtr = lpszMsg;*lpszPtr;lpszPtr++)
|
|
if (*lpszPtr != TEXT(' ') && *lpszPtr != TEXT('\n') && *lpszPtr != TEXT('\r') && *lpszPtr != TEXT('\t'))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
void CWiaDebugger::PrependString( LPTSTR lpszTgt, LPCTSTR lpszStr )
|
|
{
|
|
if (ContainsNonWhitespace(lpszTgt))
|
|
{
|
|
int iLen = lstrlen(lpszTgt);
|
|
int iThreadIdLen = lstrlen(lpszStr);
|
|
LPTSTR lpszTmp = (LPTSTR)LocalAlloc( LPTR, (iLen + iThreadIdLen + 2)*sizeof(TCHAR));
|
|
if (lpszTmp)
|
|
{
|
|
lstrcpy( lpszTmp, lpszStr );
|
|
lstrcat( lpszTmp, TEXT(" ") );
|
|
lstrcat( lpszTmp, lpszTgt );
|
|
lstrcpy( lpszTgt, lpszTmp );
|
|
LocalFree(lpszTmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CWiaDebugger::PrependThreadId( LPTSTR lpszMsg )
|
|
{
|
|
if (ContainsNonWhitespace(lpszMsg))
|
|
{
|
|
TCHAR szThreadId[20];
|
|
wsprintf( szThreadId, TEXT("[%08X]"), GetCurrentThreadId() );
|
|
PrependString( lpszMsg, szThreadId );
|
|
}
|
|
}
|
|
|
|
|
|
void CWiaDebugger::PrependModuleName( LPTSTR lpszMsg )
|
|
{
|
|
if (ContainsNonWhitespace(lpszMsg))
|
|
{
|
|
TCHAR szModuleName[MAX_PATH+1];
|
|
lstrcpy( szModuleName, m_szModuleName );
|
|
lstrcat( szModuleName, TEXT(":") );
|
|
PrependString( lpszMsg, szModuleName );
|
|
}
|
|
}
|
|
|
|
void CWiaDebugger::InsertStackLevelIndent( LPTSTR lpszMsg, int nStackLevel )
|
|
{
|
|
const LPTSTR lpszIndent = TEXT(" ");
|
|
TCHAR szTmp[m_nBufferMax], *pstrTmp, *pstrPtr;
|
|
pstrTmp=szTmp;
|
|
pstrPtr=lpszMsg;
|
|
while (pstrPtr && *pstrPtr)
|
|
{
|
|
// if the current character is a newline and it isn't the
|
|
// last character, append the indent string
|
|
if (*pstrPtr==TEXT('\n') && ContainsNonWhitespace(pstrPtr))
|
|
{
|
|
*pstrTmp++ = *pstrPtr++;
|
|
for (int i=0;i<nStackLevel;i++)
|
|
{
|
|
lstrcpy(pstrTmp,lpszIndent);
|
|
pstrTmp += lstrlen(lpszIndent);
|
|
}
|
|
}
|
|
// If this is the first character, insert the indent string before the
|
|
// first character
|
|
else if (pstrPtr == lpszMsg && ContainsNonWhitespace(pstrPtr))
|
|
{
|
|
for (int i=0;i<nStackLevel;i++)
|
|
{
|
|
lstrcpy(pstrTmp,lpszIndent);
|
|
pstrTmp += lstrlen(lpszIndent);
|
|
}
|
|
*pstrTmp++ = *pstrPtr++;
|
|
}
|
|
else *pstrTmp++ = *pstrPtr++;
|
|
}
|
|
*pstrTmp = TEXT('\0');
|
|
lstrcpy( lpszMsg, szTmp );
|
|
}
|
|
|
|
LPTSTR CWiaDebugger::AnsiToTChar( LPCSTR pszAnsi, LPTSTR pszTChar )
|
|
{
|
|
#if defined(UNICODE) || defined(_UNICODE)
|
|
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszAnsi, lstrlenA(pszAnsi)+1, pszTChar, m_nBufferMax );
|
|
#else
|
|
lstrcpyA( pszTChar, pszAnsi );
|
|
#endif
|
|
return pszTChar;
|
|
}
|
|
|
|
LPTSTR CWiaDebugger::WideToTChar( LPWSTR pszWide, LPTSTR pszTChar )
|
|
{
|
|
#if !defined(UNICODE) && !defined(_UNICODE)
|
|
WideCharToMultiByte( CP_ACP, 0, pszWide, lstrlenW(pszWide)+1, pszTChar, m_nBufferMax, NULL, NULL );
|
|
#else
|
|
lstrcpyW( pszTChar, pszWide );
|
|
#endif
|
|
return pszTChar;
|
|
}
|
|
|
|
void CWiaDebugger::RouteString( LPWSTR lpszMsg, COLORREF nColor )
|
|
{
|
|
TCHAR szMsg[m_nBufferMax];
|
|
WideToTChar( lpszMsg, szMsg );
|
|
// Remove extra CRs and LFs - we want to control them
|
|
RemoveTrailingCrLf( szMsg );
|
|
if (m_nFlags & DebugPrintModuleName)
|
|
PrependModuleName( szMsg );
|
|
if (m_nFlags & DebugPrintThreadId)
|
|
PrependThreadId( szMsg );
|
|
InsertStackLevelIndent( szMsg, GetStackLevel() );
|
|
if (m_nFlags & DebugToWindow)
|
|
AddString( szMsg, nColor );
|
|
#ifdef WIA_DEBUG
|
|
if (m_nFlags & DebugToDebugger)
|
|
{
|
|
OutputDebugString( szMsg );
|
|
OutputDebugString( TEXT("\n") );
|
|
}
|
|
#endif
|
|
if (m_nFlags & DebugToFile)
|
|
{
|
|
WriteMessageToFile( szMsg );
|
|
WriteMessageToFile( TEXT("\n") );
|
|
}
|
|
}
|
|
|
|
void CWiaDebugger::RouteString( LPSTR lpszMsg, COLORREF nColor )
|
|
{
|
|
TCHAR szMsg[m_nBufferMax];
|
|
AnsiToTChar( lpszMsg, szMsg );
|
|
// Remove extra CRs and LFs - we want to control them
|
|
RemoveTrailingCrLf( szMsg );
|
|
if (m_nFlags & DebugPrintModuleName)
|
|
PrependModuleName( szMsg );
|
|
if (m_nFlags & DebugPrintThreadId)
|
|
PrependThreadId( szMsg );
|
|
InsertStackLevelIndent( szMsg, GetStackLevel() );
|
|
if (m_nFlags & DebugToWindow)
|
|
AddString( szMsg, nColor );
|
|
#ifdef WIA_DEBUG
|
|
if (m_nFlags & DebugToDebugger)
|
|
{
|
|
OutputDebugString( szMsg );
|
|
OutputDebugString( TEXT("\n") );
|
|
}
|
|
#endif
|
|
if (m_nFlags & DebugToFile)
|
|
{
|
|
WriteMessageToFile( szMsg );
|
|
WriteMessageToFile( TEXT("\n") );
|
|
}
|
|
}
|
|
|
|
int CWiaDebugger::SetDebugFlags( int nDebugFlags )
|
|
{
|
|
int nOld = m_nFlags;
|
|
m_nFlags = nDebugFlags;
|
|
return nOld;
|
|
}
|
|
|
|
int CWiaDebugger::GetDebugFlags(void)
|
|
{
|
|
return m_nFlags;
|
|
}
|
|
|
|
int CWiaDebugger::GetStackLevel(void)
|
|
{
|
|
return m_nStackLevel;
|
|
}
|
|
|
|
int CWiaDebugger::PushLevel( LPCTSTR lpszFunctionName )
|
|
{
|
|
WiaTrace( TEXT("Entering function %s, (Level %d)"), lpszFunctionName, GetStackLevel() );
|
|
return m_nStackLevel++;
|
|
}
|
|
|
|
int CWiaDebugger::PopLevel( LPCTSTR lpszFunctionName )
|
|
{
|
|
m_nStackLevel--;
|
|
if (m_nStackLevel < 0)
|
|
m_nStackLevel = 0;
|
|
if (!m_nStackLevel)
|
|
WiaTrace( TEXT("\n") );
|
|
return m_nStackLevel;
|
|
}
|
|
|