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.

694 lines
15 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. setuplog.c
  5. Abstract:
  6. Routines for logging actions and errors during setup.
  7. Author:
  8. Steve Owen (SteveOw) 1-Sep-1996
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include "setuplog.h"
  16. #if DBG
  17. VOID
  18. SetupLogAssertFail(
  19. IN PSTR FileName,
  20. IN UINT LineNumber,
  21. IN PSTR Condition
  22. )
  23. {
  24. CHAR Msg[4096];
  25. wsprintfA(
  26. Msg,
  27. "SetupLog: Assertion failure at line %u in file %s: %s\r\n",
  28. LineNumber,
  29. FileName,
  30. Condition
  31. );
  32. OutputDebugStringA(Msg);
  33. DebugBreak();
  34. }
  35. #define MYASSERT(x) if(!(x)) { SetupLogAssertFail(__FILE__,__LINE__,#x); }
  36. #else
  37. #define MYASSERT(x)
  38. #endif
  39. //
  40. // Pointer to structure given to us during initialization that provides all
  41. // the callbacks and global info we need.
  42. //
  43. PSETUPLOG_CONTEXT Context = NULL;
  44. BOOL
  45. pLogAction (
  46. IN LPCTSTR Message
  47. )
  48. /*++
  49. Routine Description:
  50. Writes an entry into the Setup Action Log. This routine is responsible
  51. for setting the format of the log file entries.
  52. Arguments:
  53. Message - Buffer that contains the text to write.
  54. Return Value:
  55. Boolean indicating whether the operation was successful.
  56. --*/
  57. {
  58. return Context->Write (Context->hActionLog, Message);
  59. }
  60. BOOL
  61. pLogError (
  62. IN LogSeverity Severity,
  63. IN LPCTSTR Message
  64. )
  65. /*++
  66. Routine Description:
  67. Writes an entry into the Setup Error Log. This routine is responsible
  68. for setting the format of the log file entries.
  69. Arguments:
  70. Message - Buffer that contains the text to write.
  71. Return Value:
  72. Boolean indicating whether the operation was successful.
  73. --*/
  74. {
  75. BOOL b;
  76. Context->Lock(Context->Mutex);
  77. //
  78. // Write the severity description.
  79. //
  80. if(Context->SeverityDescriptions[Severity]) {
  81. b = Context->Write (Context->hErrorLog,
  82. Context->SeverityDescriptions[Severity]);
  83. b = b && Context->Write (Context->hErrorLog, TEXT(":\r\n"));
  84. } else {
  85. b = TRUE;
  86. }
  87. //
  88. // Write the text.
  89. //
  90. b = b && Context->Write (Context->hErrorLog, Message);
  91. //
  92. // Write a terminating marker.
  93. //
  94. b = b && Context->Write (Context->hErrorLog, SETUPLOG_ITEM_TERMINATOR);
  95. Context->Unlock(Context->Mutex);
  96. return(b);
  97. }
  98. PTSTR
  99. pFormatMessage (
  100. IN PSETUPLOG_CONTEXT MyContext,
  101. IN LPCTSTR MessageString,
  102. IN UINT MessageId,
  103. ...
  104. )
  105. /*++
  106. Routine Description:
  107. Wrapper for Context->Format callback routine. This routine passes its
  108. variable argument list to Context->Format as a va_list.
  109. Arguments:
  110. MyContext - provides callback routines.
  111. MessageId - supplies message-table identifier or win32 error code
  112. for the message.
  113. Return Value:
  114. Pointer to a buffer containing the formatted string.
  115. --*/
  116. {
  117. va_list arglist;
  118. PTSTR p;
  119. va_start(arglist, MessageId);
  120. p = MyContext->Format (MessageString,MessageId,&arglist);
  121. va_end(arglist);
  122. return(p);
  123. }
  124. BOOL
  125. SetuplogInitializeEx(
  126. IN PSETUPLOG_CONTEXT SetuplogContext,
  127. IN BOOL WipeLogFile,
  128. IN LPCTSTR ActionFilename,
  129. IN LPCTSTR ErrorFilename,
  130. IN PVOID Reserved1,
  131. IN DWORD Reserved2
  132. )
  133. /*++
  134. Routine Description:
  135. Opens the Setup log files.
  136. Arguments:
  137. SetuplogContext - pointer to a context that has been filled in with the
  138. required callback routines by the caller.
  139. WipeLogFile - Boolean indicating whether any existing log files should be
  140. deleted (TRUE) or whether we should append onto existing files (FALSE).
  141. ActionFilename - filename to be used for the Action Log.
  142. ErrorFilename - filename to be used for the Error Log.
  143. Reserved1 - Reserved for future use--must be NULL.
  144. Reserved2 - Reserved for future use--must be 0.
  145. Return Value:
  146. Boolean indicating whether the operation was successful.
  147. --*/
  148. {
  149. if(Reserved1 || Reserved2) {
  150. return FALSE;
  151. }
  152. Context = SetuplogContext;
  153. Context->WorstError = LogSevInformation;
  154. Context->hActionLog = Context->OpenFile(
  155. ActionFilename, WipeLogFile);
  156. Context->hErrorLog = Context->OpenFile(
  157. ErrorFilename, WipeLogFile);
  158. return (Context->hActionLog != INVALID_HANDLE_VALUE &&
  159. Context->hErrorLog != INVALID_HANDLE_VALUE);
  160. }
  161. BOOL
  162. SetuplogInitialize(
  163. IN PSETUPLOG_CONTEXT SetuplogContext,
  164. IN BOOL WipeLogFile
  165. )
  166. /*++
  167. Routine Description:
  168. Opens the Setup log files with default file names.
  169. Arguments:
  170. SetuplogContext - pointer to a context that has been filled in with the
  171. required callback routines by the caller.
  172. WipeLogFile - Boolean indicating whether any existing log files should be
  173. deleted (TRUE) or whether we should append onto existing files (FALSE).
  174. Return Value:
  175. Boolean indicating whether the operation was successful.
  176. --*/
  177. {
  178. return SetuplogInitializeEx(
  179. SetuplogContext,
  180. WipeLogFile,
  181. SETUPLOG_ACTION_FILENAME,
  182. SETUPLOG_ERROR_FILENAME,
  183. NULL,
  184. 0
  185. );
  186. }
  187. PTSTR
  188. SetuplogFormatMessageWithContextV(
  189. IN PSETUPLOG_CONTEXT MyContext,
  190. IN DWORD Flags,
  191. IN LPCTSTR MessageString,
  192. IN UINT MessageId,
  193. IN va_list *ArgumentList
  194. )
  195. /*++
  196. Routine Description:
  197. Formats a specified message with caller-supplied arguments. The message
  198. can contain any number of imbedded messages.
  199. Arguments:
  200. MyContext - provides callback routines. This parameter is provided so that
  201. messages can be formatted even the global Context has not been
  202. initialized because we're not in Setup. This ability is needed by the
  203. Add/Remove Programs applet. The only fields that we use in this
  204. structure are AllocMem, FreeMem, and Format.
  205. Flags - Optional flags that can modify how the formatting is performed.
  206. MessageString - pointer to a buffer containing unformatted message text.
  207. If this value is SETUPLOG_USE_MESSAGEID, then MessageId is used to
  208. generate the message text. Otherwise, MessageId is unused.
  209. MessageID - ID of the outer level message to be formatted
  210. ArgumentList - list of strings to be substituted into the message. The
  211. order of items in the ArgumentList is given by:
  212. ArgumentList = Arg1,...,ArgN,NULL,{ImbeddedMessage},NULL
  213. ImbeddedMessage = MessageID,Arg1,...,ArgN,NULL,{ImbeddedMessage}
  214. where Arg1,...,ArgN are the arguments for MessageID
  215. Return Value:
  216. Pointer to a buffer containing the formatted string. If an error prevented
  217. the routine from completing successfully, NULL is returned. The caller
  218. can free the buffer with Context->MyFree().
  219. --*/
  220. {
  221. va_list major_ap, minor_ap;
  222. UINT NumberOfArguments, i;
  223. UINT MinorMessageId;
  224. PVOID p, *MajorArgList;
  225. PTSTR MajorMessage, MinorMessage, MinorMessageString;
  226. //
  227. // Handle a single message first.
  228. //
  229. if(Flags & SETUPLOG_SINGLE_MESSAGE) {
  230. return MyContext->Format (MessageString, MessageId, ArgumentList);
  231. }
  232. //
  233. // Count the number of arguments that go with the major message (MessageID)
  234. // and get ready to process the minor (imbedded) message if there is one
  235. //
  236. minor_ap = *ArgumentList;
  237. NumberOfArguments = 0;
  238. major_ap = minor_ap;
  239. while (p=va_arg(minor_ap, PVOID)) {
  240. NumberOfArguments++;
  241. }
  242. MYASSERT (NumberOfArguments < 7);
  243. MinorMessageString = va_arg(minor_ap, PTSTR);
  244. if (MinorMessageString) {
  245. //
  246. // We've got a minor message, so process it first
  247. //
  248. MinorMessageId = va_arg(minor_ap, UINT);
  249. MinorMessage = SetuplogFormatMessageWithContextV (
  250. MyContext,
  251. Flags,
  252. MinorMessageString,
  253. MinorMessageId,
  254. &minor_ap);
  255. if (!MinorMessage) {
  256. return NULL;
  257. }
  258. //
  259. // Now we handle the major message
  260. // Ugly hack: since we don't know how to bulid a va_list, we've
  261. // got to let the compiler do it.
  262. //
  263. MajorArgList = MyContext->AllocMem ((NumberOfArguments) * sizeof(PVOID));
  264. if (!MajorArgList) {
  265. MyContext->FreeMem (MinorMessage);
  266. return NULL;
  267. }
  268. for (i=0; i<NumberOfArguments; i++) {
  269. MajorArgList[i] = va_arg (major_ap, PVOID);
  270. }
  271. switch (NumberOfArguments) {
  272. case 0:
  273. MajorMessage = pFormatMessage (
  274. MyContext,
  275. MessageString,
  276. MessageId,
  277. MinorMessage);
  278. break;
  279. case 1:
  280. MajorMessage = pFormatMessage (
  281. MyContext,
  282. MessageString,
  283. MessageId,
  284. MajorArgList[0],
  285. MinorMessage);
  286. break;
  287. case 2:
  288. MajorMessage = pFormatMessage (
  289. MyContext,
  290. MessageString,
  291. MessageId,
  292. MajorArgList[0],
  293. MajorArgList[1],
  294. MinorMessage);
  295. break;
  296. case 3:
  297. MajorMessage = pFormatMessage (
  298. MyContext,
  299. MessageString,
  300. MessageId,
  301. MajorArgList[0],
  302. MajorArgList[1],
  303. MajorArgList[2],
  304. MinorMessage);
  305. break;
  306. case 4:
  307. MajorMessage = pFormatMessage (
  308. MyContext,
  309. MessageString,
  310. MessageId,
  311. MajorArgList[0],
  312. MajorArgList[1],
  313. MajorArgList[2],
  314. MajorArgList[3],
  315. MinorMessage);
  316. break;
  317. case 5:
  318. MajorMessage = pFormatMessage (
  319. MyContext,
  320. MessageString,
  321. MessageId,
  322. MajorArgList[0],
  323. MajorArgList[1],
  324. MajorArgList[2],
  325. MajorArgList[3],
  326. MajorArgList[4],
  327. MinorMessage);
  328. break;
  329. case 6:
  330. MajorMessage = pFormatMessage (
  331. MyContext,
  332. MessageString,
  333. MessageId,
  334. MajorArgList[0],
  335. MajorArgList[1],
  336. MajorArgList[2],
  337. MajorArgList[3],
  338. MajorArgList[4],
  339. MajorArgList[5],
  340. MinorMessage);
  341. break;
  342. default:
  343. MajorMessage = NULL;
  344. MYASSERT (0);
  345. }
  346. MyContext->FreeMem (MajorArgList);
  347. MyContext->FreeMem (MinorMessage);
  348. } else {
  349. MajorMessage = MyContext->Format (MessageString, MessageId, &major_ap);
  350. }
  351. return MajorMessage;
  352. }
  353. PTSTR
  354. SetuplogFormatMessageV(
  355. IN DWORD Flags,
  356. IN LPCTSTR MessageString,
  357. IN UINT MessageId,
  358. IN va_list *ArgumentList
  359. )
  360. /*++
  361. Routine Description:
  362. Wrapper for SetuplogFormatMessageWithContextV.
  363. Arguments:
  364. See FormatMessageWithContextV.
  365. Return Value:
  366. See FormatMessageWithContextV.
  367. --*/
  368. {
  369. //
  370. // Make sure we've been initialized
  371. //
  372. if(!Context) {
  373. return NULL;
  374. }
  375. return SetuplogFormatMessageWithContextV(
  376. Context,
  377. Flags,
  378. MessageString,
  379. MessageId,
  380. ArgumentList
  381. );
  382. }
  383. PTSTR
  384. SetuplogFormatMessage(
  385. IN DWORD Flags,
  386. IN LPCTSTR MessageString,
  387. IN UINT MessageId,
  388. ...
  389. )
  390. /*++
  391. Routine Description:
  392. Wrapper for SetuplogFormatMessageWithContextV. This routine passes its
  393. variable argument list to SetuplogFormatMessageV as a va_list.
  394. Arguments:
  395. See FormatMessageWithContextV.
  396. Return Value:
  397. See FormatMessageWithContextV.
  398. --*/
  399. {
  400. va_list arglist;
  401. PTSTR p;
  402. //
  403. // Make sure we've been initialized
  404. //
  405. if(!Context) {
  406. return NULL;
  407. }
  408. va_start(arglist,MessageId);
  409. p = SetuplogFormatMessageWithContextV(
  410. Context,
  411. Flags,
  412. MessageString,
  413. MessageId,
  414. &arglist);
  415. va_end(arglist);
  416. return(p);
  417. }
  418. BOOL
  419. SetuplogErrorV(
  420. IN LogSeverity Severity,
  421. IN LPCTSTR MessageString,
  422. IN UINT MessageId, OPTIONAL
  423. IN va_list *ArgumentList
  424. )
  425. /*++
  426. Routine Description:
  427. Writes an entry to the Setup Error Log.
  428. Arguments:
  429. Severity - Severity of the error. The low word contains the actual number
  430. of the severity. The high word contains any flags that affect how the
  431. message is formatted.
  432. MessageString - pointer to a buffer containing unformatted message text.
  433. If this value is SETUPLOG_USE_MESSAGEID, then MessageId is used to
  434. generate the message text. Otherwise, MessageId is unused.
  435. MessageId - supplies message-table identifier or win32 error code
  436. for the message.
  437. ArgumentList - supplies arguments to be inserted in the message text.
  438. Return Value:
  439. Boolean indicating whether the operation was successful.
  440. --*/
  441. {
  442. BOOL Status = FALSE;
  443. LPCTSTR Message;
  444. if(Context) {
  445. if(Message = SetuplogFormatMessageV (
  446. Severity,
  447. MessageString,
  448. MessageId,
  449. ArgumentList)) {
  450. //
  451. // Now validate the Severity. Note that we don't have to do this
  452. // for SetuplogFormatMessageV, since it just looks at the flags
  453. // set in the high word.
  454. //
  455. Severity = LOWORD(Severity);
  456. if(Severity < LogSevMaximum) {
  457. Status = TRUE;
  458. } else {
  459. MYASSERT (Severity < LogSevMaximum);
  460. Severity = LogSevInformation;
  461. Status = FALSE;
  462. }
  463. Context->WorstError = max (Context->WorstError, Severity);
  464. //
  465. // Write the message(s).
  466. //
  467. Status = pLogAction (Message) && Status;
  468. if(Severity != LogSevInformation) {
  469. Status = pLogError (Severity, Message) && Status;
  470. }
  471. Context->FreeMem (Message);
  472. }
  473. }
  474. #if DBG
  475. if(!Status) {
  476. OutputDebugStringA("SETUPLOG: Unable to log a message.\n");
  477. }
  478. #endif
  479. return Status;
  480. }
  481. BOOL
  482. SetuplogError(
  483. IN LogSeverity Severity,
  484. IN LPCTSTR MessageString,
  485. IN UINT MessageId, OPTIONAL
  486. ...
  487. )
  488. /*++
  489. Wrapper for SetuplogErrorV
  490. Make sure to pass two NULLs to end the arglist.
  491. Otherwise SetuplogFormatMessageWithContextV will cause an exception.
  492. --*/
  493. {
  494. va_list arglist;
  495. BOOL Status;
  496. va_start(arglist, MessageId);
  497. Status = SetuplogErrorV (Severity, MessageString, MessageId, &arglist);
  498. va_end(arglist);
  499. return Status;
  500. }
  501. BOOL
  502. SetuplogTerminate(
  503. VOID
  504. )
  505. /*++
  506. Routine Description:
  507. Closes the Setup log files.
  508. Arguments:
  509. None.
  510. Return Value:
  511. Boolean indicating whether the operation was successful.
  512. --*/
  513. {
  514. BOOL Status = FALSE;
  515. if(Context) {
  516. Context->CloseFile(Context->hActionLog);
  517. Context->CloseFile(Context->hErrorLog);
  518. Context = NULL;
  519. Status = TRUE;
  520. }
  521. return Status;
  522. }