Leaked source code of windows server 2003
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

  1. #include "precomp.h"
  2. #include "wiadbgp.h"
  3. #ifdef WIA_DEBUG
  4. CWiaDebugger *_global_pWiaDebugger = NULL;
  5. #endif
  6. CWiaDebugger::CWiaDebugger( HINSTANCE hInstance, LPTSTR pszModuleName, BOOL bDisplayUi, BOOL bLogFile, HANDLE hStartedEvent )
  7. : m_bDisplayUi(bDisplayUi),
  8. m_bLogFile(bLogFile),
  9. m_hWnd(NULL),
  10. m_hLogFile(NULL),
  11. m_nStackLevel(0),
  12. m_nFlags(DebugToWindow|DebugToFile|DebugToDebugger|DebugPrintThreadId),
  13. m_hStartedEvent(hStartedEvent),
  14. m_dwThreadId(0),
  15. m_hInstance(hInstance)
  16. {
  17. if (pszModuleName)
  18. lstrcpy( m_szModuleName, pszModuleName );
  19. else lstrcpy( m_szModuleName, TEXT("") );
  20. if (bLogFile)
  21. {
  22. TCHAR szLogFileName[MAX_PATH]=TEXT("");
  23. LPTSTR pPtr=szLogFileName;
  24. GetWindowsDirectory( szLogFileName, MAX_PATH );
  25. while (*pPtr && *pPtr != TEXT('\\'))
  26. pPtr++;
  27. if (*pPtr == TEXT('\\'))
  28. pPtr++;
  29. else pPtr = szLogFileName;
  30. lstrcpy( pPtr, pszModuleName );
  31. for (int i=lstrlen(szLogFileName);i>0;i--)
  32. {
  33. if (szLogFileName[i-1]==TEXT('.'))
  34. {
  35. szLogFileName[i-1]=TEXT('\0');
  36. break;
  37. }
  38. }
  39. lstrcat(szLogFileName, TEXT(".log"));
  40. if ((m_hLogFile = CreateFile(szLogFileName,
  41. GENERIC_WRITE,
  42. FILE_SHARE_WRITE,
  43. NULL,
  44. CREATE_ALWAYS,
  45. FILE_ATTRIBUTE_NORMAL,
  46. NULL)) == INVALID_HANDLE_VALUE)
  47. {
  48. m_hLogFile = NULL;
  49. m_nFlags &= ~DebugToFile;
  50. OutputDebugString( TEXT("WIADBG: Unable to create log file\n") );
  51. }
  52. else
  53. {
  54. m_nFlags |= DebugToFile;
  55. }
  56. }
  57. }
  58. DWORD CWiaDebugger::DebugLoop(void)
  59. {
  60. if (m_bDisplayUi)
  61. {
  62. m_hWnd = CWiaDebugWindow::Create( m_szModuleName, m_hInstance, true );
  63. ShowWindow( m_hWnd, SW_SHOW );
  64. UpdateWindow( m_hWnd );
  65. }
  66. SetEvent(m_hStartedEvent);
  67. MSG msg;
  68. while (GetMessage(&msg, 0, 0, 0))
  69. {
  70. if (!msg.hwnd)
  71. {
  72. if (msg.message==WM_CLOSE)
  73. PostQuitMessage(0);
  74. }
  75. else
  76. {
  77. TranslateMessage(&msg);
  78. DispatchMessage(&msg);
  79. }
  80. }
  81. return 0;
  82. }
  83. DWORD CWiaDebugger::ThreadProc( LPVOID pParam )
  84. {
  85. DWORD dwResult = 0;
  86. CWiaDebugger *This = (CWiaDebugger*)pParam;
  87. if (This)
  88. {
  89. dwResult = (DWORD)This->DebugLoop();
  90. delete This;
  91. }
  92. return dwResult;
  93. }
  94. CWiaDebugger::~CWiaDebugger(void)
  95. {
  96. if (m_hThread)
  97. CloseHandle( m_hThread );
  98. }
  99. CWiaDebugger * __stdcall CWiaDebugger::Create( HINSTANCE hInstance, LPTSTR pszModuleName, BOOL bDisplayUi, BOOL bLogFile )
  100. {
  101. CWiaDebugger *pDebugger = NULL;
  102. HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  103. if (hEvent)
  104. {
  105. pDebugger = new CWiaDebugger( hInstance, pszModuleName, bDisplayUi, bLogFile, hEvent );
  106. if (pDebugger)
  107. {
  108. pDebugger->m_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (PVOID)pDebugger, 0, &pDebugger->m_dwThreadId );
  109. if (pDebugger->m_hThread)
  110. {
  111. // Wait for up to 5 seconds. If someone tries to create a debug
  112. // context in the DLL startup code, the wait will fail and
  113. // we'll output a debug message.
  114. if (WAIT_TIMEOUT == WaitForSingleObject( hEvent, 5000 )) {
  115. OutputDebugString(TEXT("Wait failed while creating a debug context. No context creation in DLL startup."));
  116. }
  117. }
  118. else
  119. {
  120. delete pDebugger;
  121. pDebugger = NULL;
  122. }
  123. }
  124. CloseHandle(hEvent);
  125. }
  126. return pDebugger;
  127. }
  128. int CWiaDebugger::AddString( LPCTSTR szStr, COLORREF cr )
  129. {
  130. if (!m_hWnd || !IsWindow(m_hWnd))
  131. {
  132. return -1;
  133. }
  134. LPTSTR pszStr = (LPTSTR)szStr;
  135. if (pszStr)
  136. {
  137. pszStr = (LPTSTR)LocalAlloc(LPTR,(lstrlen(szStr)+1)*sizeof(TCHAR));
  138. if (pszStr)
  139. lstrcpy(pszStr,szStr);
  140. }
  141. SendMessage( m_hWnd, CWiaDebugWindow::sc_nMsgAddString, (WPARAM)pszStr, (LPARAM)cr);
  142. return 1;
  143. }
  144. HANDLE CWiaDebugger::SetLogFileHandle( HANDLE hFile )
  145. {
  146. HANDLE hOld = m_hLogFile;
  147. m_hLogFile = hFile;
  148. return hOld;
  149. }
  150. HANDLE CWiaDebugger::GetLogFileHandle(void)
  151. {
  152. return m_hLogFile;
  153. }
  154. void CWiaDebugger::WiaTrace( LPCWSTR lpszFormat, ... )
  155. {
  156. WCHAR szMsg[m_nBufferMax];
  157. va_list arglist;
  158. va_start(arglist, lpszFormat);
  159. ::wvsprintfW(szMsg, lpszFormat, arglist);
  160. va_end(arglist);
  161. RouteString( szMsg, RGB(0,0,0) );
  162. }
  163. void CWiaDebugger::WiaTrace( LPCSTR lpszFormat, ... )
  164. {
  165. CHAR szMsg[m_nBufferMax];
  166. va_list arglist;
  167. va_start(arglist, lpszFormat);
  168. ::wvsprintfA(szMsg, lpszFormat, arglist);
  169. va_end(arglist);
  170. RouteString( szMsg, RGB(0,0,0) );
  171. }
  172. void CWiaDebugger::PrintColor( COLORREF crColor, LPCWSTR lpszMsg )
  173. {
  174. WCHAR szMsg[m_nBufferMax];
  175. lstrcpyW( szMsg, lpszMsg );
  176. RouteString( szMsg, crColor );
  177. }
  178. void CWiaDebugger::PrintColor( COLORREF crColor, LPCSTR lpszMsg )
  179. {
  180. CHAR szMsg[m_nBufferMax];
  181. lstrcpyA( szMsg, lpszMsg );
  182. RouteString( szMsg, crColor );
  183. }
  184. void CWiaDebugger::WiaTrace( HRESULT hr )
  185. {
  186. DWORD dwLen;
  187. LPTSTR pMsgBuf;
  188. dwLen = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  189. NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  190. (LPTSTR)&pMsgBuf, 0, NULL);
  191. if (dwLen)
  192. {
  193. RouteString( pMsgBuf, RGB(0,0,0) );
  194. LocalFree(pMsgBuf);
  195. }
  196. else
  197. WiaTrace( TEXT("WiaError: Can't format WiaError message 0x%08X"), hr );
  198. }
  199. void CWiaDebugger::WiaError( LPCWSTR lpszFormat, ... )
  200. {
  201. WCHAR szMsg[m_nBufferMax];
  202. va_list arglist;
  203. va_start(arglist, lpszFormat);
  204. ::wvsprintfW( szMsg, lpszFormat, arglist);
  205. va_end(arglist);
  206. RouteString( szMsg, RGB(255,0,0) );
  207. }
  208. void CWiaDebugger::WiaError( HRESULT hr )
  209. {
  210. ULONG ulLen;
  211. LPTSTR pMsgBuf;
  212. ulLen = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  213. NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  214. (LPTSTR)&pMsgBuf, 0, NULL);
  215. if (ulLen)
  216. {
  217. RouteString( pMsgBuf, RGB(255,0,0) );
  218. LocalFree(pMsgBuf);
  219. }
  220. else
  221. WiaError( TEXT("WiaError: Can't format WiaError message 0x%08X"), hr );
  222. }
  223. void CWiaDebugger::WiaError( LPCSTR lpszFormat, ... )
  224. {
  225. CHAR szMsg[m_nBufferMax];
  226. va_list arglist;
  227. va_start(arglist, lpszFormat);
  228. ::wvsprintfA(szMsg, lpszFormat, arglist);
  229. va_end(arglist);
  230. RouteString( szMsg, RGB(255,0,0) );
  231. }
  232. LPTSTR CWiaDebugger::RemoveTrailingCrLf( LPTSTR lpszStr )
  233. {
  234. for (int i=lstrlen(lpszStr);i>0;i--)
  235. if (lpszStr[i-1]==TEXT('\n') || lpszStr[i-1]==TEXT('\r'))
  236. lpszStr[i-1]=TEXT('\0');
  237. else break;
  238. return lpszStr;
  239. }
  240. LPSTR CWiaDebugger::UnicodeToAnsi( LPSTR lpszAnsi, LPTSTR lpszUnicode )
  241. {
  242. #if defined(_UNICODE) || defined(UNICODE)
  243. WideCharToMultiByte( CP_ACP, 0, lpszUnicode, -1, lpszAnsi, lstrlen(lpszUnicode)+1, NULL, NULL );
  244. #else
  245. lstrcpy( lpszAnsi, lpszUnicode );
  246. #endif
  247. return lpszAnsi;
  248. }
  249. void CWiaDebugger::WriteMessageToFile( LPTSTR lpszMsg )
  250. {
  251. HANDLE hFile = GetLogFileHandle();
  252. if (hFile != NULL && hFile != INVALID_HANDLE_VALUE)
  253. {
  254. DWORD dwBytes;
  255. CHAR lpszAnsiMsg[m_nBufferMax];
  256. UnicodeToAnsi( lpszAnsiMsg, lpszMsg );
  257. ULONG ulLength = lstrlenA(lpszAnsiMsg);
  258. WriteFile(hFile, lpszAnsiMsg, ulLength, &dwBytes, NULL);
  259. FlushFileBuffers(hFile);
  260. }
  261. }
  262. static BOOL ContainsNonWhitespace( LPTSTR lpszMsg )
  263. {
  264. for (LPTSTR lpszPtr = lpszMsg;*lpszPtr;lpszPtr++)
  265. if (*lpszPtr != TEXT(' ') && *lpszPtr != TEXT('\n') && *lpszPtr != TEXT('\r') && *lpszPtr != TEXT('\t'))
  266. return TRUE;
  267. return FALSE;
  268. }
  269. void CWiaDebugger::PrependString( LPTSTR lpszTgt, LPCTSTR lpszStr )
  270. {
  271. if (ContainsNonWhitespace(lpszTgt))
  272. {
  273. int iLen = lstrlen(lpszTgt);
  274. int iThreadIdLen = lstrlen(lpszStr);
  275. LPTSTR lpszTmp = (LPTSTR)LocalAlloc( LPTR, (iLen + iThreadIdLen + 2)*sizeof(TCHAR));
  276. if (lpszTmp)
  277. {
  278. lstrcpy( lpszTmp, lpszStr );
  279. lstrcat( lpszTmp, TEXT(" ") );
  280. lstrcat( lpszTmp, lpszTgt );
  281. lstrcpy( lpszTgt, lpszTmp );
  282. LocalFree(lpszTmp);
  283. }
  284. }
  285. }
  286. void CWiaDebugger::PrependThreadId( LPTSTR lpszMsg )
  287. {
  288. if (ContainsNonWhitespace(lpszMsg))
  289. {
  290. TCHAR szThreadId[20];
  291. wsprintf( szThreadId, TEXT("[%08X]"), GetCurrentThreadId() );
  292. PrependString( lpszMsg, szThreadId );
  293. }
  294. }
  295. void CWiaDebugger::PrependModuleName( LPTSTR lpszMsg )
  296. {
  297. if (ContainsNonWhitespace(lpszMsg))
  298. {
  299. TCHAR szModuleName[MAX_PATH+1];
  300. lstrcpy( szModuleName, m_szModuleName );
  301. lstrcat( szModuleName, TEXT(":") );
  302. PrependString( lpszMsg, szModuleName );
  303. }
  304. }
  305. void CWiaDebugger::InsertStackLevelIndent( LPTSTR lpszMsg, int nStackLevel )
  306. {
  307. const LPTSTR lpszIndent = TEXT(" ");
  308. TCHAR szTmp[m_nBufferMax], *pstrTmp, *pstrPtr;
  309. pstrTmp=szTmp;
  310. pstrPtr=lpszMsg;
  311. while (pstrPtr && *pstrPtr)
  312. {
  313. // if the current character is a newline and it isn't the
  314. // last character, append the indent string
  315. if (*pstrPtr==TEXT('\n') && ContainsNonWhitespace(pstrPtr))
  316. {
  317. *pstrTmp++ = *pstrPtr++;
  318. for (int i=0;i<nStackLevel;i++)
  319. {
  320. lstrcpy(pstrTmp,lpszIndent);
  321. pstrTmp += lstrlen(lpszIndent);
  322. }
  323. }
  324. // If this is the first character, insert the indent string before the
  325. // first character
  326. else if (pstrPtr == lpszMsg && ContainsNonWhitespace(pstrPtr))
  327. {
  328. for (int i=0;i<nStackLevel;i++)
  329. {
  330. lstrcpy(pstrTmp,lpszIndent);
  331. pstrTmp += lstrlen(lpszIndent);
  332. }
  333. *pstrTmp++ = *pstrPtr++;
  334. }
  335. else *pstrTmp++ = *pstrPtr++;
  336. }
  337. *pstrTmp = TEXT('\0');
  338. lstrcpy( lpszMsg, szTmp );
  339. }
  340. LPTSTR CWiaDebugger::AnsiToTChar( LPCSTR pszAnsi, LPTSTR pszTChar )
  341. {
  342. #if defined(UNICODE) || defined(_UNICODE)
  343. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszAnsi, lstrlenA(pszAnsi)+1, pszTChar, m_nBufferMax );
  344. #else
  345. lstrcpyA( pszTChar, pszAnsi );
  346. #endif
  347. return pszTChar;
  348. }
  349. LPTSTR CWiaDebugger::WideToTChar( LPWSTR pszWide, LPTSTR pszTChar )
  350. {
  351. #if !defined(UNICODE) && !defined(_UNICODE)
  352. WideCharToMultiByte( CP_ACP, 0, pszWide, lstrlenW(pszWide)+1, pszTChar, m_nBufferMax, NULL, NULL );
  353. #else
  354. lstrcpyW( pszTChar, pszWide );
  355. #endif
  356. return pszTChar;
  357. }
  358. void CWiaDebugger::RouteString( LPWSTR lpszMsg, COLORREF nColor )
  359. {
  360. TCHAR szMsg[m_nBufferMax];
  361. WideToTChar( lpszMsg, szMsg );
  362. // Remove extra CRs and LFs - we want to control them
  363. RemoveTrailingCrLf( szMsg );
  364. if (m_nFlags & DebugPrintModuleName)
  365. PrependModuleName( szMsg );
  366. if (m_nFlags & DebugPrintThreadId)
  367. PrependThreadId( szMsg );
  368. InsertStackLevelIndent( szMsg, GetStackLevel() );
  369. if (m_nFlags & DebugToWindow)
  370. AddString( szMsg, nColor );
  371. #ifdef WIA_DEBUG
  372. if (m_nFlags & DebugToDebugger)
  373. {
  374. OutputDebugString( szMsg );
  375. OutputDebugString( TEXT("\n") );
  376. }
  377. #endif
  378. if (m_nFlags & DebugToFile)
  379. {
  380. WriteMessageToFile( szMsg );
  381. WriteMessageToFile( TEXT("\n") );
  382. }
  383. }
  384. void CWiaDebugger::RouteString( LPSTR lpszMsg, COLORREF nColor )
  385. {
  386. TCHAR szMsg[m_nBufferMax];
  387. AnsiToTChar( lpszMsg, szMsg );
  388. // Remove extra CRs and LFs - we want to control them
  389. RemoveTrailingCrLf( szMsg );
  390. if (m_nFlags & DebugPrintModuleName)
  391. PrependModuleName( szMsg );
  392. if (m_nFlags & DebugPrintThreadId)
  393. PrependThreadId( szMsg );
  394. InsertStackLevelIndent( szMsg, GetStackLevel() );
  395. if (m_nFlags & DebugToWindow)
  396. AddString( szMsg, nColor );
  397. #ifdef WIA_DEBUG
  398. if (m_nFlags & DebugToDebugger)
  399. {
  400. OutputDebugString( szMsg );
  401. OutputDebugString( TEXT("\n") );
  402. }
  403. #endif
  404. if (m_nFlags & DebugToFile)
  405. {
  406. WriteMessageToFile( szMsg );
  407. WriteMessageToFile( TEXT("\n") );
  408. }
  409. }
  410. int CWiaDebugger::SetDebugFlags( int nDebugFlags )
  411. {
  412. int nOld = m_nFlags;
  413. m_nFlags = nDebugFlags;
  414. return nOld;
  415. }
  416. int CWiaDebugger::GetDebugFlags(void)
  417. {
  418. return m_nFlags;
  419. }
  420. int CWiaDebugger::GetStackLevel(void)
  421. {
  422. return m_nStackLevel;
  423. }
  424. int CWiaDebugger::PushLevel( LPCTSTR lpszFunctionName )
  425. {
  426. WiaTrace( TEXT("Entering function %s, (Level %d)"), lpszFunctionName, GetStackLevel() );
  427. return m_nStackLevel++;
  428. }
  429. int CWiaDebugger::PopLevel( LPCTSTR lpszFunctionName )
  430. {
  431. m_nStackLevel--;
  432. if (m_nStackLevel < 0)
  433. m_nStackLevel = 0;
  434. if (!m_nStackLevel)
  435. WiaTrace( TEXT("\n") );
  436. return m_nStackLevel;
  437. }