Source code of Windows XP (NT5)
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.

710 lines
17 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. Author:
  6. Revision History:
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. HANDLE hDebugLog;
  11. Winnt32DebugLevel DebugLevel;
  12. BOOL
  13. StartDebugLog(
  14. IN LPCTSTR DebugFileLog,
  15. IN Winnt32DebugLevel Level
  16. )
  17. /*++
  18. Routine Description:
  19. Create a file to be used for logging debugging information.
  20. Note: There can be only one debug log. Second and subsequent
  21. calls to this routine return TRUE if a debug log is already in use.
  22. Arguments:
  23. DebugFileLog - supplies filename of file to be used for debugging log.
  24. Level - supplies logging level desired.
  25. Return Value:
  26. Boolean value indicating whether the file log was successfully started.
  27. --*/
  28. {
  29. DWORD Written;
  30. TCHAR Text[512];
  31. if(hDebugLog) {
  32. return(TRUE);
  33. }
  34. if(Level > Winnt32LogMax) {
  35. Level = Winnt32LogMax;
  36. }
  37. DebugLevel = Level;
  38. hDebugLog = CreateFile(
  39. DebugFileLog,
  40. GENERIC_WRITE,
  41. FILE_SHARE_READ,
  42. NULL,
  43. Winnt32Restarted () ? OPEN_ALWAYS : CREATE_ALWAYS,
  44. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  45. NULL
  46. );
  47. if(hDebugLog == INVALID_HANDLE_VALUE) {
  48. hDebugLog = NULL;
  49. return(FALSE);
  50. }
  51. if(GetLastError() == ERROR_ALREADY_EXISTS) {
  52. //
  53. // Appending to existing file
  54. //
  55. SetFilePointer(hDebugLog,0,NULL,FILE_END);
  56. LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR) );
  57. DebugLog(
  58. Winnt32LogMax,
  59. Text,
  60. 0
  61. );
  62. }
  63. if( CheckUpgradeOnly ) {
  64. LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR) );
  65. DebugLog( Winnt32LogInformation,
  66. Text,
  67. 0 );
  68. LoadString( hInst, IDS_APPTITLE_CHECKUPGRADE, Text, sizeof(Text)/sizeof(TCHAR) );
  69. DebugLog( Winnt32LogInformation,
  70. Text,
  71. 0 );
  72. LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR) );
  73. DebugLog( Winnt32LogInformation,
  74. Text,
  75. 0 );
  76. }
  77. return(TRUE);
  78. }
  79. VOID
  80. CloseDebugLog(
  81. VOID
  82. )
  83. /*++
  84. Routine Description:
  85. Close the logging file.
  86. Arguments:
  87. Return Value:
  88. --*/
  89. {
  90. if( hDebugLog ) {
  91. CloseHandle( hDebugLog );
  92. }
  93. }
  94. BOOL
  95. DebugLog(
  96. IN Winnt32DebugLevel Level,
  97. IN LPCTSTR Text, OPTIONAL
  98. IN UINT MessageId,
  99. ...
  100. )
  101. /*++
  102. Routine Description:
  103. Write some text into the debug log file, if there is one.
  104. Arguments:
  105. Level - supplies the logging level for this log event. Only items
  106. with a level greater than or equal to the one specified by the user
  107. are actually logged.
  108. Text - if specified, supplies the format string for the text message
  109. to go into the log file. If not specified, MessageId must be.
  110. MessageId - if Text is not specified, supplies the message id for the
  111. item in the message table that has the text of the item to be
  112. written into the log file.
  113. Additional arguments supply insertion values for the message.
  114. Return Value:
  115. --*/
  116. {
  117. va_list arglist;
  118. BOOL b;
  119. va_start(arglist,MessageId);
  120. b = DebugLog2 (Level, Text, MessageId, arglist);
  121. va_end(arglist);
  122. return b;
  123. }
  124. BOOL
  125. DebugLog2(
  126. IN Winnt32DebugLevel Level,
  127. IN LPCTSTR Text, OPTIONAL
  128. IN UINT MessageId,
  129. IN va_list ArgList
  130. )
  131. /*++
  132. Routine Description:
  133. Write some text into the debug log file, if there is one.
  134. Arguments:
  135. Level - supplies the logging level for this log event. Only items
  136. with a level greater than or equal to the one specified by the user
  137. are actually logged.
  138. Text - if specified, supplies the format string for the text message
  139. to go into the log file. If not specified, MessageId must be.
  140. MessageId - if Text is not specified, supplies the message id for the
  141. item in the message table that has the text of the item to be
  142. written into the log file.
  143. Additional arguments supply insertion values for the message.
  144. Return Value:
  145. --*/
  146. {
  147. CHAR AnsiMessage[5000];
  148. DWORD Size;
  149. DWORD Written;
  150. LPCTSTR Message;
  151. BOOL b;
  152. DWORD rc;
  153. if(!hDebugLog) {
  154. return(FALSE);
  155. }
  156. if((Level & ~WINNT32_HARDWARE_LOG) > DebugLevel) {
  157. return(TRUE);
  158. }
  159. rc = GetLastError ();
  160. if(Text) {
  161. Size = FormatMessage(
  162. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  163. Text,
  164. 0,0,
  165. (LPTSTR)&Message,
  166. 0,
  167. &ArgList
  168. );
  169. } else {
  170. Size = FormatMessage(
  171. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  172. hInst,
  173. MessageId,
  174. 0,
  175. (LPTSTR)&Message,
  176. 0,
  177. &ArgList
  178. );
  179. }
  180. if(Size) {
  181. #ifdef UNICODE
  182. WideCharToMultiByte(
  183. CP_ACP,
  184. 0,
  185. Message,
  186. -1,
  187. AnsiMessage,
  188. sizeof(AnsiMessage),
  189. NULL,
  190. NULL
  191. );
  192. #else
  193. lstrcpyn(AnsiMessage,Message,sizeof(AnsiMessage));
  194. #endif
  195. b = WriteFile(hDebugLog,AnsiMessage,lstrlenA(AnsiMessage),&Written,NULL);
  196. if ((Level & WINNT32_HARDWARE_LOG) == 0) {
  197. if (Text && b) {
  198. if (Level <= Winnt32LogError && rc) {
  199. CHAR buffer[50];
  200. b = WriteFile(
  201. hDebugLog,
  202. buffer,
  203. wsprintfA (buffer, " (rc=%u[0x%X])\r\n", rc, rc),
  204. &Written,
  205. NULL
  206. );
  207. } else {
  208. b = WriteFile(hDebugLog,"\r\n", 2, &Written,NULL);
  209. }
  210. }
  211. }
  212. LocalFree((HLOCAL)Message);
  213. } else {
  214. b = FALSE;
  215. }
  216. SetLastError (rc);
  217. return(b);
  218. }
  219. #if ASSERTS_ON
  220. VOID
  221. AssertFail(
  222. IN PSTR FileName,
  223. IN UINT LineNumber,
  224. IN PSTR Condition
  225. )
  226. {
  227. int i;
  228. CHAR Name[MAX_PATH];
  229. PCHAR p;
  230. CHAR Msg[4096];
  231. //
  232. // Use dll name as caption
  233. //
  234. GetModuleFileNameA(hInst,Name,MAX_PATH);
  235. if(p = strrchr(Name,'\\')) {
  236. p++;
  237. } else {
  238. p = Name;
  239. }
  240. wsprintfA(
  241. Msg,
  242. "Assertion failure at line %u in file %s: %s\n\nCall DebugBreak()?",
  243. LineNumber,
  244. FileName,
  245. Condition
  246. );
  247. i = MessageBoxA(
  248. NULL,
  249. Msg,
  250. p,
  251. MB_YESNO | MB_TASKMODAL | MB_ICONSTOP | MB_SETFOREGROUND
  252. );
  253. if(i == IDYES) {
  254. DebugBreak();
  255. }
  256. }
  257. #endif
  258. VOID
  259. MyEnumerateDirectory(
  260. LPTSTR DirectoryName,
  261. DWORD Index,
  262. BOOL Recordable
  263. )
  264. /*++
  265. Routine Description:
  266. This routine will enumerate all files in a directory structure.
  267. It then prints those filenames into the debug logfile.
  268. Arguments:
  269. DirectoryName Name of the directory we're currently examining.
  270. Index Indicates our recurse-level. Used for formatting
  271. the output.
  272. Recordable This determines if we will be logging this item
  273. or not. Some items we don't care about.
  274. Return Value:
  275. --*/
  276. {
  277. TCHAR TmpDirectoryString[MAX_PATH];
  278. TCHAR TmpName[MAX_PATH];
  279. HANDLE FindHandle;
  280. WIN32_FIND_DATA FoundData;
  281. DWORD i;
  282. //
  283. // Fix our path so we know where we're looking...
  284. //
  285. if( DirectoryName[0] ) {
  286. lstrcpy( TmpDirectoryString, DirectoryName );
  287. if( ISNT() ) {
  288. ConcatenatePaths( TmpDirectoryString, TEXT("*"), MAX_PATH );
  289. } else {
  290. ConcatenatePaths( TmpDirectoryString, TEXT("*.*"), MAX_PATH );
  291. }
  292. } else {
  293. if( ISNT() ) {
  294. lstrcpy( TmpDirectoryString, TEXT("*") );
  295. } else {
  296. lstrcpy( TmpDirectoryString, TEXT("*.*") );
  297. }
  298. }
  299. //
  300. // Get the first item.
  301. //
  302. FindHandle = FindFirstFile( TmpDirectoryString, &FoundData );
  303. if( !FindHandle || (FindHandle == INVALID_HANDLE_VALUE) ) {
  304. //
  305. // The directory is empty.
  306. //
  307. return;
  308. }
  309. //
  310. // Now look at every item in the directory.
  311. //
  312. do {
  313. TmpName[0] = 0;
  314. for( i = 0; i < Index; i++ ) {
  315. lstrcat( TmpName, TEXT(" ") );
  316. }
  317. if( FoundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  318. //
  319. // Directory. Ignore . and .. entries.
  320. //
  321. if(lstrcmp(FoundData.cFileName,TEXT("."))
  322. && lstrcmp(FoundData.cFileName,TEXT(".."))) {
  323. //
  324. // Print the entry.
  325. //
  326. lstrcat( TmpName, TEXT("\\") );
  327. lstrcat( TmpName, FoundData.cFileName );
  328. lstrcat( TmpName, TEXT("\n") );
  329. if( ( !lstrcmpi( FoundData.cFileName, TEXT("Start Menu"))) ||
  330. ( Recordable ) ) {
  331. Recordable = TRUE;
  332. if( !_tcsrchr( TmpName, TEXT('%') ) ) {
  333. DebugLog( Winnt32LogInformation,
  334. TmpName,
  335. 0 );
  336. }
  337. }
  338. //
  339. // Call ourselves on this directory.
  340. //
  341. lstrcpy( TmpName, DirectoryName );
  342. ConcatenatePaths( TmpName, FoundData.cFileName, MAX_PATH );
  343. MyEnumerateDirectory( TmpName, Index+1, Recordable );
  344. //
  345. // If we just recursed into a Start Menu directory,
  346. // we need to turn off recordability.
  347. //
  348. if( !lstrcmpi( FoundData.cFileName, TEXT("Start Menu"))) {
  349. Recordable = FALSE;
  350. }
  351. }
  352. } else {
  353. //
  354. // File. Just print it.
  355. //
  356. if( Recordable ) {
  357. lstrcat( TmpName, FoundData.cFileName );
  358. lstrcat( TmpName, TEXT("\n") );
  359. if( !_tcsrchr( TmpName, TEXT('%') ) ) {
  360. DebugLog( Winnt32LogInformation,
  361. TmpName,
  362. 0 );
  363. }
  364. }
  365. }
  366. } while( FindNextFile( FindHandle, &FoundData ) );
  367. }
  368. VOID
  369. GatherOtherLogFiles(
  370. VOID
  371. )
  372. /*++
  373. Routine Description:
  374. This routine will launch winmsd in a batch-mode, then
  375. copy it's output onto the backend of our debug log.
  376. Arguments:
  377. Return Value:
  378. --*/
  379. {
  380. STARTUPINFO StartupInfo;
  381. PROCESS_INFORMATION ProcessInfo;
  382. DWORD dw,
  383. ExitCode;
  384. BOOL Done;
  385. TCHAR FileName[MAX_PATH];
  386. TCHAR ComputerName[MAX_PATH];
  387. MSG msg;
  388. TCHAR Text[512];
  389. //
  390. // If we're on Win9X, we will also want %windir%\upgrade.txt.
  391. //
  392. if( !ISNT() ) {
  393. //
  394. // %windir%\upgrade.txt
  395. //
  396. FileName[0] = TEXT('\0');
  397. MyGetWindowsDirectory( FileName, MAX_PATH );
  398. ConcatenatePaths( FileName, TEXT("upgrade.txt"), MAX_PATH );
  399. if( !ConcatenateFile( hDebugLog, FileName ) ) {
  400. DebugLog( Winnt32LogInformation,
  401. TEXT("\r\nFailed to append upgrade.txt!\r\n"),
  402. 0 );
  403. }
  404. //
  405. // %windir%\beta-upg.log
  406. //
  407. FileName[0] = TEXT('\0');
  408. MyGetWindowsDirectory( FileName, MAX_PATH );
  409. ConcatenatePaths( FileName, TEXT("beta-upg.log"), MAX_PATH );
  410. if( !ConcatenateFile( hDebugLog, FileName ) ) {
  411. DebugLog( Winnt32LogInformation,
  412. TEXT("\r\nFailed to append beta-upg.log!\r\n"),
  413. 0 );
  414. }
  415. //
  416. // %windir%\config.dmp
  417. //
  418. FileName[0] = TEXT('\0');
  419. MyGetWindowsDirectory( FileName, MAX_PATH );
  420. ConcatenatePaths( FileName, TEXT("config.dmp"), MAX_PATH );
  421. if( !ConcatenateFile( hDebugLog, FileName ) ) {
  422. DebugLog( Winnt32LogInformation,
  423. TEXT("\r\nFailed to append config.dmp!\r\n"),
  424. 0 );
  425. }
  426. }
  427. #if 0
  428. //
  429. // remove winmsd call for now.
  430. //
  431. if( ISNT() && (BuildNumber > NT351) ) {
  432. //
  433. // If we're on NT, run winmsd and capture his
  434. // output.
  435. //
  436. ZeroMemory(&StartupInfo,sizeof(StartupInfo));
  437. StartupInfo.cb = sizeof(StartupInfo);
  438. lstrcpy( FileName, TEXT( "winmsd.exe /a" ) );
  439. if( CreateProcess( NULL,
  440. FileName,
  441. NULL,
  442. NULL,
  443. FALSE,
  444. 0,
  445. NULL,
  446. NULL,
  447. &StartupInfo,
  448. &ProcessInfo ) ) {
  449. //
  450. // Wait for him.
  451. //
  452. //
  453. // Process any messages that may already be in the queue.
  454. //
  455. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  456. DispatchMessage(&msg);
  457. }
  458. //
  459. // Wait for process to terminate or more messages in the queue.
  460. //
  461. Done = FALSE;
  462. do {
  463. switch(MsgWaitForMultipleObjects(1,&ProcessInfo.hProcess,FALSE,INFINITE,QS_ALLINPUT)) {
  464. case WAIT_OBJECT_0:
  465. //
  466. // Process has terminated.
  467. //
  468. dw = GetExitCodeProcess(ProcessInfo.hProcess,&ExitCode) ? NO_ERROR : GetLastError();
  469. Done = TRUE;
  470. break;
  471. case WAIT_OBJECT_0+1:
  472. //
  473. // Messages in the queue.
  474. //
  475. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  476. DispatchMessage(&msg);
  477. }
  478. break;
  479. default:
  480. //
  481. // Error.
  482. //
  483. dw = GetLastError();
  484. Done = TRUE;
  485. break;
  486. }
  487. } while(!Done);
  488. }
  489. CloseHandle( ProcessInfo.hThread );
  490. CloseHandle( ProcessInfo.hProcess );
  491. if( dw == NO_ERROR ) {
  492. //
  493. // Concatenate him onto the end of our logfile. His
  494. // logfile will be <computer_name>.txt and will be
  495. // located in our directory. Map the file...
  496. //
  497. DebugLog( Winnt32LogInformation,
  498. TEXT("\r\n\r\n********************************************************************\r\n\r\n"),
  499. 0 );
  500. DebugLog( Winnt32LogInformation,
  501. TEXT("\t\tWinMSD Log\n"),
  502. 0 );
  503. DebugLog( Winnt32LogInformation,
  504. TEXT("\r\n********************************************************************\r\n\r\n"),
  505. 0 );
  506. GetCurrentDirectory( MAX_PATH, FileName );
  507. dw = MAX_PATH;
  508. GetComputerName( ComputerName, &dw );
  509. ConcatenatePaths( FileName, ComputerName, MAX_PATH );
  510. lstrcat( FileName, TEXT(".txt") );
  511. ConcatenateFile( hDebugLog, FileName );
  512. } else {
  513. //
  514. // Should we log our failure to be sneaky??
  515. //
  516. }
  517. }
  518. #endif
  519. //
  520. // Go enumerate the Start Menu
  521. // for all users... Don't do this for NT 3.51.
  522. //
  523. if( !(ISNT() && (BuildNumber <= NT351)) ){
  524. LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR) );
  525. DebugLog( Winnt32LogInformation,
  526. Text,
  527. 0 );
  528. LoadString( hInst, IDS_COMPAT_STRT_MENU, Text, sizeof(Text)/sizeof(TCHAR) );
  529. DebugLog( Winnt32LogInformation,
  530. Text,
  531. 0 );
  532. LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR) );
  533. DebugLog( Winnt32LogInformation,
  534. Text,
  535. 0 );
  536. if( !ISNT() ) {
  537. //
  538. // On Win9X, we can find Start Menu items in
  539. // two places!
  540. //
  541. MyGetWindowsDirectory( FileName, MAX_PATH );
  542. ConcatenatePaths( FileName, TEXT("Start Menu"), MAX_PATH );
  543. MyEnumerateDirectory( FileName, 0, TRUE );
  544. } else {
  545. if( BuildNumber >= 1890 ) {
  546. //
  547. // Starting on build 1890, we moved/renamed the Profiles
  548. // directory. Of course, that only happens on clean installs
  549. // of these new builds. We need to see if there's anything
  550. // in the new directory structure.
  551. //
  552. MyGetWindowsDirectory( FileName, MAX_PATH );
  553. FileName[3] = 0;
  554. ConcatenatePaths( FileName, TEXT("Documents and Settings"), MAX_PATH );
  555. MyEnumerateDirectory( FileName, 0, FALSE );
  556. }
  557. }
  558. MyGetWindowsDirectory( FileName, MAX_PATH );
  559. ConcatenatePaths( FileName, TEXT("Profiles"), MAX_PATH );
  560. MyEnumerateDirectory( FileName, 0, FALSE );
  561. }
  562. }