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.

2803 lines
65 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. routing\netsh\shell\utils.c
  5. Abstract:
  6. Utilities.
  7. Revision History:
  8. 6/12/96 V Raman
  9. --*/
  10. #include "precomp.h"
  11. #include <wincon.h>
  12. #include <winbase.h>
  13. #define STOP_EVENT L"NetshStopRefreshEvent"
  14. extern HANDLE g_hModule;
  15. BOOL
  16. WINAPI
  17. MatchCmdLine(
  18. IN LPWSTR *ppwcArguments,
  19. IN DWORD dwArgCount,
  20. IN LPCWSTR pwszCmdToken,
  21. OUT PDWORD pdwNumMatched
  22. )
  23. {
  24. LPCWSTR pwcToken;
  25. DWORD dwCount;
  26. WCHAR wcszBuffer[256];
  27. //
  28. // Compare the two strings
  29. //
  30. dwCount = 0;
  31. if (!ppwcArguments || !pwszCmdToken || !pdwNumMatched)
  32. {
  33. return FALSE;
  34. }
  35. *pdwNumMatched = 0; // init OUT parameter
  36. if ( (wcslen(pwszCmdToken) + 1) > (sizeof(wcszBuffer)/sizeof(wcszBuffer[0])) )
  37. {
  38. // incoming command string is too large for processing
  39. return FALSE;
  40. }
  41. // copy into a buffer which wcstok can munge
  42. wcscpy(wcszBuffer, pwszCmdToken);
  43. if((pwcToken = wcstok(wcszBuffer,
  44. NETSH_CMD_DELIMITER)) != NULL)
  45. {
  46. do
  47. {
  48. if (dwCount < dwArgCount &&
  49. (_wcsnicmp(ppwcArguments[dwCount],
  50. pwcToken,
  51. wcslen(ppwcArguments[dwCount])) == 0))
  52. {
  53. dwCount++;
  54. }
  55. else
  56. {
  57. return FALSE;
  58. }
  59. } while((pwcToken = wcstok((LPWSTR) NULL, NETSH_CMD_DELIMITER )) != NULL);
  60. }
  61. *pdwNumMatched = dwCount;
  62. return TRUE;
  63. }
  64. #if 0
  65. BOOL
  66. WINAPI
  67. MatchCmdTokenId(
  68. IN HANDLE hModule,
  69. IN LPCWSTR *ppwcArguments,
  70. IN DWORD dwArgCount,
  71. IN DWORD dwCmdId,
  72. OUT PDWORD pdwNumMatched
  73. )
  74. /*++
  75. Routine Description:
  76. Tries to match a command in the given command line.
  77. The function takes the id of the command of the command message.
  78. A command message consists of command words separated by white space.
  79. The function tokenises this messages into separate words and then
  80. tries to match the first N arguments against the N separate tokens that
  81. constitute the command.
  82. e.g if the command is "add if neighbour" - the function will generate
  83. 3 tokens "add" "if" and "neighbour". It will then try and match the
  84. all these to the given arg array.
  85. Arguments:
  86. ppwcArguments - Argument array
  87. dwArgCount - Number of arguments
  88. dwTokenId - Token Id of command
  89. pdwNumMatched - Number of arguments matched in the array
  90. Return Value:
  91. TRUE if matched else FALSE
  92. --*/
  93. {
  94. WCHAR pwszTemp[NETSH_MAX_CMD_TOKEN_LENGTH];
  95. LPCWSTR pwcToken;
  96. DWORD dwCount;
  97. if(!LoadStringW(hModule,
  98. dwCmdId,
  99. pwszTemp,
  100. NETSH_MAX_CMD_TOKEN_LENGTH) )
  101. {
  102. return FALSE;
  103. }
  104. //
  105. // Compare the two strings
  106. //
  107. dwCount = 0;
  108. if((pwcToken = wcstok(pwszTemp,
  109. NETSH_CMD_DELIMITER)) != NULL)
  110. {
  111. do
  112. {
  113. if (dwCount < dwArgCount &&
  114. (_wcsnicmp(ppwcArguments[dwCount],
  115. pwcToken,
  116. wcslen(ppwcArguments[dwCount])) == 0))
  117. {
  118. dwCount++;
  119. }
  120. else
  121. {
  122. *pdwNumMatched = 0;
  123. return FALSE;
  124. }
  125. } while((pwcToken = wcstok((LPCWSTR) NULL, NETSH_CMD_DELIMITER )) != NULL);
  126. }
  127. *pdwNumMatched = dwCount;
  128. return TRUE;
  129. }
  130. #endif
  131. DWORD
  132. WINAPI
  133. MatchEnumTag(
  134. IN HANDLE hModule,
  135. IN LPCWSTR pwcArg,
  136. IN DWORD dwNumArg,
  137. IN CONST TOKEN_VALUE *pEnumTable,
  138. OUT PDWORD pdwValue
  139. )
  140. /*++
  141. Routine Description:
  142. Used for options that take a specific set of values. Matches argument
  143. with the set of values specified and returns corresponding value.
  144. Arguments:
  145. pwcArg - Argument
  146. dwNumArg - Number of possible values.
  147. Return Value:
  148. NO_ERROR
  149. ERROR_NOT_FOUND
  150. --*/
  151. {
  152. DWORD i;
  153. if ( (!pdwValue) || (!pEnumTable) )
  154. {
  155. return ERROR_INVALID_PARAMETER;
  156. }
  157. for (i = 0; i < dwNumArg; i++)
  158. {
  159. if (MatchToken(pwcArg,
  160. pEnumTable[i].pwszToken))
  161. {
  162. *pdwValue = pEnumTable[i].dwValue;
  163. return NO_ERROR;
  164. }
  165. }
  166. return ERROR_NOT_FOUND;
  167. }
  168. DWORD
  169. MatchTagsInCmdLine(
  170. IN HANDLE hModule,
  171. IN OUT LPWSTR *ppwcArguments,
  172. IN DWORD dwCurrentIndex,
  173. IN DWORD dwArgCount,
  174. IN OUT PTAG_TYPE pttTagToken,
  175. IN DWORD dwNumTags,
  176. OUT PDWORD pdwOut
  177. )
  178. /*++
  179. Routine Description:
  180. Identifies each argument based on its tag.
  181. It also removes tag= from each argument.
  182. It also sets the bPresent flag in the tags present.
  183. Arguments:
  184. ppwcArguments - The argument array. Each argument has tag=value form
  185. dwCurrentIndex - ppwcArguments[dwCurrentIndex] is first arg.
  186. dwArgCount - ppwcArguments[dwArgCount - 1] is last arg.
  187. pttTagToken - Array of tag token ids that are allowed in the args
  188. dwNumTags - Size of pttTagToken
  189. pdwOut - Array identifying the type of each argument, where
  190. pdwOut[0] is for ppwcArguments[dwCurrentIndex]
  191. Return Value:
  192. NO_ERROR, ERROR_INVALID_PARAMETER, ERROR_INVALID_OPTION_TAG
  193. --*/
  194. {
  195. DWORD i,j,len;
  196. LPCWSTR pwcTag;
  197. LPWSTR pwcTagVal, pwszArg;
  198. BOOL bFound = FALSE;
  199. //
  200. // This function assumes that every argument has a tag
  201. // It goes ahead and removes the tag.
  202. //
  203. for (i = dwCurrentIndex; i < dwArgCount; i++)
  204. {
  205. if (!wcspbrk(ppwcArguments[i], NETSH_ARG_DELIMITER))
  206. {
  207. pdwOut[i - dwCurrentIndex] = (DWORD) -2;
  208. continue;
  209. }
  210. len = wcslen(ppwcArguments[i]);
  211. if (len is 0)
  212. {
  213. //
  214. // something wrong with arg
  215. //
  216. pdwOut[i - dwCurrentIndex] = (DWORD) -1;
  217. continue;
  218. }
  219. pwszArg = HeapAlloc(GetProcessHeap(),0,(len + 1) * sizeof(WCHAR));
  220. if (pwszArg is NULL)
  221. {
  222. PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
  223. return ERROR_NOT_ENOUGH_MEMORY;
  224. }
  225. wcscpy(pwszArg, ppwcArguments[i]);
  226. pwcTag = wcstok(pwszArg, NETSH_ARG_DELIMITER);
  227. //
  228. // Got the first part
  229. // Now if next call returns NULL then there was no tag
  230. //
  231. pwcTagVal = wcstok((LPWSTR)NULL, NETSH_ARG_DELIMITER);
  232. if (pwcTagVal is NULL)
  233. {
  234. PrintMessageFromModule(g_hModule, ERROR_NO_TAG, ppwcArguments[i]);
  235. HeapFree(GetProcessHeap(),0,pwszArg);
  236. return ERROR_INVALID_PARAMETER;
  237. }
  238. //
  239. // Got the tag. Now try to match it
  240. //
  241. bFound = FALSE;
  242. pdwOut[i - dwCurrentIndex] = (DWORD) -1;
  243. for ( j = 0; j < dwNumTags; j++)
  244. {
  245. if (MatchToken(pwcTag, pttTagToken[j].pwszTag))
  246. {
  247. //
  248. // Tag matched
  249. //
  250. if (pttTagToken[j].bPresent
  251. && !(pttTagToken[j].dwRequired & NS_REQ_ALLOW_MULTIPLE))
  252. {
  253. HeapFree(GetProcessHeap(),0,pwszArg);
  254. PrintMessageFromModule(g_hModule, ERROR_TAG_ALREADY_PRESENT, pwcTag);
  255. return ERROR_TAG_ALREADY_PRESENT;
  256. }
  257. bFound = TRUE;
  258. pdwOut[i - dwCurrentIndex] = j;
  259. pttTagToken[j].bPresent = TRUE;
  260. break;
  261. }
  262. }
  263. if (bFound)
  264. {
  265. //
  266. // Remove tag from the argument
  267. //
  268. wcscpy(ppwcArguments[i], pwcTagVal);
  269. }
  270. else
  271. {
  272. PrintMessageFromModule(g_hModule, ERROR_INVALID_OPTION_TAG, pwcTag);
  273. HeapFree(GetProcessHeap(),0,pwszArg);
  274. return ERROR_INVALID_OPTION_TAG;
  275. }
  276. HeapFree(GetProcessHeap(),0,pwszArg);
  277. }
  278. // Now tag all untagged arguments
  279. for (i = dwCurrentIndex; i < dwArgCount; i++)
  280. {
  281. if ( pdwOut[i - dwCurrentIndex] != -2)
  282. {
  283. continue;
  284. }
  285. bFound = FALSE;
  286. for ( j = 0; j < dwNumTags; j++)
  287. {
  288. if (!pttTagToken[j].bPresent)
  289. {
  290. bFound = TRUE;
  291. pdwOut[i - dwCurrentIndex] = j;
  292. pttTagToken[j].bPresent = TRUE;
  293. break;
  294. }
  295. }
  296. if (!bFound)
  297. {
  298. pdwOut[i - dwCurrentIndex] = (DWORD) -1;
  299. }
  300. }
  301. return NO_ERROR;
  302. }
  303. BOOL
  304. WINAPI
  305. MatchToken(
  306. IN LPCWSTR pwszUserToken,
  307. IN LPCWSTR pwszCmdToken
  308. )
  309. {
  310. if ( (!pwszUserToken) || (!pwszCmdToken) )
  311. {
  312. return ERROR_INVALID_PARAMETER;
  313. }
  314. return !_wcsnicmp(pwszUserToken,
  315. pwszCmdToken,
  316. wcslen(pwszUserToken));
  317. }
  318. BOOL
  319. WINAPI
  320. MatchTokenId( // changed this name since I don't think anything will use it
  321. IN HANDLE hModule,
  322. IN LPCWSTR pwszToken,
  323. IN DWORD dwTokenId
  324. )
  325. /*++
  326. Routine Description:
  327. Sees if the given string and the string corresponding to dwTokenId
  328. are the same.
  329. Arguments:
  330. pwszToken - Token string
  331. dwTokenId - Token Id
  332. Return Value:
  333. TRUE is matched else FALSE
  334. --*/
  335. {
  336. WCHAR pwszTemp[NETSH_MAX_TOKEN_LENGTH];
  337. if(!LoadStringW(hModule,
  338. dwTokenId,
  339. pwszTemp,
  340. NETSH_MAX_TOKEN_LENGTH))
  341. {
  342. return FALSE;
  343. }
  344. return MatchToken(pwszToken, pwszTemp);
  345. }
  346. extern HANDLE g_hLogFile;
  347. LPWSTR
  348. OEMfgets(
  349. OUT PDWORD pdwLen,
  350. IN FILE *fp
  351. )
  352. {
  353. LPWSTR pwszUnicode;
  354. DWORD dwErr = NO_ERROR;
  355. DWORD dwLen;
  356. CHAR buff[MAX_CMD_LEN];
  357. fflush(stdout);
  358. if (fgets( buff, sizeof(buff), fp ) is NULL)
  359. {
  360. return NULL;
  361. }
  362. dwLen = MultiByteToWideChar( GetConsoleOutputCP(),
  363. 0,
  364. buff,
  365. -1,
  366. NULL,
  367. 0 );
  368. if (g_hLogFile)
  369. {
  370. DWORD dwWritten;
  371. CHAR szCrLf[] = "\r\n";
  372. if (0 == WriteFile( g_hLogFile, buff, dwLen-2, &dwWritten, NULL ))
  373. {
  374. CloseHandle(g_hLogFile);
  375. g_hLogFile = NULL;
  376. PrintError(NULL, GetLastError());
  377. }
  378. if (0 == WriteFile( g_hLogFile, szCrLf, 2, &dwWritten, NULL ))
  379. {
  380. CloseHandle(g_hLogFile);
  381. g_hLogFile = NULL;
  382. PrintError(NULL, GetLastError());
  383. }
  384. }
  385. pwszUnicode = MALLOC(dwLen * sizeof(WCHAR));
  386. if (pwszUnicode)
  387. {
  388. MultiByteToWideChar( GetConsoleOutputCP(),
  389. 0,
  390. buff,
  391. sizeof(buff),
  392. pwszUnicode,
  393. dwLen );
  394. }
  395. *pdwLen = dwLen;
  396. return pwszUnicode;
  397. }
  398. VOID
  399. OEMfprintf(
  400. IN HANDLE hHandle,
  401. IN LPCWSTR pwszUnicode
  402. )
  403. {
  404. PCHAR achOem;
  405. DWORD dwLen, dwWritten;
  406. dwLen = WideCharToMultiByte( GetConsoleOutputCP(),
  407. 0,
  408. pwszUnicode,
  409. -1,
  410. NULL,
  411. 0,
  412. NULL,
  413. NULL );
  414. achOem = MALLOC(dwLen);
  415. if (achOem)
  416. {
  417. WideCharToMultiByte( GetConsoleOutputCP(),
  418. 0,
  419. pwszUnicode,
  420. -1,
  421. achOem,
  422. dwLen,
  423. NULL,
  424. NULL );
  425. WriteFile( hHandle, achOem, dwLen-1, &dwWritten, NULL );
  426. if (g_hLogFile)
  427. {
  428. if (0 == WriteFile( g_hLogFile, achOem, dwLen-1, &dwWritten, NULL ))
  429. {
  430. CloseHandle(g_hLogFile);
  431. g_hLogFile = NULL;
  432. PrintError(NULL, GetLastError());
  433. }
  434. }
  435. FREE(achOem);
  436. }
  437. }
  438. #define OEMprintf(pwszUnicode) \
  439. OEMfprintf( GetStdHandle(STD_OUTPUT_HANDLE), pwszUnicode)
  440. LPWSTR
  441. WINAPI
  442. GetEnumString(
  443. IN HANDLE hModule,
  444. IN DWORD dwValue,
  445. IN DWORD dwNumVal,
  446. IN PTOKEN_VALUE pEnumTable
  447. )
  448. /*++
  449. Routine Description:
  450. This routine looks up the value specified, dwValue, in the Value table
  451. pEnumTable and returns the string corresponding to the value
  452. Arguments :
  453. hModule - handle to current module
  454. dwValue - Value whose display string is required
  455. dwNumVal - Number of elements in pEnumTable
  456. pEnumTable - Table of enumerated value and corresp. string IDs
  457. Return Value :
  458. NULL - Value not found in pEnumTable
  459. Pointer to string on success
  460. --*/
  461. {
  462. DWORD dwInd;
  463. for ( dwInd = 0; dwInd < dwNumVal; dwInd++ )
  464. {
  465. if ( pEnumTable[ dwInd ].dwValue == dwValue )
  466. {
  467. // ISSUE: const_cast
  468. return (LPWSTR)pEnumTable[ dwInd ].pwszToken;
  469. }
  470. }
  471. return NULL;
  472. }
  473. LPWSTR
  474. WINAPI
  475. MakeString(
  476. IN HANDLE hModule,
  477. IN DWORD dwMsgId,
  478. ...
  479. )
  480. {
  481. DWORD dwMsgLen;
  482. LPWSTR pwszInput, pwszOutput = NULL;
  483. va_list arglist;
  484. do
  485. {
  486. va_start( arglist, dwMsgId );
  487. pwszInput = HeapAlloc(GetProcessHeap(),
  488. 0,
  489. MAX_MSG_LENGTH * sizeof(WCHAR) );
  490. if ( pwszInput == NULL )
  491. {
  492. break;
  493. }
  494. if ( !LoadStringW(hModule,
  495. dwMsgId,
  496. pwszInput,
  497. MAX_MSG_LENGTH) )
  498. {
  499. break;
  500. }
  501. FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  502. pwszInput,
  503. 0,
  504. 0L, // Default country ID.
  505. (LPWSTR)&pwszOutput,
  506. 0,
  507. &arglist);
  508. } while ( FALSE );
  509. if ( pwszInput ) { HeapFree( GetProcessHeap(), 0, pwszInput ); }
  510. return pwszOutput;
  511. }
  512. VOID
  513. WINAPI
  514. FreeString(
  515. IN LPWSTR pwszMadeString
  516. )
  517. /*++
  518. Routine Description:
  519. Frees string allocated by make string.
  520. Arguments:
  521. Return Value:
  522. --*/
  523. {
  524. LocalFree( pwszMadeString );
  525. }
  526. LPWSTR
  527. WINAPI
  528. MakeQuotedString(
  529. IN LPCWSTR pwszOrigString
  530. )
  531. {
  532. LPWSTR pwszNewString;
  533. pwszNewString = HeapAlloc(GetProcessHeap(),
  534. 0,
  535. (wcslen(pwszOrigString) + 3) * sizeof(WCHAR));
  536. if(pwszNewString == NULL)
  537. {
  538. return NULL;
  539. }
  540. wsprintfW(pwszNewString, L"\"%s\"",pwszOrigString);
  541. pwszNewString[wcslen(pwszOrigString) + 2] = UNICODE_NULL;
  542. return pwszNewString;
  543. }
  544. VOID
  545. WINAPI
  546. FreeQuotedString(
  547. LPWSTR pwszString
  548. )
  549. {
  550. HeapFree(GetProcessHeap(),
  551. 0,
  552. pwszString);
  553. }
  554. DWORD
  555. PrintError(
  556. IN HANDLE hModule, OPTIONAL
  557. IN DWORD dwErrId,
  558. ...
  559. )
  560. /*++
  561. Routine Description:
  562. Displays an error message.
  563. We first search for the error code in the module specified by the caller
  564. (if one is specified)
  565. If no module is given, or the error code doesnt exist we look for MPR
  566. errors, RAS errors and Win32 errors - in that order
  567. Arguments:
  568. hModule - Module to load the string from
  569. dwMsgId - Message to be printed
  570. ... - Insert strings
  571. Return Value:
  572. Message length
  573. --*/
  574. {
  575. DWORD dwMsgLen;
  576. LPWSTR pwszOutput = NULL;
  577. WCHAR rgwcInput[MAX_MSG_LENGTH + 1];
  578. va_list arglist;
  579. va_start(arglist, dwErrId);
  580. if(hModule)
  581. {
  582. if(LoadStringW(hModule,
  583. dwErrId,
  584. rgwcInput,
  585. MAX_MSG_LENGTH))
  586. {
  587. //
  588. // Found the message in the callers module
  589. //
  590. dwMsgLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_STRING,
  591. rgwcInput,
  592. 0,
  593. 0L,
  594. (LPWSTR)&pwszOutput,
  595. 0,
  596. &arglist);
  597. if(dwMsgLen == 0)
  598. {
  599. ASSERT(pwszOutput == NULL);
  600. }
  601. else
  602. {
  603. OEMprintf(pwszOutput);
  604. LocalFree(pwszOutput);
  605. return dwMsgLen;
  606. }
  607. }
  608. else
  609. {
  610. return 0;
  611. }
  612. }
  613. //
  614. // Next try, local errors
  615. //
  616. if((dwErrId > NETSH_ERROR_BASE) &&
  617. (dwErrId < NETSH_ERROR_END))
  618. {
  619. if(LoadStringW(g_hModule,
  620. dwErrId,
  621. rgwcInput,
  622. MAX_MSG_LENGTH))
  623. {
  624. //
  625. // Found the message in our module
  626. //
  627. dwMsgLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_STRING,
  628. rgwcInput,
  629. 0,
  630. 0L,
  631. (LPWSTR)&pwszOutput,
  632. 0,
  633. &arglist);
  634. if(dwMsgLen == 0)
  635. {
  636. ASSERT(pwszOutput == NULL);
  637. }
  638. else
  639. {
  640. OEMprintf(pwszOutput);
  641. LocalFree(pwszOutput);
  642. return dwMsgLen;
  643. }
  644. }
  645. }
  646. //
  647. // Next try MPR errors
  648. //
  649. if (MprAdminGetErrorString(dwErrId,
  650. &pwszOutput) == NO_ERROR)
  651. {
  652. wcscpy(rgwcInput, pwszOutput);
  653. LocalFree(pwszOutput);
  654. wcscat(rgwcInput, L"\r\n");
  655. OEMprintf(rgwcInput);
  656. dwMsgLen = wcslen(rgwcInput);
  657. return dwMsgLen;
  658. }
  659. //
  660. // Next try RAS errors
  661. //
  662. if (RasGetErrorStringW(dwErrId,
  663. rgwcInput,
  664. MAX_MSG_LENGTH) == NO_ERROR)
  665. {
  666. wcscat(rgwcInput, L"\r\n");
  667. OEMprintf(rgwcInput);
  668. dwMsgLen = wcslen(rgwcInput);
  669. return dwMsgLen;
  670. }
  671. //
  672. // Finally try Win32
  673. //
  674. dwMsgLen = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  675. NULL,
  676. dwErrId,
  677. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  678. (LPWSTR)&rgwcInput,
  679. MAX_MSG_LENGTH,
  680. &arglist);
  681. if(dwMsgLen)
  682. {
  683. OEMprintf(rgwcInput);
  684. return dwMsgLen;
  685. }
  686. return 0;
  687. }
  688. DWORD
  689. DisplayMessageVA(
  690. IN LPCWSTR pwszFormat,
  691. IN va_list *parglist
  692. )
  693. {
  694. DWORD dwMsgLen = 0;
  695. LPWSTR pwszOutput = NULL;
  696. do
  697. {
  698. dwMsgLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
  699. |FORMAT_MESSAGE_FROM_STRING,
  700. pwszFormat,
  701. 0,
  702. 0L, // Default country ID.
  703. (LPWSTR)&pwszOutput,
  704. 0,
  705. parglist);
  706. if(dwMsgLen == 0)
  707. {
  708. // ISSUE: Unlocalized string.
  709. wprintf( L"Error %d in FormatMessageW()\n", GetLastError());
  710. ASSERT(pwszOutput == NULL);
  711. break;
  712. }
  713. OEMprintf( pwszOutput );
  714. } while ( FALSE );
  715. if ( pwszOutput) { LocalFree( pwszOutput ); }
  716. return dwMsgLen;
  717. }
  718. DWORD
  719. PrintMessage(
  720. IN LPCWSTR rgwcInput,
  721. ...
  722. )
  723. {
  724. DWORD dwMsgLen = 0;
  725. LPCWSTR pwszOutput = NULL;
  726. va_list arglist;
  727. va_start(arglist, rgwcInput);
  728. if (!rgwcInput)
  729. {
  730. return ERROR_INVALID_PARAMETER;
  731. }
  732. return DisplayMessageVA(rgwcInput, &arglist);
  733. }
  734. DWORD
  735. PrintMessageFromModule(
  736. IN HANDLE hModule,
  737. IN DWORD dwMsgId,
  738. ...
  739. )
  740. {
  741. WCHAR rgwcInput[MAX_MSG_LENGTH + 1];
  742. va_list arglist;
  743. if ( !LoadStringW(hModule,
  744. dwMsgId,
  745. rgwcInput,
  746. MAX_MSG_LENGTH) )
  747. {
  748. return 0;
  749. }
  750. va_start(arglist, dwMsgId);
  751. return DisplayMessageVA(rgwcInput, &arglist);
  752. }
  753. DWORD
  754. DisplayMessageM(
  755. IN HANDLE hModule,
  756. IN DWORD dwMsgId,
  757. ...
  758. )
  759. {
  760. DWORD dwMsgLen;
  761. LPWSTR pwszOutput = NULL;
  762. va_list arglist;
  763. do
  764. {
  765. va_start(arglist, dwMsgId);
  766. dwMsgLen = FormatMessageW(
  767. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  768. FORMAT_MESSAGE_FROM_HMODULE,
  769. hModule,
  770. dwMsgId,
  771. 0L,
  772. (LPWSTR)&pwszOutput,
  773. 0,
  774. &arglist
  775. );
  776. if(dwMsgLen == 0)
  777. {
  778. DWORD dwErr;
  779. dwErr = GetLastError();
  780. ASSERT(pwszOutput == NULL);
  781. break;
  782. }
  783. OEMprintf( pwszOutput );
  784. } while ( FALSE );
  785. if ( pwszOutput) { LocalFree( pwszOutput ); }
  786. return dwMsgLen;
  787. }
  788. DWORD
  789. DisplayMessageToConsole(
  790. IN HANDLE hModule,
  791. IN HANDLE hConsole,
  792. IN DWORD dwMsgId,
  793. ...
  794. )
  795. {
  796. DWORD dwMsgLen = 0;
  797. LPWSTR pwszInput, pwszOutput = NULL;
  798. va_list arglist;
  799. DWORD dwNumWritten;
  800. do
  801. {
  802. va_start(arglist, dwMsgId);
  803. pwszInput = HeapAlloc(GetProcessHeap(),
  804. 0,
  805. MAX_MSG_LENGTH * sizeof(WCHAR));
  806. if ( pwszInput == (LPCWSTR) NULL )
  807. {
  808. break;
  809. }
  810. if ( !LoadStringW(hModule,
  811. dwMsgId,
  812. pwszInput,
  813. MAX_MSG_LENGTH) )
  814. {
  815. break;
  816. }
  817. dwMsgLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  818. pwszInput,
  819. 0,
  820. 0L, // Default country ID.
  821. (LPWSTR)&pwszOutput,
  822. 0,
  823. &arglist);
  824. if ( dwMsgLen == 0 )
  825. {
  826. break;
  827. }
  828. OEMfprintf( hConsole, pwszOutput );
  829. fflush(stdout);
  830. } while ( FALSE );
  831. if ( pwszInput ) { HeapFree( GetProcessHeap(), 0, pwszInput ); }
  832. if ( pwszOutput) { LocalFree( pwszOutput ); }
  833. return dwMsgLen;
  834. }
  835. BOOL
  836. WINAPI
  837. HandlerRoutine(
  838. DWORD dwCtrlType // control signal type
  839. )
  840. {
  841. HANDLE hStop;
  842. if (dwCtrlType == CTRL_C_EVENT)
  843. {
  844. hStop = OpenEvent(EVENT_ALL_ACCESS,
  845. FALSE,
  846. STOP_EVENT);
  847. if (hStop isnot NULL)
  848. {
  849. SetEvent(hStop);
  850. CloseHandle(hStop);
  851. }
  852. return TRUE;
  853. }
  854. else
  855. {
  856. // Need to handle the other events...
  857. // CTRL_BREAK_EVENT
  858. // CTRL_CLOSE_EVENT
  859. // CTRL_LOGOFF_EVENT
  860. // Need to clean up, free all the dll's we loaded.
  861. //
  862. FreeHelpers();
  863. FreeDlls();
  864. // Always need to return false for these events, otherwise the app will hang.
  865. //
  866. return FALSE;
  867. }
  868. };
  869. void
  870. cls(
  871. IN HANDLE hConsole
  872. )
  873. {
  874. COORD coordScreen = { 0, 0 };
  875. BOOL bSuccess;
  876. DWORD cCharsWritten;
  877. CONSOLE_SCREEN_BUFFER_INFO csbi;
  878. DWORD dwConSize;
  879. WORD wAttr;
  880. bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
  881. dwConSize = (WORD) csbi.dwSize.X * (WORD) csbi.dwSize.Y;
  882. bSuccess = FillConsoleOutputCharacter(hConsole,
  883. _TEXT(' '),
  884. dwConSize,
  885. coordScreen,
  886. &cCharsWritten);
  887. //
  888. // get the current text attribute
  889. //
  890. bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
  891. //
  892. // Make the background and foreground the same
  893. //
  894. wAttr = (csbi.wAttributes & 0xFFF0) | ((csbi.wAttributes & 0x00F0) >> 4);
  895. //
  896. // now set the buffer's attributes accordingly
  897. //
  898. bSuccess = FillConsoleOutputAttribute(hConsole,
  899. wAttr,
  900. dwConSize,
  901. coordScreen,
  902. &cCharsWritten);
  903. bSuccess = SetConsoleCursorPosition(hConsole, coordScreen);
  904. return;
  905. }
  906. BOOL
  907. WINAPI
  908. InitializeConsole(
  909. IN OUT PDWORD pdwRR,
  910. OUT HANDLE *phMib,
  911. OUT HANDLE *phConsole
  912. )
  913. {
  914. HANDLE hMib, hStdOut, hConsole;
  915. CONSOLE_SCREEN_BUFFER_INFO csbi;
  916. hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  917. if (hStdOut is INVALID_HANDLE_VALUE)
  918. {
  919. return FALSE;
  920. }
  921. if (!*pdwRR)
  922. {
  923. //
  924. // No refresh. Display to standard output
  925. //
  926. *phConsole = hStdOut;
  927. *phMib = (HANDLE) NULL;
  928. return TRUE;
  929. }
  930. do
  931. {
  932. hMib = CreateEvent( NULL, TRUE, FALSE, STOP_EVENT);
  933. if (hMib == NULL)
  934. {
  935. *pdwRR = 0;
  936. *phConsole = hStdOut;
  937. *phMib = (HANDLE) NULL;
  938. break;
  939. }
  940. *phMib = hMib;
  941. hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  942. 0, // NO sharing
  943. NULL,
  944. CONSOLE_TEXTMODE_BUFFER,
  945. NULL);
  946. if (hConsole is INVALID_HANDLE_VALUE)
  947. {
  948. //
  949. // No refresh will be done
  950. //
  951. *pdwRR = 0;
  952. *phConsole = hStdOut;
  953. *phMib = (HANDLE) NULL;
  954. break;
  955. }
  956. else
  957. {
  958. GetConsoleScreenBufferInfo(hStdOut, &csbi);
  959. csbi.dwSize.X = 80;
  960. SetConsoleScreenBufferSize(hConsole, csbi.dwSize);
  961. SetConsoleActiveScreenBuffer(hConsole);
  962. SetConsoleCtrlHandler(HandlerRoutine,TRUE);
  963. *phConsole = hConsole;
  964. }
  965. }while (FALSE);
  966. return TRUE;
  967. }
  968. DWORD
  969. WINAPI
  970. RefreshConsole(
  971. IN HANDLE hMib,
  972. IN HANDLE hConsole,
  973. IN DWORD dwRR
  974. )
  975. {
  976. COORD origin = {0,0};
  977. if (dwRR)
  978. {
  979. SetConsoleCursorPosition(hConsole, origin);
  980. if (WaitForSingleObject(hMib, dwRR) == WAIT_OBJECT_0)
  981. {
  982. //
  983. // End of refresh
  984. //
  985. ResetEvent(hMib);
  986. SetConsoleCtrlHandler(HandlerRoutine,FALSE);
  987. CloseHandle(hMib);
  988. CloseHandle(hConsole);
  989. // SetConsoleActiveScreenBuffer(g_hStdOut);
  990. return FALSE;
  991. }
  992. else
  993. {
  994. //
  995. // Go in loop again
  996. //
  997. cls(hConsole);
  998. return TRUE;
  999. }
  1000. }
  1001. return FALSE;
  1002. }
  1003. #define HT_TOP 0
  1004. #define HT_CONTEXT 1
  1005. #define HT_GROUP 2
  1006. typedef struct {
  1007. HANDLE hModule;
  1008. LPCWSTR pwszContext;
  1009. DWORD dwType;
  1010. LPCWSTR pwszCommand;
  1011. DWORD dwDescr;
  1012. LPCWSTR pwszDescr;
  1013. LPCWSTR pwszGroup;
  1014. } help_t;
  1015. #define MAX_HELP_COMMANDS 100
  1016. help_t help[MAX_HELP_COMMANDS];
  1017. ULONG ulNumHelpCommands = 0;
  1018. DWORD
  1019. FindHelpCommand(
  1020. IN LPCWSTR pwszCommand
  1021. )
  1022. {
  1023. ULONG i;
  1024. for (i=0; i<ulNumHelpCommands; i++)
  1025. {
  1026. if (!wcscmp(pwszCommand, help[i].pwszCommand))
  1027. {
  1028. return i;
  1029. }
  1030. }
  1031. return -1;
  1032. }
  1033. DWORD
  1034. AddHelpCommand(
  1035. IN HANDLE hModule,
  1036. IN LPCWSTR pwszContext,
  1037. IN DWORD dwType,
  1038. IN LPCWSTR pwszCommand,
  1039. IN DWORD dwDescr,
  1040. IN LPCWSTR pwszDescr,
  1041. IN LPCWSTR pwszGroup
  1042. )
  1043. {
  1044. ULONG i;
  1045. ASSERT(ulNumHelpCommands < MAX_HELP_COMMANDS); // XXX
  1046. i = ulNumHelpCommands++;
  1047. help[i].hModule = hModule;
  1048. help[i].pwszContext = pwszContext;
  1049. help[i].dwType = dwType;
  1050. help[i].pwszCommand = pwszCommand;
  1051. help[i].dwDescr = dwDescr;
  1052. help[i].pwszDescr = pwszDescr;
  1053. help[i].pwszGroup = pwszGroup;
  1054. return NO_ERROR;
  1055. }
  1056. int
  1057. __cdecl
  1058. helpcmp(
  1059. const void *a,
  1060. const void *b
  1061. )
  1062. {
  1063. return _wcsicmp(((help_t*)a)->pwszCommand, ((help_t*)b)->pwszCommand);
  1064. }
  1065. DWORD
  1066. DisplayAllHelpCommands(
  1067. )
  1068. {
  1069. ULONG i;
  1070. // Sort
  1071. qsort( (void*)help, ulNumHelpCommands, sizeof(help_t), helpcmp );
  1072. for (i=0; i<ulNumHelpCommands; i++)
  1073. {
  1074. if ((HT_GROUP == help[i].dwType) && help[i].pwszGroup)
  1075. {
  1076. LPWSTR pwszGroupFullCmd = (LPWSTR)
  1077. MALLOC( ( wcslen(help[i].pwszGroup) +
  1078. wcslen(help[i].pwszCommand) +
  1079. 2 // for blank and NULL characters
  1080. ) * sizeof(WCHAR)
  1081. );
  1082. if (NULL == pwszGroupFullCmd)
  1083. {
  1084. PrintMessage( MSG_HELP_START, help[i].pwszCommand );
  1085. }
  1086. else
  1087. {
  1088. wcscpy(pwszGroupFullCmd, help[i].pwszGroup);
  1089. wcscat(pwszGroupFullCmd, L" ");
  1090. wcscat(pwszGroupFullCmd, help[i].pwszCommand);
  1091. PrintMessage( MSG_HELP_START, pwszGroupFullCmd );
  1092. FREE(pwszGroupFullCmd);
  1093. }
  1094. }
  1095. else
  1096. {
  1097. PrintMessage( MSG_HELP_START, help[i].pwszCommand );
  1098. }
  1099. if (!PrintMessageFromModule( help[i].hModule, help[i].dwDescr, help[i].pwszDescr,
  1100. help[i].pwszContext,
  1101. (help[i].pwszContext[0])? L" " : L"" ))
  1102. {
  1103. PrintMessage(MSG_NEWLINE);
  1104. }
  1105. }
  1106. // Delete all help commands
  1107. ulNumHelpCommands = 0;
  1108. return NO_ERROR;
  1109. }
  1110. VOID
  1111. DisplayContextsHere(
  1112. IN ULONG ulNumContexts,
  1113. IN PBYTE pByteContexts,
  1114. IN DWORD dwContextSize,
  1115. IN DWORD dwDisplayFlags
  1116. )
  1117. {
  1118. DWORD i;
  1119. PCNS_CONTEXT_ATTRIBUTES pContext;
  1120. if (!ulNumContexts)
  1121. {
  1122. return;
  1123. }
  1124. PrintMessageFromModule(g_hModule, MSG_SUBCONTEXT_LIST);
  1125. for (i = 0; i < ulNumContexts; i++)
  1126. {
  1127. pContext = (PCNS_CONTEXT_ATTRIBUTES)(pByteContexts + i*dwContextSize);
  1128. if (pContext->dwFlags & ~dwDisplayFlags)
  1129. {
  1130. continue;
  1131. }
  1132. if (!VerifyOsVersion(pContext->pfnOsVersionCheck))
  1133. {
  1134. continue;
  1135. }
  1136. PrintMessage(L" %1!s!", pContext->pwszContext);
  1137. }
  1138. PrintMessage(MSG_NEWLINE);
  1139. }
  1140. DWORD
  1141. DisplayContextHelp(
  1142. IN PCNS_CONTEXT_ATTRIBUTES pContext,
  1143. IN DWORD dwDisplayFlags,
  1144. IN DWORD dwCmdFlags,
  1145. IN DWORD dwArgsRemaining,
  1146. IN LPCWSTR pwszGroup
  1147. )
  1148. {
  1149. DWORD i, j, dwErr;
  1150. PNS_HELPER_TABLE_ENTRY pHelper;
  1151. ULONG ulNumContexts;
  1152. DWORD dwContextSize;
  1153. PBYTE pByteContexts;
  1154. PNS_DLL_TABLE_ENTRY pDll;
  1155. PCNS_CONTEXT_ATTRIBUTES pSubContext;
  1156. LPWSTR pwszFullContextName = NULL;
  1157. dwErr = GetHelperEntry(&pContext->guidHelper, &pHelper);
  1158. if (dwErr)
  1159. {
  1160. return dwErr;
  1161. }
  1162. dwErr = GetDllEntry( pHelper->dwDllIndex, &pDll );
  1163. if (dwErr)
  1164. {
  1165. return dwErr;
  1166. }
  1167. dwErr = AppendFullContextName(pContext, &pwszFullContextName);
  1168. ulNumContexts = pHelper->ulNumSubContexts;
  1169. dwContextSize = pHelper->ulSubContextSize;
  1170. pByteContexts = pHelper->pSubContextTable;
  1171. // First set up flags
  1172. if (dwCmdFlags & CMD_FLAG_INTERACTIVE)
  1173. {
  1174. dwDisplayFlags |= CMD_FLAG_INTERACTIVE;
  1175. }
  1176. if (dwCmdFlags & CMD_FLAG_ONLINE)
  1177. {
  1178. dwDisplayFlags |= CMD_FLAG_ONLINE;
  1179. }
  1180. if (dwCmdFlags & CMD_FLAG_LOCAL)
  1181. {
  1182. dwDisplayFlags |= CMD_FLAG_LOCAL;
  1183. }
  1184. if (IsImmediate(dwCmdFlags, dwArgsRemaining))
  1185. {
  1186. dwCmdFlags |= CMD_FLAG_IMMEDIATE;
  1187. }
  1188. // Turn on any flags not used to limit commands
  1189. // so they won't cause commands to not be displayed
  1190. dwDisplayFlags |= ~CMD_FLAG_LIMIT_MASK;
  1191. if (dwDisplayFlags & CMD_FLAG_PRIVATE)
  1192. {
  1193. PrintMessageFromModule(g_hModule, MSG_SHELL_CMD_HELP_HEADER);
  1194. }
  1195. // dwDisplayFlags has PRIVATE set *unless* this is called as a result of
  1196. // printing help in the parent context, and non-inheritable commands
  1197. // should not be printed.
  1198. //
  1199. // dwCmdFlags has IMMEDIATE set *unless* this is called from a parent
  1200. // context, in which case parent help should not be printed.
  1201. if ((!(dwDisplayFlags & CMD_FLAG_PRIVATE)
  1202. || (dwCmdFlags & CMD_FLAG_IMMEDIATE)))
  1203. {
  1204. // Print help on inherited commands
  1205. PCNS_CONTEXT_ATTRIBUTES pParentContext;
  1206. dwErr = GetParentContext( pContext, &pParentContext );
  1207. if (dwErr is NO_ERROR)
  1208. {
  1209. dwErr = DisplayContextHelp( pParentContext,
  1210. dwDisplayFlags & ~CMD_FLAG_PRIVATE,
  1211. dwCmdFlags,
  1212. dwArgsRemaining,
  1213. pwszGroup );
  1214. }
  1215. }
  1216. for(i = 0; !pwszGroup && (i < pContext->ulNumTopCmds); i++)
  1217. {
  1218. if (((*pContext->pTopCmds)[i].dwCmdHlpToken == MSG_NULL)
  1219. || ((*pContext->pTopCmds)[i].dwFlags & ~dwDisplayFlags))
  1220. {
  1221. continue;
  1222. }
  1223. if (!VerifyOsVersion((*pContext->pTopCmds)[i].pOsVersionCheck))
  1224. {
  1225. continue;
  1226. }
  1227. AddHelpCommand( pDll->hDll,
  1228. pwszFullContextName,
  1229. HT_TOP,
  1230. (*pContext->pTopCmds)[i].pwszCmdToken,
  1231. (*pContext->pTopCmds)[i].dwShortCmdHelpToken,
  1232. NULL, NULL );
  1233. }
  1234. for(i = 0; i < pContext->ulNumGroups; i++)
  1235. {
  1236. if (((*pContext->pCmdGroups)[i].dwShortCmdHelpToken == MSG_NULL)
  1237. || ((*pContext->pCmdGroups)[i].dwFlags & ~dwDisplayFlags))
  1238. {
  1239. continue;
  1240. }
  1241. if (!(*pContext->pCmdGroups)[i].pwszCmdGroupToken[0])
  1242. {
  1243. continue;
  1244. }
  1245. if (pwszGroup)
  1246. {
  1247. if (_wcsicmp(pwszGroup, (*pContext->pCmdGroups)[i].pwszCmdGroupToken))
  1248. {
  1249. continue;
  1250. }
  1251. if (!VerifyOsVersion((*pContext->pCmdGroups)[i].pOsVersionCheck))
  1252. {
  1253. continue;
  1254. }
  1255. for (j = 0; j < (*pContext->pCmdGroups)[i].ulCmdGroupSize; j++)
  1256. {
  1257. if ((*pContext->pCmdGroups)[i].pCmdGroup[j].dwFlags & ~dwDisplayFlags)
  1258. {
  1259. continue;
  1260. }
  1261. if (!VerifyOsVersion((*pContext->pCmdGroups)[i].pCmdGroup[j].pOsVersionCheck))
  1262. {
  1263. continue;
  1264. }
  1265. AddHelpCommand( pDll->hDll,
  1266. pwszFullContextName,
  1267. HT_GROUP,
  1268. (*pContext->pCmdGroups)[i].pCmdGroup[j].pwszCmdToken,
  1269. (*pContext->pCmdGroups)[i].pCmdGroup[j].dwShortCmdHelpToken,
  1270. NULL,
  1271. pwszGroup);
  1272. }
  1273. }
  1274. else
  1275. {
  1276. if (!VerifyOsVersion((*pContext->pCmdGroups)[i].pOsVersionCheck))
  1277. {
  1278. continue;
  1279. }
  1280. AddHelpCommand( pDll->hDll,
  1281. pwszFullContextName,
  1282. HT_GROUP,
  1283. (*pContext->pCmdGroups)[i].pwszCmdGroupToken,
  1284. (*pContext->pCmdGroups)[i].dwShortCmdHelpToken,
  1285. NULL, NULL );
  1286. }
  1287. }
  1288. for (i = 0; !pwszGroup && (i < ulNumContexts); i++)
  1289. {
  1290. pSubContext = (PCNS_CONTEXT_ATTRIBUTES)(pByteContexts + i * dwContextSize);
  1291. if ((pSubContext->dwFlags & ~dwDisplayFlags))
  1292. {
  1293. continue;
  1294. }
  1295. if (!VerifyOsVersion(pSubContext->pfnOsVersionCheck))
  1296. {
  1297. continue;
  1298. }
  1299. AddHelpCommand( g_hModule,
  1300. pwszFullContextName,
  1301. HT_CONTEXT,
  1302. pSubContext->pwszContext,
  1303. MSG_HELPER_HELP,
  1304. pSubContext->pwszContext, NULL );
  1305. }
  1306. if (dwDisplayFlags & CMD_FLAG_PRIVATE)
  1307. {
  1308. // Add any ubiquitous commands that aren't already added
  1309. for(i = 0; !pwszGroup && (i < g_ulNumUbiqCmds); i++)
  1310. {
  1311. if ((g_UbiqCmds[i].dwCmdHlpToken == MSG_NULL)
  1312. || (g_UbiqCmds[i].dwFlags & ~dwDisplayFlags))
  1313. {
  1314. continue;
  1315. }
  1316. if (FindHelpCommand(g_UbiqCmds[i].pwszCmdToken) isnot -1)
  1317. {
  1318. continue;
  1319. }
  1320. AddHelpCommand( g_hModule,
  1321. pwszFullContextName,
  1322. HT_TOP,
  1323. g_UbiqCmds[i].pwszCmdToken,
  1324. g_UbiqCmds[i].dwShortCmdHelpToken,
  1325. NULL, NULL );
  1326. }
  1327. }
  1328. if (ulNumHelpCommands > 0)
  1329. {
  1330. if (dwDisplayFlags & CMD_FLAG_PRIVATE)
  1331. {
  1332. PrintMessageFromModule( g_hModule, MSG_LOCAL_COMMANDS );
  1333. }
  1334. else if (help[0].pwszContext[0])
  1335. {
  1336. PrintMessageFromModule( g_hModule,
  1337. MSG_INHERITED_COMMANDS,
  1338. help[0].pwszContext );
  1339. }
  1340. else
  1341. {
  1342. PrintMessageFromModule( g_hModule, MSG_GLOBAL_COMMANDS );
  1343. }
  1344. DisplayAllHelpCommands();
  1345. }
  1346. // Once we've popped the stack back up to the original context
  1347. // in which the help command was run, display all the subcontexts
  1348. // available here.
  1349. if ((dwDisplayFlags & CMD_FLAG_PRIVATE) && !pwszGroup)
  1350. {
  1351. DisplayContextsHere( pHelper->ulNumSubContexts,
  1352. pHelper->pSubContextTable,
  1353. pHelper->ulSubContextSize,
  1354. dwDisplayFlags );
  1355. PrintMessageFromModule( g_hModule, MSG_HELP_FOOTER, CMD_HELP2 );
  1356. }
  1357. if (pwszFullContextName)
  1358. {
  1359. FREE(pwszFullContextName);
  1360. }
  1361. return NO_ERROR;
  1362. }
  1363. DWORD
  1364. WINAPI
  1365. DisplayHelp(
  1366. IN CONST GUID *pguidHelper,
  1367. IN LPCWSTR pwszContext,
  1368. IN DWORD dwDisplayFlags,
  1369. IN DWORD dwCmdFlags,
  1370. IN DWORD dwArgsRemaining,
  1371. IN LPCWSTR pwszGroup
  1372. )
  1373. {
  1374. DWORD i, j, dwErr;
  1375. PCNS_CONTEXT_ATTRIBUTES pContext;
  1376. PNS_HELPER_TABLE_ENTRY pHelper;
  1377. // Locate helper
  1378. dwErr = GetHelperEntry( pguidHelper, &pHelper );
  1379. // Locate context
  1380. dwErr = GetContextEntry( pHelper, pwszContext, &pContext );
  1381. if (dwErr)
  1382. {
  1383. return dwErr;
  1384. }
  1385. return DisplayContextHelp( pContext,
  1386. dwDisplayFlags,
  1387. dwCmdFlags,
  1388. dwArgsRemaining,
  1389. pwszGroup );
  1390. }
  1391. DWORD
  1392. WINAPI
  1393. PreprocessCommand(
  1394. IN HANDLE hModule,
  1395. IN OUT LPWSTR *ppwcArguments,
  1396. IN DWORD dwCurrentIndex,
  1397. IN DWORD dwArgCount,
  1398. IN OUT PTAG_TYPE pttTags,
  1399. IN DWORD dwTagCount,
  1400. IN DWORD dwMinArgs,
  1401. IN DWORD dwMaxArgs,
  1402. OUT DWORD *pdwTagType
  1403. )
  1404. /*++
  1405. Description:
  1406. Make sure the number of arguments is valid.
  1407. Make sure there are no duplicate or unrecognized tags.
  1408. Arguments:
  1409. ppwcArguments - Argument array
  1410. dwCurrentIndex - ppwcArguments[dwCurrentIndex] is the first arg
  1411. dwArgCount - ppwcArguments[dwArgCount - 1] is the last arg
  1412. pttTags - Legal tags
  1413. dwTagCount - Number of legal tags
  1414. dwMinArgs - minimum # of args required
  1415. dwMaxArgs - maximum # of args required
  1416. pdwTagType - Index into pttTags for each argument
  1417. --*/
  1418. {
  1419. DWORD dwNumArgs, i;
  1420. DWORD dwErr = NO_ERROR;
  1421. DWORD dwTagEnum;
  1422. if ( (!ppwcArguments) || (!pttTags) || (!pdwTagType) )
  1423. {
  1424. return ERROR_INVALID_PARAMETER;
  1425. }
  1426. for (dwTagEnum = 0; dwTagEnum < dwTagCount; dwTagEnum++)
  1427. {
  1428. pttTags->bPresent = FALSE;
  1429. }
  1430. #ifdef EXTRA_DEBUG
  1431. PRINT("PreHandleCommand:");
  1432. for( i = 0; i < dwArgCount; i++)
  1433. {
  1434. PRINT(ppwcArguments[i]);
  1435. }
  1436. #endif
  1437. dwNumArgs = dwArgCount - dwCurrentIndex;
  1438. if((dwNumArgs < dwMinArgs) or
  1439. (dwNumArgs > dwMaxArgs))
  1440. {
  1441. //
  1442. // Wrong number of arguments specified
  1443. //
  1444. return ERROR_INVALID_SYNTAX;
  1445. }
  1446. if ( dwNumArgs > 0 )
  1447. {
  1448. dwErr = MatchTagsInCmdLine(hModule,
  1449. ppwcArguments,
  1450. dwCurrentIndex,
  1451. dwArgCount,
  1452. pttTags,
  1453. dwTagCount,
  1454. pdwTagType);
  1455. if (dwErr isnot NO_ERROR)
  1456. {
  1457. if (dwErr is ERROR_INVALID_OPTION_TAG)
  1458. {
  1459. return ERROR_INVALID_SYNTAX;
  1460. }
  1461. return dwErr;
  1462. }
  1463. }
  1464. // Make sure we don't have duplicate or unrecognized tags
  1465. for(i = 0; i < dwNumArgs; i ++)
  1466. {
  1467. if ((int) pdwTagType[i] < 0 || pdwTagType[i] >= dwTagCount)
  1468. {
  1469. dwErr = ERROR_INVALID_SYNTAX;
  1470. break;
  1471. }
  1472. }
  1473. switch(dwErr)
  1474. {
  1475. case NO_ERROR:
  1476. {
  1477. break;
  1478. }
  1479. default:
  1480. {
  1481. return dwErr;
  1482. }
  1483. }
  1484. // Make sure every required tag is present
  1485. for(i = 0; i < dwTagCount; i++)
  1486. {
  1487. if ((pttTags[i].dwRequired & NS_REQ_PRESENT)
  1488. && !pttTags[i].bPresent)
  1489. {
  1490. PrintMessageFromModule(g_hModule, ERROR_MISSING_OPTION);
  1491. return ERROR_INVALID_SYNTAX;
  1492. }
  1493. }
  1494. return NO_ERROR;
  1495. }
  1496. #define HISTORY_MASK (NS_EVENT_LAST_N | NS_EVENT_FROM_N | \
  1497. NS_EVENT_FROM_START | NS_EVENT_LAST_SECS)
  1498. DWORD
  1499. WINAPI
  1500. PrintEventLog(
  1501. IN LPCWSTR pwszLogName,
  1502. IN LPCWSTR pwszComponent,
  1503. IN LPCWSTR pwszSubComponent, OPTIONAL
  1504. IN DWORD fFlags,
  1505. IN LPCVOID pvHistoryInfo,
  1506. IN PNS_EVENT_FILTER pfnEventFilter, OPTIONAL
  1507. IN LPCVOID pvFilterContext
  1508. )
  1509. /*++
  1510. Routine Description:
  1511. Called by monitors and helpers to print events in the eventlog
  1512. It can either work in a refresh mode where it will loop till a CRTL-C
  1513. is entered, or will print only the history. The function looks up
  1514. the message file for the component by reading the REG_EXPAND_SZ value
  1515. in Services\Eventlog\pwszComponent\EventMessageFile.
  1516. It then loads the library, and gets the PNS_QUERY_SUBCOMPONENT function.
  1517. It calls the function to map the subcomponent to an array of eventids.
  1518. According to the flags given, the function seeks to the right position
  1519. in the event log file. It then prints out all logs that fall in the
  1520. component/subcomp from the seek pointer to the current time. If the user
  1521. specifies NS_EVENT_LOOP, then we set up a notification to the eventlog
  1522. and print messages as they get written
  1523. Arguments:
  1524. pwszLogName Event Log source (e.g L"System", L"Security")
  1525. pwszComponent Name of the component whose events are to be logged
  1526. dwComponentId Subcomponent. 0 means all
  1527. fFlags Flags that control printing and history
  1528. pvHistoryInfo Depends on flags -
  1529. NS_EVENT_LAST_N - this is the (DWORD) number of records
  1530. to go back
  1531. NS_EVENT_FROM_N - this is an event id (DWORD). We go back
  1532. to the latest instance of event id N
  1533. NS_EVENT_FROM_START - this is ignored. We go to event
  1534. 6005, source EVENTLOG
  1535. NS_EVENT_LAST_SECS - this is the number of seconds (DWORD)
  1536. to go back
  1537. pfnEventFilter If specified, this is a callback function the caller
  1538. can specify for additional filtering
  1539. pvFilterContext Passed to pfnEventFilter
  1540. Return Value:
  1541. ERROR_INVALID_FLAGS
  1542. --*/
  1543. {
  1544. HANDLE hEventLog, hEvent, hStop, rghEvents[2];
  1545. HINSTANCE hInst;
  1546. HKEY hkRoot, hkKey;
  1547. LPWSTR pwszValueName;
  1548. ULONG ulLen, ulEventCount;
  1549. DWORD dwResult, dwType;
  1550. PDWORD pdwEventIds;
  1551. BOOL bDone;
  1552. WCHAR rgwcDll[MAX_PATH + 2], rgwcRealDll[MAX_PATH + 2];
  1553. EVENT_PRINT_INFO EventInfo;
  1554. PNS_GET_EVENT_IDS_FN pfnQueryEventIds;
  1555. //
  1556. // Validate the flags. User has to tell us atleast whether he wants
  1557. // history or looping
  1558. // Also the history flags (NS_EVENT_LAST_N, NS_EVENT_FROM_N,
  1559. // NS_EVENT_FROM_START and NS_EVENT_LAST_SECS) are all mutually exclusive
  1560. //
  1561. if((fFlags is 0) or
  1562. (((fFlags & NS_EVENT_LAST_N) and (fFlags & (HISTORY_MASK ^ NS_EVENT_LAST_N))) or
  1563. ((fFlags & NS_EVENT_LAST_SECS) and (fFlags & (HISTORY_MASK ^ NS_EVENT_LAST_SECS))) or
  1564. ((fFlags & NS_EVENT_FROM_N) and (fFlags & (HISTORY_MASK ^ NS_EVENT_FROM_N))) or
  1565. ((fFlags & NS_EVENT_FROM_START) and (fFlags & (HISTORY_MASK ^ NS_EVENT_FROM_START)))))
  1566. {
  1567. return ERROR_INVALID_FLAGS;
  1568. }
  1569. //
  1570. // Create the value name
  1571. //
  1572. ulLen = wcslen(EVENT_MSG_KEY_W) + wcslen(pwszLogName) +
  1573. wcslen(L"\\") + wcslen(pwszComponent) + 1;
  1574. ulLen *= sizeof(WCHAR);
  1575. __try
  1576. {
  1577. pwszValueName = _alloca(ulLen);
  1578. }
  1579. __except(EXCEPTION_EXECUTE_HANDLER)
  1580. {
  1581. return ERROR_NOT_ENOUGH_MEMORY;
  1582. }
  1583. //
  1584. // First query the registry to see what dll contains the messages
  1585. // for the component
  1586. //
  1587. dwResult = RegConnectRegistryW(g_pwszRouterName,
  1588. HKEY_LOCAL_MACHINE,
  1589. &hkRoot);
  1590. if(dwResult isnot NO_ERROR)
  1591. {
  1592. return dwResult;
  1593. }
  1594. RtlZeroMemory(pwszValueName, ulLen);
  1595. //
  1596. // Setup the key
  1597. //
  1598. wcscpy(pwszValueName,
  1599. EVENT_MSG_KEY_W);
  1600. wcscat(pwszValueName,
  1601. pwszLogName);
  1602. wcscat(pwszValueName,
  1603. L"\\");
  1604. wcscat(pwszValueName,
  1605. pwszComponent);
  1606. dwResult = RegOpenKeyExW(hkRoot,
  1607. pwszValueName,
  1608. 0,
  1609. KEY_READ,
  1610. &hkKey);
  1611. //
  1612. // This is actually a very bad thing to do (calling RegCloseKey on a
  1613. // predefined handle
  1614. //
  1615. RegCloseKey(hkRoot);
  1616. if(dwResult isnot NO_ERROR)
  1617. {
  1618. return dwResult;
  1619. }
  1620. ulLen = sizeof(rgwcDll);
  1621. //
  1622. // Get the value of the message dll
  1623. //
  1624. dwResult = RegQueryValueExW(hkKey,
  1625. EVENT_MSG_FILE_VALUE_W,
  1626. NULL,
  1627. &dwType,
  1628. (PBYTE)rgwcDll,
  1629. &ulLen);
  1630. RegCloseKey(hkKey);
  1631. if(dwResult isnot NO_ERROR)
  1632. {
  1633. return dwResult;
  1634. }
  1635. if(dwType isnot REG_EXPAND_SZ)
  1636. {
  1637. return ERROR_DATATYPE_MISMATCH;
  1638. }
  1639. if(ulLen is 0)
  1640. {
  1641. return ERROR_REGISTRY_CORRUPT;
  1642. }
  1643. //
  1644. // Expand the type
  1645. //
  1646. ulLen = MAX_PATH + 2;
  1647. if(ExpandEnvironmentStringsW(rgwcDll,
  1648. rgwcRealDll,
  1649. ulLen) >= ulLen)
  1650. {
  1651. //
  1652. // Shouldnt be more than MAX_PATH
  1653. //
  1654. return ERROR_REGISTRY_CORRUPT;
  1655. }
  1656. //
  1657. // Now load the DLL and query its function ptr
  1658. // IMPORTANT - we read the remote registry but look for the DLL on the
  1659. // local machine
  1660. //
  1661. hInst = LoadLibraryW(rgwcRealDll);
  1662. if(hInst is NULL)
  1663. {
  1664. return GetLastError();
  1665. }
  1666. //
  1667. // Get the set of event ids
  1668. //
  1669. pdwEventIds = NULL;
  1670. if(pwszSubComponent is NULL)
  1671. {
  1672. //
  1673. // Means the caller wants all events generated by the component
  1674. // printed out. To do this we just set ulEventCount to 0
  1675. //
  1676. ulEventCount = 0;
  1677. }
  1678. else
  1679. {
  1680. //
  1681. // Get the procaddr of the function which will tell us the
  1682. // set
  1683. //
  1684. pfnQueryEventIds =
  1685. (PNS_GET_EVENT_IDS_FN) GetProcAddress((HMODULE)hInst,
  1686. NS_GET_EVENT_IDS_FN_NAME);
  1687. if(pfnQueryEventIds is NULL)
  1688. {
  1689. FreeLibrary((HMODULE)hInst);
  1690. return ERROR_PROC_NOT_FOUND;
  1691. }
  1692. //
  1693. // Now call the function to get an array of eventids
  1694. //
  1695. ulEventCount = 0;
  1696. dwResult = pfnQueryEventIds(pwszComponent,
  1697. pwszSubComponent,
  1698. NULL,
  1699. &ulEventCount);
  1700. if(dwResult is ERROR_INSUFFICIENT_BUFFER)
  1701. {
  1702. do
  1703. {
  1704. //
  1705. // Allocate the event table
  1706. //
  1707. __try
  1708. {
  1709. pdwEventIds = _alloca(ulEventCount * sizeof(DWORD));
  1710. }
  1711. __except(EXCEPTION_EXECUTE_HANDLER)
  1712. {
  1713. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  1714. break;
  1715. }
  1716. dwResult = pfnQueryEventIds(pwszComponent,
  1717. pwszSubComponent,
  1718. pdwEventIds,
  1719. &ulEventCount);
  1720. }while(FALSE);
  1721. }
  1722. if(dwResult isnot NO_ERROR)
  1723. {
  1724. FreeLibrary((HMODULE)hInst);
  1725. return dwResult;
  1726. }
  1727. }
  1728. //
  1729. // Open the eventlog and seek to the pointer depending on the history
  1730. // flags being passed
  1731. //
  1732. EventInfo.pwszLogName = pwszLogName;
  1733. EventInfo.pwszComponent = pwszComponent;
  1734. EventInfo.pwszSubComponent = pwszSubComponent;
  1735. EventInfo.fFlags = (fFlags & HISTORY_MASK);
  1736. EventInfo.dwHistoryContext = PtrToUlong(pvHistoryInfo);
  1737. EventInfo.ulEventCount = ulEventCount;
  1738. EventInfo.pdwEventIds = pdwEventIds;
  1739. EventInfo.pfnEventFilter = pfnEventFilter;
  1740. EventInfo.pvFilterContext = pvFilterContext;
  1741. dwResult = SetupEventLogSeekPtr(&hEventLog,
  1742. &EventInfo);
  1743. if(dwResult isnot NO_ERROR)
  1744. {
  1745. FreeLibrary((HMODULE)hInst);
  1746. return dwResult;
  1747. }
  1748. PrintHistory(hEventLog,
  1749. hInst,
  1750. &EventInfo);
  1751. if(!(fFlags & NS_EVENT_LOOP))
  1752. {
  1753. FreeLibrary((HMODULE)hInst);
  1754. CloseEventLog(hEventLog);
  1755. return NO_ERROR;
  1756. }
  1757. //
  1758. // The user wants to loop, printing events as they come
  1759. // Create the event that will notify us that a new event was written
  1760. //
  1761. hEvent = CreateEvent(NULL,
  1762. FALSE,
  1763. FALSE,
  1764. NULL);
  1765. if(hEvent is NULL)
  1766. {
  1767. FreeLibrary((HMODULE)hInst);
  1768. CloseEventLog(hEventLog);
  1769. return GetLastError();
  1770. }
  1771. //
  1772. // Create the event for the ctrl-c handler
  1773. //
  1774. hStop = CreateEvent(NULL,
  1775. FALSE,
  1776. FALSE,
  1777. STOP_EVENT);
  1778. if(hStop is NULL)
  1779. {
  1780. FreeLibrary((HMODULE)hInst);
  1781. CloseEventLog(hEventLog);
  1782. CloseHandle(hEvent);
  1783. return GetLastError();
  1784. }
  1785. //
  1786. // Register for event change notifications
  1787. //
  1788. if(!NotifyChangeEventLog(hEventLog,
  1789. hEvent))
  1790. {
  1791. FreeLibrary((HMODULE)hInst);
  1792. CloseEventLog(hEventLog);
  1793. CloseHandle(hEvent);
  1794. CloseHandle(hStop);
  1795. return GetLastError();
  1796. }
  1797. //
  1798. // Handler routine opens the named stop event and sets it
  1799. // when a ctrl-c is hit
  1800. //
  1801. SetConsoleCtrlHandler(HandlerRoutine,
  1802. TRUE);
  1803. rghEvents[0] = hEvent;
  1804. rghEvents[1] = hStop;
  1805. bDone = FALSE;
  1806. while(!bDone)
  1807. {
  1808. dwResult = WaitForMultipleObjectsEx(2,
  1809. rghEvents,
  1810. FALSE,
  1811. INFINITE,
  1812. TRUE);
  1813. switch((dwResult - WAIT_OBJECT_0))
  1814. {
  1815. case 0:
  1816. {
  1817. PrintHistory(hEventLog,
  1818. hInst,
  1819. &EventInfo);
  1820. break;
  1821. }
  1822. case 1:
  1823. {
  1824. bDone = TRUE;
  1825. break;
  1826. }
  1827. }
  1828. }
  1829. FreeLibrary((HMODULE)hInst);
  1830. CloseEventLog(hEventLog);
  1831. CloseHandle(hEvent);
  1832. CloseHandle(hStop);
  1833. return NO_ERROR;
  1834. }
  1835. DWORD
  1836. SetupEventLogSeekPtr(
  1837. OUT PHANDLE phEventLog,
  1838. IN PEVENT_PRINT_INFO pEventInfo
  1839. )
  1840. /*++
  1841. Routine Description:
  1842. This function opens a handle to the appropriate event log and "rewinds"
  1843. to the correct point as specified by the fflags. When the function returns
  1844. the eventlog handle is setup such that reading the log sequentially in a
  1845. forward direction will get the events the caller wants
  1846. Locks:
  1847. None
  1848. Arguments:
  1849. See above, args are passed pretty much the same
  1850. Return Value:
  1851. Win32
  1852. --*/
  1853. {
  1854. DWORD dwResult, dwRead, dwNeed, i, dwHistoryContext;
  1855. ULONGLONG Buffer[512]; // Huge buffer
  1856. DWORD_PTR pNextEvent;
  1857. BOOL bResult, bDone;
  1858. LPCWSTR pwszComponent;
  1859. EVENTLOGRECORD *pStartEvent;
  1860. dwResult = NO_ERROR;
  1861. //
  1862. // Open the event log
  1863. //
  1864. *phEventLog = OpenEventLogW(g_pwszRouterName,
  1865. pEventInfo->pwszLogName);
  1866. if(*phEventLog is NULL)
  1867. {
  1868. return GetLastError();
  1869. }
  1870. if(pEventInfo->fFlags is 0)
  1871. {
  1872. //
  1873. // If no history is being requested, just return. Our seek ptr
  1874. // will be already setup
  1875. //
  1876. return NO_ERROR;
  1877. }
  1878. if(pEventInfo->fFlags & NS_EVENT_FROM_START)
  1879. {
  1880. //
  1881. // We can use the same matching for this as we do for NS_EVENT_FROM_N
  1882. // by setting component to eventlog and dwHistoryContext to 6005
  1883. //
  1884. pwszComponent = L"eventlog";
  1885. dwHistoryContext = 6005;
  1886. }
  1887. else
  1888. {
  1889. pwszComponent = pEventInfo->pwszComponent;
  1890. dwHistoryContext = pEventInfo->dwHistoryContext;
  1891. }
  1892. //
  1893. // Okay so she wants history. Either way we read backwards
  1894. //
  1895. i = 0;
  1896. pStartEvent = NULL;
  1897. bDone = FALSE;
  1898. //
  1899. // Read the event log till we find a record to stop at
  1900. // This is signalled by the code setting bDone to TRUE
  1901. //
  1902. while(!bDone)
  1903. {
  1904. //
  1905. // Get a bunch of events
  1906. //
  1907. bResult = ReadEventLogW(
  1908. *phEventLog,
  1909. EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ,
  1910. 0,
  1911. (PVOID)Buffer,
  1912. sizeof(Buffer),
  1913. &dwRead,
  1914. &dwNeed
  1915. );
  1916. if(bResult isnot TRUE)
  1917. {
  1918. dwResult = GetLastError();
  1919. if(dwResult is ERROR_HANDLE_EOF)
  1920. {
  1921. //
  1922. // If we have reached the end of the log, break out
  1923. //
  1924. bDone = TRUE;
  1925. break;
  1926. }
  1927. else
  1928. {
  1929. return dwResult;
  1930. }
  1931. }
  1932. //
  1933. // Start at the beginning of the buffer we just read
  1934. //
  1935. pNextEvent = (DWORD_PTR)Buffer;
  1936. //
  1937. // Read till we walk off the end of the buffer or find a record
  1938. //
  1939. // If we find the starting record, we set pStartEvent to one after that
  1940. // It may so happen that the starting record is the last one in
  1941. // the block that we have read. In that case, we set pStartEvent
  1942. // to NULL but bDone to TRUE
  1943. //
  1944. while((pNextEvent < (DWORD_PTR)Buffer + dwRead) and !bDone)
  1945. {
  1946. EVENTLOGRECORD *pCurrentEvent;
  1947. pCurrentEvent = (EVENTLOGRECORD *)pNextEvent;
  1948. pNextEvent += pCurrentEvent->Length;
  1949. switch(pEventInfo->fFlags)
  1950. {
  1951. case NS_EVENT_LAST_N:
  1952. case NS_EVENT_LAST_SECS:
  1953. {
  1954. //
  1955. // We are being asked to go back N (of our records)
  1956. // or go back N secs
  1957. //
  1958. if(!IsOurRecord(pCurrentEvent,
  1959. pEventInfo))
  1960. {
  1961. //
  1962. // Not one of ours
  1963. //
  1964. continue;
  1965. }
  1966. if(pEventInfo->fFlags is NS_EVENT_LAST_N)
  1967. {
  1968. //
  1969. // i is the count of events
  1970. //
  1971. i++;
  1972. }
  1973. else
  1974. {
  1975. time_t CurrentTime;
  1976. //
  1977. // i is the time difference in seconds
  1978. // = currentTime - eventTime
  1979. //
  1980. time(&CurrentTime);
  1981. //
  1982. // Subtract and truncate
  1983. //
  1984. i = (DWORD)(CurrentTime - pCurrentEvent->TimeGenerated);
  1985. }
  1986. if(i >= dwHistoryContext)
  1987. {
  1988. //
  1989. // Have gone back N (records or seconds)
  1990. //
  1991. if(pNextEvent < (DWORD_PTR)Buffer + dwRead)
  1992. {
  1993. //
  1994. // Have some more records in this buffer, so
  1995. // set pStartEvent to the next one
  1996. //
  1997. pStartEvent = (EVENTLOGRECORD *)pNextEvent;
  1998. }
  1999. else
  2000. {
  2001. pStartEvent = NULL;
  2002. }
  2003. //
  2004. // Done, break out of while(pNextEvent... and
  2005. // while(!bDone)
  2006. //
  2007. bDone = TRUE;
  2008. break;
  2009. }
  2010. break;
  2011. }
  2012. case NS_EVENT_FROM_N:
  2013. case NS_EVENT_FROM_START:
  2014. {
  2015. //
  2016. // We are being asked to go to the the most recent
  2017. // occurance of a certain event.
  2018. //
  2019. if(_wcsicmp((LPCWSTR)((DWORD_PTR)pCurrentEvent + sizeof(*pCurrentEvent)),
  2020. pwszComponent) == 0)
  2021. {
  2022. if(pCurrentEvent->EventID is dwHistoryContext)
  2023. {
  2024. if(pNextEvent < (DWORD_PTR)Buffer + dwRead)
  2025. {
  2026. pStartEvent = (EVENTLOGRECORD *)pNextEvent;
  2027. }
  2028. else
  2029. {
  2030. pStartEvent = NULL;
  2031. }
  2032. //
  2033. // Done, break out of while(pCurrent...
  2034. // and while(!bDone)
  2035. //
  2036. bDone = TRUE;
  2037. break;
  2038. }
  2039. }
  2040. }
  2041. default:
  2042. {
  2043. ASSERT(FALSE);
  2044. }
  2045. }
  2046. }
  2047. }
  2048. if(pStartEvent)
  2049. {
  2050. //
  2051. // So we found a record at which to start.
  2052. // API wants a buffer even if we set the size to 0
  2053. //
  2054. bResult = ReadEventLogW(*phEventLog,
  2055. EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
  2056. pStartEvent->RecordNumber,
  2057. (PVOID)Buffer,
  2058. 0,
  2059. &dwRead,
  2060. &dwNeed);
  2061. if(dwNeed < sizeof(Buffer))
  2062. {
  2063. ReadEventLogW(*phEventLog,
  2064. EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
  2065. pStartEvent->RecordNumber,
  2066. (PVOID)Buffer,
  2067. dwNeed,
  2068. &dwRead,
  2069. &dwNeed);
  2070. }
  2071. }
  2072. return NO_ERROR;
  2073. }
  2074. VOID
  2075. PrintHistory(
  2076. IN HANDLE hEventLog,
  2077. IN HINSTANCE hInst,
  2078. IN PEVENT_PRINT_INFO pEventInfo
  2079. )
  2080. {
  2081. DWORD dwResult, dwRead, dwNeed;
  2082. ULONGLONG Buffer[512]; // Huge buffer
  2083. DWORD_PTR pCurrent;
  2084. LPCWSTR *pInsertArray;
  2085. LPWSTR pwszOutput;
  2086. BOOL bResult;
  2087. ULONG ulCurrentInserts;
  2088. dwResult = NO_ERROR;
  2089. pInsertArray = NULL;
  2090. ulCurrentInserts = 0;
  2091. while(TRUE)
  2092. {
  2093. //
  2094. // Get a bunch of logs
  2095. //
  2096. bResult = ReadEventLogW(hEventLog,
  2097. EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
  2098. 0,
  2099. (PVOID)Buffer,
  2100. sizeof(Buffer),
  2101. &dwRead,
  2102. &dwNeed);
  2103. if((bResult isnot TRUE) or
  2104. (dwRead is 0))
  2105. {
  2106. dwResult = GetLastError();
  2107. return;
  2108. }
  2109. pCurrent = (DWORD_PTR)Buffer;
  2110. //
  2111. // Read till we walk off the end of the buffer
  2112. //
  2113. while(pCurrent < (DWORD_PTR)Buffer + dwRead)
  2114. {
  2115. EVENTLOGRECORD *pTemp;
  2116. LPCWSTR pInsertPtr;
  2117. DWORD i;
  2118. pTemp = (EVENTLOGRECORD *)pCurrent;
  2119. pCurrent += pTemp->Length;
  2120. if(!IsOurRecord(pTemp,
  2121. pEventInfo))
  2122. {
  2123. continue;
  2124. }
  2125. if(ulCurrentInserts < (ULONG)(pTemp->NumStrings + 1))
  2126. {
  2127. ulCurrentInserts = 2 * pTemp->NumStrings;
  2128. __try
  2129. {
  2130. pInsertArray = _alloca(ulCurrentInserts * sizeof(LPCWSTR));
  2131. }
  2132. __except(EXCEPTION_EXECUTE_HANDLER)
  2133. {
  2134. continue;
  2135. }
  2136. }
  2137. #define _FM_FLAGS (FORMAT_MESSAGE_ALLOCATE_BUFFER | \
  2138. FORMAT_MESSAGE_FROM_HMODULE | \
  2139. FORMAT_MESSAGE_ARGUMENT_ARRAY | \
  2140. FORMAT_MESSAGE_MAX_WIDTH_MASK)
  2141. dwResult = FormatMessageW(_FM_FLAGS,
  2142. hInst,
  2143. pTemp->EventID,
  2144. 0L,
  2145. (LPWSTR)&pwszOutput,
  2146. 0,
  2147. (va_list *)pInsertArray);
  2148. #undef _FM_FLAGS
  2149. if(dwResult is 0)
  2150. {
  2151. continue;
  2152. }
  2153. else
  2154. {
  2155. WCHAR pwszTime[26];
  2156. time_t TimeGenerated = pTemp->TimeGenerated;
  2157. //
  2158. // ctime is 26 chars with time[24] and time[25] being
  2159. // \n\0. So we copy 24 and set the 25th to \0
  2160. //
  2161. CopyMemory(pwszTime,
  2162. _wctime(&TimeGenerated),
  2163. 24 * sizeof(WCHAR));
  2164. pwszTime[24] = UNICODE_NULL;
  2165. printf("[%S] %S\n\n",
  2166. pwszTime,
  2167. pwszOutput);
  2168. LocalFree(pwszOutput);
  2169. }
  2170. }
  2171. }
  2172. return;
  2173. }
  2174. BOOL
  2175. IsOurRecord(
  2176. IN EVENTLOGRECORD *pRecord,
  2177. IN PEVENT_PRINT_INFO pEventInfo
  2178. )
  2179. {
  2180. BOOL bRet;
  2181. DWORD i;
  2182. if(_wcsicmp((LPCWSTR)((DWORD_PTR)pRecord + sizeof(*pRecord)),
  2183. pEventInfo->pwszComponent) isnot 0)
  2184. {
  2185. return FALSE;
  2186. }
  2187. bRet = TRUE;
  2188. //
  2189. // If ulEventCount is 0 means any event. So return TRUE
  2190. //
  2191. for(i = 0; i < pEventInfo->ulEventCount; i++)
  2192. {
  2193. bRet = (pRecord->EventID is pEventInfo->pdwEventIds[i]);
  2194. if(bRet)
  2195. {
  2196. break;
  2197. }
  2198. }
  2199. if(bRet)
  2200. {
  2201. if(pEventInfo->pfnEventFilter)
  2202. {
  2203. if(!(pEventInfo->pfnEventFilter)(pRecord,
  2204. pEventInfo->pwszLogName,
  2205. pEventInfo->pwszComponent,
  2206. pEventInfo->pwszSubComponent,
  2207. pEventInfo->pvFilterContext))
  2208. {
  2209. //
  2210. // It fell in our subcomp, but the caller doesnt
  2211. // consider it so
  2212. //
  2213. bRet = FALSE;
  2214. }
  2215. }
  2216. }
  2217. return bRet;
  2218. }