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.

1613 lines
56 KiB

  1. /--------------------------------------------------------------------
  2. // OtherCmds-implementation
  3. // Copyright (C) Microsoft Corporation, 1999
  4. //
  5. // Created by: Louis Thomas (louisth), 2-17-00
  6. //
  7. // Other useful w32tm commands
  8. //
  9. #include "pch.h" // precompiled headers
  10. //--------------------------------------------------------------------
  11. //####################################################################
  12. //##
  13. //## Copied from c run time and modified to be 64bit capable
  14. //##
  15. #include <crt\limits.h>
  16. /* flag values */
  17. #define FL_UNSIGNED 1 /* wcstoul called */
  18. #define FL_NEG 2 /* negative sign found */
  19. #define FL_OVERFLOW 4 /* overflow occured */
  20. #define FL_READDIGIT 8 /* we've read at least one correct digit */
  21. MODULEPRIVATE unsigned __int64 my_wcstoxl (const WCHAR * nptr, WCHAR ** endptr, int ibase, int flags) {
  22. const WCHAR *p;
  23. WCHAR c;
  24. unsigned __int64 number;
  25. unsigned __int64 digval;
  26. unsigned __int64 maxval;
  27. p=nptr; /* p is our scanning pointer */
  28. number=0; /* start with zero */
  29. c=*p++; /* read char */
  30. while (iswspace(c))
  31. c=*p++; /* skip whitespace */
  32. if (c=='-') {
  33. flags|=FL_NEG; /* remember minus sign */
  34. c=*p++;
  35. }
  36. else if (c=='+')
  37. c=*p++; /* skip sign */
  38. if (ibase<0 || ibase==1 || ibase>36) {
  39. /* bad base! */
  40. if (endptr)
  41. /* store beginning of string in endptr */
  42. *endptr=(wchar_t *)nptr;
  43. return 0L; /* return 0 */
  44. }
  45. else if (ibase==0) {
  46. /* determine base free-lance, based on first two chars of
  47. string */
  48. if (c != L'0')
  49. ibase=10;
  50. else if (*p==L'x' || *p==L'X')
  51. ibase=16;
  52. else
  53. ibase=8;
  54. }
  55. if (ibase==16) {
  56. /* we might have 0x in front of number; remove if there */
  57. if (c==L'0' && (*p==L'x' || *p==L'X')) {
  58. ++p;
  59. c=*p++; /* advance past prefix */
  60. }
  61. }
  62. /* if our number exceeds this, we will overflow on multiply */
  63. maxval=_UI64_MAX / ibase;
  64. for (;;) { /* exit in middle of loop */
  65. /* convert c to value */
  66. if (iswdigit(c))
  67. digval=c-L'0';
  68. else if (iswalpha(c))
  69. digval=(TCHAR)CharUpper((LPTSTR)c)-L'A'+10;
  70. else
  71. break;
  72. if (digval>=(unsigned)ibase)
  73. break; /* exit loop if bad digit found */
  74. /* record the fact we have read one digit */
  75. flags|=FL_READDIGIT;
  76. /* we now need to compute number=number*base+digval,
  77. but we need to know if overflow occured. This requires
  78. a tricky pre-check. */
  79. if (number<maxval || (number==maxval &&
  80. (unsigned __int64)digval<=_UI64_MAX%ibase)) {
  81. /* we won't overflow, go ahead and multiply */
  82. number=number*ibase+digval;
  83. }
  84. else {
  85. /* we would have overflowed -- set the overflow flag */
  86. flags|=FL_OVERFLOW;
  87. }
  88. c=*p++; /* read next digit */
  89. }
  90. --p; /* point to place that stopped scan */
  91. if (!(flags&FL_READDIGIT)) {
  92. /* no number there; return 0 and point to beginning of
  93. string */
  94. if (endptr)
  95. /* store beginning of string in endptr later on */
  96. p=nptr;
  97. number=0L; /* return 0 */
  98. }
  99. else if ((flags&FL_OVERFLOW) ||
  100. (!(flags&FL_UNSIGNED) &&
  101. (((flags&FL_NEG) && (number>-_I64_MIN)) ||
  102. (!(flags&FL_NEG) && (number>_I64_MAX)))))
  103. {
  104. /* overflow or signed overflow occurred */
  105. //errno=ERANGE;
  106. if ( flags&FL_UNSIGNED )
  107. number=_UI64_MAX;
  108. else if ( flags&FL_NEG )
  109. number=(unsigned __int64)(-_I64_MIN);
  110. else
  111. number=_I64_MAX;
  112. }
  113. if (endptr != NULL)
  114. /* store pointer to char that stopped the scan */
  115. *endptr=(wchar_t *)p;
  116. if (flags&FL_NEG)
  117. /* negate result if there was a neg sign */
  118. number=(unsigned __int64)(-(__int64)number);
  119. return number; /* done. */
  120. }
  121. MODULEPRIVATE unsigned __int64 wcstouI64(const WCHAR *nptr, WCHAR ** endptr, int ibase) {
  122. return my_wcstoxl(nptr, endptr, ibase, FL_UNSIGNED);
  123. }
  124. //####################################################################
  125. //--------------------------------------------------------------------
  126. HRESULT myHExceptionCode(EXCEPTION_POINTERS * pep) {
  127. HRESULT hr=pep->ExceptionRecord->ExceptionCode;
  128. if (!FAILED(hr)) {
  129. hr=HRESULT_FROM_WIN32(hr);
  130. }
  131. return hr;
  132. }
  133. //--------------------------------------------------------------------
  134. // NOTE: this function is accessed through a hidden option, and does not need to be localized.
  135. void PrintNtpPeerInfo(W32TIME_NTP_PEER_INFO *pnpInfo) {
  136. LPWSTR pwszNULL = L"(null)";
  137. wprintf(L"PEER: %s\n", pnpInfo->wszUniqueName ? pnpInfo->wszUniqueName : pwszNULL);
  138. wprintf(L"ulSize: %d\n", pnpInfo->ulSize);
  139. wprintf(L"ulResolveAttempts: %d\n", pnpInfo->ulResolveAttempts);
  140. wprintf(L"u64TimeRemaining: %I64u\n", pnpInfo->u64TimeRemaining);
  141. wprintf(L"u64LastSuccessfulSync: %I64u\n", pnpInfo->u64LastSuccessfulSync);
  142. wprintf(L"ulLastSyncError: 0x%08X\n", pnpInfo->ulLastSyncError);
  143. wprintf(L"ulLastSyncErrorMsgId: 0x%08X\n", pnpInfo->ulLastSyncErrorMsgId);
  144. wprintf(L"ulValidDataCounter: %d\n", pnpInfo->ulValidDataCounter);
  145. wprintf(L"ulAuthTypeMsgId: 0x%08X\n", pnpInfo->ulAuthTypeMsgId);
  146. wprintf(L"ulMode: %d\n", pnpInfo->ulMode);
  147. wprintf(L"ulStratum: %d\n", pnpInfo->ulStratum);
  148. wprintf(L"ulReachability: %d\n", pnpInfo->ulReachability);
  149. wprintf(L"ulPeerPollInterval: %d\n", pnpInfo->ulPeerPollInterval);
  150. wprintf(L"ulHostPollInterval: %d\n", pnpInfo->ulHostPollInterval);
  151. }
  152. //--------------------------------------------------------------------
  153. // NOTE: this function is accessed through a hidden option, and does not need to be localized.
  154. void PrintNtpProviderData(W32TIME_NTP_PROVIDER_DATA *pNtpProviderData) {
  155. wprintf(L"ulSize: %d, ulError: 0x%08X, ulErrorMsgId: 0x%08X, cPeerInfo: %d\n",
  156. pNtpProviderData->ulSize,
  157. pNtpProviderData->ulError,
  158. pNtpProviderData->ulErrorMsgId,
  159. pNtpProviderData->cPeerInfo
  160. );
  161. for (DWORD dwIndex = 0; dwIndex < pNtpProviderData->cPeerInfo; dwIndex++) {
  162. wprintf(L"\n");
  163. PrintNtpPeerInfo(&(pNtpProviderData->pPeerInfo[dwIndex]));
  164. }
  165. }
  166. //--------------------------------------------------------------------
  167. HRESULT PrintStr(HANDLE hOut, WCHAR * wszBuf)
  168. {
  169. return MyWriteConsole(hOut, wszBuf, wcslen(wszBuf));
  170. }
  171. //--------------------------------------------------------------------
  172. HRESULT Print(HANDLE hOut, WCHAR * wszFormat, ...) {
  173. WCHAR wszBuf[1024];
  174. int nWritten;
  175. va_list vlArgs;
  176. va_start(vlArgs, wszFormat);
  177. nWritten=_vsnwprintf(wszBuf, ARRAYSIZE(wszBuf)-1, wszFormat, vlArgs);
  178. va_end(vlArgs);
  179. wszBuf[ARRAYSIZE(wszBuf)-1]=L'\0';
  180. return PrintStr(hOut, wszBuf);
  181. }
  182. //--------------------------------------------------------------------
  183. MODULEPRIVATE HRESULT PrintNtTimeAsLocalTime(HANDLE hOut, unsigned __int64 qwTime) {
  184. HRESULT hr;
  185. FILETIME ftLocal;
  186. SYSTEMTIME stLocal;
  187. unsigned int nChars;
  188. // must be cleaned up
  189. WCHAR * wszDate=NULL;
  190. WCHAR * wszTime=NULL;
  191. if (!FileTimeToLocalFileTime((FILETIME *)(&qwTime), &ftLocal)) {
  192. _JumpLastError(hr, error, "FileTimeToLocalFileTime");
  193. }
  194. if (!FileTimeToSystemTime(&ftLocal, &stLocal)) {
  195. _JumpLastError(hr, error, "FileTimeToSystemTime");
  196. }
  197. nChars=GetDateFormat(NULL, 0, &stLocal, NULL, NULL, 0);
  198. if (0==nChars) {
  199. _JumpLastError(hr, error, "GetDateFormat");
  200. }
  201. wszDate=(WCHAR *)LocalAlloc(LPTR, nChars*sizeof(WCHAR));
  202. _JumpIfOutOfMemory(hr, error, wszDate);
  203. nChars=GetDateFormat(NULL, 0, &stLocal, NULL, wszDate, nChars);
  204. if (0==nChars) {
  205. _JumpLastError(hr, error, "GetDateFormat");
  206. }
  207. nChars=GetTimeFormat(NULL, 0, &stLocal, NULL, NULL, 0);
  208. if (0==nChars) {
  209. _JumpLastError(hr, error, "GetTimeFormat");
  210. }
  211. wszTime=(WCHAR *)LocalAlloc(LPTR, nChars*sizeof(WCHAR));
  212. _JumpIfOutOfMemory(hr, error, wszTime);
  213. nChars=GetTimeFormat(NULL, 0, &stLocal, NULL, wszTime, nChars);
  214. if (0==nChars) {
  215. _JumpLastError(hr, error, "GetTimeFormat");
  216. }
  217. Print(hOut, L"%s %s (local time)", wszDate, wszTime);
  218. hr=S_OK;
  219. error:
  220. if (NULL!=wszDate) {
  221. LocalFree(wszDate);
  222. }
  223. if (NULL!=wszTime) {
  224. LocalFree(wszTime);
  225. }
  226. return hr;
  227. }
  228. //--------------------------------------------------------------------
  229. void PrintNtTimePeriod(HANDLE hOut, NtTimePeriod tp) {
  230. Print(hOut, L"%02I64u.%07I64us", tp.qw/10000000,tp.qw%10000000);
  231. }
  232. //--------------------------------------------------------------------
  233. void PrintNtTimeOffset(HANDLE hOut, NtTimeOffset to) {
  234. NtTimePeriod tp;
  235. if (to.qw<0) {
  236. PrintStr(hOut, L"-");
  237. tp.qw=(unsigned __int64)-to.qw;
  238. } else {
  239. PrintStr(hOut, L"+");
  240. tp.qw=(unsigned __int64)to.qw;
  241. }
  242. PrintNtTimePeriod(hOut, tp);
  243. }
  244. //####################################################################
  245. //--------------------------------------------------------------------
  246. void PrintHelpOtherCmds(void) {
  247. UINT idsText[] = {
  248. IDS_W32TM_OTHERCMDHELP_LINE1, IDS_W32TM_OTHERCMDHELP_LINE2,
  249. IDS_W32TM_OTHERCMDHELP_LINE3, IDS_W32TM_OTHERCMDHELP_LINE4,
  250. IDS_W32TM_OTHERCMDHELP_LINE5, IDS_W32TM_OTHERCMDHELP_LINE6,
  251. IDS_W32TM_OTHERCMDHELP_LINE7, IDS_W32TM_OTHERCMDHELP_LINE8,
  252. IDS_W32TM_OTHERCMDHELP_LINE9, IDS_W32TM_OTHERCMDHELP_LINE10,
  253. IDS_W32TM_OTHERCMDHELP_LINE11, IDS_W32TM_OTHERCMDHELP_LINE12,
  254. IDS_W32TM_OTHERCMDHELP_LINE13, IDS_W32TM_OTHERCMDHELP_LINE14,
  255. IDS_W32TM_OTHERCMDHELP_LINE15, IDS_W32TM_OTHERCMDHELP_LINE16,
  256. IDS_W32TM_OTHERCMDHELP_LINE17, IDS_W32TM_OTHERCMDHELP_LINE18,
  257. IDS_W32TM_OTHERCMDHELP_LINE19, IDS_W32TM_OTHERCMDHELP_LINE20,
  258. IDS_W32TM_OTHERCMDHELP_LINE21, IDS_W32TM_OTHERCMDHELP_LINE22,
  259. IDS_W32TM_OTHERCMDHELP_LINE23, IDS_W32TM_OTHERCMDHELP_LINE24,
  260. IDS_W32TM_OTHERCMDHELP_LINE25, IDS_W32TM_OTHERCMDHELP_LINE26,
  261. IDS_W32TM_OTHERCMDHELP_LINE27, IDS_W32TM_OTHERCMDHELP_LINE28,
  262. IDS_W32TM_OTHERCMDHELP_LINE29, IDS_W32TM_OTHERCMDHELP_LINE30,
  263. IDS_W32TM_OTHERCMDHELP_LINE31, IDS_W32TM_OTHERCMDHELP_LINE32,
  264. IDS_W32TM_OTHERCMDHELP_LINE33, IDS_W32TM_OTHERCMDHELP_LINE34,
  265. IDS_W32TM_OTHERCMDHELP_LINE35, IDS_W32TM_OTHERCMDHELP_LINE36,
  266. IDS_W32TM_OTHERCMDHELP_LINE37, IDS_W32TM_OTHERCMDHELP_LINE38,
  267. IDS_W32TM_OTHERCMDHELP_LINE39, IDS_W32TM_OTHERCMDHELP_LINE40,
  268. IDS_W32TM_OTHERCMDHELP_LINE41, IDS_W32TM_OTHERCMDHELP_LINE42,
  269. IDS_W32TM_OTHERCMDHELP_LINE43, IDS_W32TM_OTHERCMDHELP_LINE44,
  270. IDS_W32TM_OTHERCMDHELP_LINE45, IDS_W32TM_OTHERCMDHELP_LINE46,
  271. IDS_W32TM_OTHERCMDHELP_LINE47, IDS_W32TM_OTHERCMDHELP_LINE48,
  272. IDS_W32TM_OTHERCMDHELP_LINE49, IDS_W32TM_OTHERCMDHELP_LINE50,
  273. IDS_W32TM_OTHERCMDHELP_LINE51, IDS_W32TM_OTHERCMDHELP_LINE52,
  274. IDS_W32TM_OTHERCMDHELP_LINE53, IDS_W32TM_OTHERCMDHELP_LINE54,
  275. IDS_W32TM_OTHERCMDHELP_LINE55, IDS_W32TM_OTHERCMDHELP_LINE56,
  276. IDS_W32TM_OTHERCMDHELP_LINE57, IDS_W32TM_OTHERCMDHELP_LINE58,
  277. IDS_W32TM_OTHERCMDHELP_LINE59, IDS_W32TM_OTHERCMDHELP_LINE60
  278. };
  279. for (int n=0; n<ARRAYSIZE(idsText); n++) {
  280. LocalizedWPrintf(idsText[n]);
  281. }
  282. }
  283. //--------------------------------------------------------------------
  284. HRESULT PrintNtte(CmdArgs * pca) {
  285. HRESULT hr;
  286. unsigned __int64 qwTime;
  287. HANDLE hOut;
  288. // must be cleaned up
  289. WCHAR * wszDate=NULL;
  290. WCHAR * wszTime=NULL;
  291. if (pca->nNextArg!=pca->nArgs-1) {
  292. if (pca->nNextArg==pca->nArgs) {
  293. LocalizedWPrintfCR(IDS_W32TM_ERRORGENERAL_MISSING_PARAM);
  294. } else {
  295. LocalizedWPrintfCR(IDS_W32TM_ERRORGENERAL_TOO_MANY_PARAMS);
  296. }
  297. hr=E_INVALIDARG;
  298. _JumpError(hr, error, "(command line parsing)");
  299. }
  300. qwTime=wcstouI64(pca->rgwszArgs[pca->nNextArg], NULL, 0);
  301. {
  302. unsigned __int64 qwTemp=qwTime;
  303. DWORD dwNanoSecs=(DWORD)(qwTemp%10000000);
  304. qwTemp/=10000000;
  305. DWORD dwSecs=(DWORD)(qwTemp%60);
  306. qwTemp/=60;
  307. DWORD dwMins=(DWORD)(qwTemp%60);
  308. qwTemp/=60;
  309. DWORD dwHours=(DWORD)(qwTemp%24);
  310. DWORD dwDays=(DWORD)(qwTemp/24);
  311. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, IDS_W32TM_NTTE, dwDays, dwHours, dwMins, dwSecs, dwNanoSecs);
  312. }
  313. hOut=GetStdHandle(STD_OUTPUT_HANDLE);
  314. if (INVALID_HANDLE_VALUE==hOut) {
  315. _JumpLastError(hr, error, "GetStdHandle");
  316. }
  317. hr=PrintNtTimeAsLocalTime(hOut, qwTime);
  318. if (FAILED(hr)) {
  319. if (HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)==hr) {
  320. LocalizedWPrintfCR(IDS_W32TM_ERRORGENERAL_INVALID_LOCALTIME);
  321. } else {
  322. _JumpError(hr, error, "PrintNtTimeAsLocalTime");
  323. }
  324. }
  325. wprintf(L"\n");
  326. hr=S_OK;
  327. error:
  328. if (NULL!=wszDate) {
  329. LocalFree(wszDate);
  330. }
  331. if (NULL!=wszTime) {
  332. LocalFree(wszTime);
  333. }
  334. return hr;
  335. }
  336. //--------------------------------------------------------------------
  337. HRESULT PrintNtpte(CmdArgs * pca) {
  338. HRESULT hr;
  339. unsigned __int64 qwTime;
  340. HANDLE hOut;
  341. // must be cleaned up
  342. WCHAR * wszDate=NULL;
  343. WCHAR * wszTime=NULL;
  344. if (pca->nNextArg!=pca->nArgs-1) {
  345. if (pca->nNextArg==pca->nArgs) {
  346. LocalizedWPrintfCR(IDS_W32TM_ERRORGENERAL_MISSING_PARAM);
  347. } else {
  348. LocalizedWPrintfCR(IDS_W32TM_ERRORGENERAL_TOO_MANY_PARAMS);
  349. }
  350. hr=E_INVALIDARG;
  351. _JumpError(hr, error, "(command line parsing)");
  352. }
  353. qwTime=wcstouI64(pca->rgwszArgs[pca->nNextArg], NULL, 0);
  354. {
  355. NtpTimeEpoch teNtp={qwTime};
  356. qwTime=NtTimeEpochFromNtpTimeEpoch(teNtp).qw;
  357. unsigned __int64 qwTemp=qwTime;
  358. DWORD dwNanoSecs=(DWORD)(qwTemp%10000000);
  359. qwTemp/=10000000;
  360. DWORD dwSecs=(DWORD)(qwTemp%60);
  361. qwTemp/=60;
  362. DWORD dwMins=(DWORD)(qwTemp%60);
  363. qwTemp/=60;
  364. DWORD dwHours=(DWORD)(qwTemp%24);
  365. DWORD dwDays=(DWORD)(qwTemp/24);
  366. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, IDS_W32TM_NTPTE, qwTime, dwDays, dwHours, dwMins, dwSecs, dwNanoSecs);
  367. }
  368. hOut=GetStdHandle(STD_OUTPUT_HANDLE);
  369. if (INVALID_HANDLE_VALUE==hOut) {
  370. _JumpLastError(hr, error, "GetStdHandle")
  371. }
  372. hr=PrintNtTimeAsLocalTime(hOut, qwTime);
  373. if (FAILED(hr)) {
  374. if (HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)==hr) {
  375. LocalizedWPrintf(IDS_W32TM_ERRORGENERAL_INVALID_LOCALTIME);
  376. } else {
  377. _JumpError(hr, error, "PrintNtTimeAsLocalTime");
  378. }
  379. }
  380. wprintf(L"\n");
  381. hr=S_OK;
  382. error:
  383. if (NULL!=wszDate) {
  384. LocalFree(wszDate);
  385. }
  386. if (NULL!=wszTime) {
  387. LocalFree(wszTime);
  388. }
  389. return hr;
  390. }
  391. //--------------------------------------------------------------------
  392. // NOTE: this function is accessed through a hidden option, and does not need to be localized.
  393. HRESULT SysExpr(CmdArgs * pca) {
  394. HRESULT hr;
  395. unsigned __int64 qwExprDate;
  396. HANDLE hOut;
  397. hr=VerifyAllArgsUsed(pca);
  398. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  399. hOut=GetStdHandle(STD_OUTPUT_HANDLE);
  400. if (INVALID_HANDLE_VALUE==hOut) {
  401. _JumpLastError(hr, error, "GetStdHandle")
  402. }
  403. GetSysExpirationDate(&qwExprDate);
  404. wprintf(L"0x%016I64X - ", qwExprDate);
  405. if (0==qwExprDate) {
  406. wprintf(L"no expiration date\n");
  407. } else {
  408. hr=PrintNtTimeAsLocalTime(hOut, qwExprDate);
  409. _JumpIfError(hr, error, "PrintNtTimeAsLocalTime")
  410. wprintf(L"\n");
  411. }
  412. hr=S_OK;
  413. error:
  414. return hr;
  415. }
  416. //--------------------------------------------------------------------
  417. HRESULT ResyncCommand(CmdArgs * pca) {
  418. HANDLE hTimeSlipEvent = NULL;
  419. HRESULT hr;
  420. WCHAR * wszComputer=NULL;
  421. WCHAR * wszComputerDisplay;
  422. bool bUseDefaultErrorPrinting = false;
  423. bool bHard=true;
  424. bool bNoWait=false;
  425. bool bRediscover=false;
  426. unsigned int nArgID;
  427. DWORD dwResult;
  428. DWORD dwSyncFlags=0;
  429. // must be cleaned up
  430. WCHAR * wszError=NULL;
  431. // find out what computer to resync
  432. if (FindArg(pca, L"computer", &wszComputer, &nArgID)) {
  433. MarkArgUsed(pca, nArgID);
  434. }
  435. wszComputerDisplay=wszComputer;
  436. if (NULL==wszComputerDisplay) {
  437. wszComputerDisplay=L"local computer";
  438. }
  439. // find out if we need to use the w32tm named timeslip event to resync
  440. if (FindArg(pca, L"event", NULL, &nArgID)) {
  441. MarkArgUsed(pca, nArgID);
  442. hr=VerifyAllArgsUsed(pca);
  443. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  444. hTimeSlipEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, W32TIME_NAMED_EVENT_SYSTIME_NOT_CORRECT);
  445. if (NULL == hTimeSlipEvent) {
  446. bUseDefaultErrorPrinting = true;
  447. _JumpLastError(hr, error, "OpenEvent");
  448. }
  449. if (!SetEvent(hTimeSlipEvent)) {
  450. bUseDefaultErrorPrinting = true;
  451. _JumpLastError(hr, error, "SetEvent");
  452. }
  453. } else {
  454. // find out if we need to do a soft resync
  455. if (FindArg(pca, L"soft", NULL, &nArgID)) {
  456. MarkArgUsed(pca, nArgID);
  457. dwSyncFlags = TimeSyncFlag_SoftResync;
  458. } else if (FindArg(pca, L"update", NULL, &nArgID)) {
  459. MarkArgUsed(pca, nArgID);
  460. dwSyncFlags = TimeSyncFlag_UpdateAndResync;
  461. } else if (FindArg(pca, L"rediscover", NULL, &nArgID)) {
  462. // find out if we need to do a rediscover
  463. MarkArgUsed(pca, nArgID);
  464. dwSyncFlags = TimeSyncFlag_Rediscover;
  465. } else {
  466. dwSyncFlags = TimeSyncFlag_HardResync;
  467. }
  468. // find out if we don't want to wait
  469. if (FindArg(pca, L"nowait", NULL, &nArgID)) {
  470. MarkArgUsed(pca, nArgID);
  471. bNoWait=true;
  472. }
  473. hr=VerifyAllArgsUsed(pca);
  474. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  475. if (bRediscover && !bHard) {
  476. LocalizedWPrintfCR(IDS_W32TM_WARN_IGNORE_SOFT);
  477. }
  478. LocalizedWPrintf2(IDS_W32TM_STATUS_SENDING_RESYNC_TO, L" %s...\n", wszComputerDisplay);
  479. dwResult=W32TimeSyncNow(wszComputer, !bNoWait, TimeSyncFlag_ReturnResult | dwSyncFlags);
  480. if (ResyncResult_Success==dwResult) {
  481. LocalizedWPrintfCR(IDS_W32TM_ERRORGENERAL_COMMAND_SUCCESSFUL);
  482. } else if (ResyncResult_NoData==dwResult) {
  483. LocalizedWPrintfCR(IDS_W32TM_ERRORRESYNC_NO_TIME_DATA);
  484. } else if (ResyncResult_StaleData==dwResult) {
  485. LocalizedWPrintfCR(IDS_W32TM_ERRORRESYNC_STALE_DATA);
  486. } else if (ResyncResult_Shutdown==dwResult) {
  487. LocalizedWPrintfCR(IDS_W32TM_ERRORRESYNC_SHUTTING_DOWN);
  488. } else if (ResyncResult_ChangeTooBig==dwResult) {
  489. LocalizedWPrintfCR(IDS_W32TM_ERRORRESYNC_CHANGE_TOO_BIG);
  490. } else {
  491. bUseDefaultErrorPrinting = true;
  492. hr = HRESULT_FROM_WIN32(dwResult);
  493. _JumpError(hr, error, "W32TimeSyncNow");
  494. }
  495. }
  496. hr=S_OK;
  497. error:
  498. if (FAILED(hr)) {
  499. HRESULT hr2 = GetSystemErrorString(hr, &wszError);
  500. _IgnoreIfError(hr2, "GetSystemErrorString");
  501. if (SUCCEEDED(hr2)) {
  502. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  503. }
  504. }
  505. if (NULL!=hTimeSlipEvent) {
  506. CloseHandle(hTimeSlipEvent);
  507. }
  508. if (NULL!=wszError) {
  509. LocalFree(wszError);
  510. }
  511. return hr;
  512. }
  513. //--------------------------------------------------------------------
  514. HRESULT Stripchart(CmdArgs * pca) {
  515. HRESULT hr;
  516. WCHAR * wszParam;
  517. WCHAR * wszComputer;
  518. bool bDataOnly=false;
  519. unsigned int nArgID;
  520. unsigned int nIpAddrs;
  521. TIME_ZONE_INFORMATION timezoneinfo;
  522. signed __int64 nFullTzBias;
  523. DWORD dwTimeZoneMode;
  524. DWORD dwSleepSeconds;
  525. HANDLE hOut;
  526. bool bDontRunForever=false;
  527. unsigned int nSamples;
  528. NtTimeEpoch teNow;
  529. // must be cleaned up
  530. WCHAR * wszError=NULL;
  531. bool bSocketLayerOpened=false;
  532. in_addr * rgiaLocalIpAddrs=NULL;
  533. in_addr * rgiaRemoteIpAddrs=NULL;
  534. // find out what computer to watch
  535. if (FindArg(pca, L"computer", &wszComputer, &nArgID)) {
  536. MarkArgUsed(pca, nArgID);
  537. } else {
  538. LocalizedWPrintfCR(IDS_W32TM_ERRORPARAMETER_COMPUTER_MISSING);
  539. hr=E_INVALIDARG;
  540. _JumpError(hr, error, "command line parsing");
  541. }
  542. // find out how often to watch
  543. if (FindArg(pca, L"period", &wszParam, &nArgID)) {
  544. MarkArgUsed(pca, nArgID);
  545. dwSleepSeconds=wcstoul(wszParam, NULL, 0);
  546. if (dwSleepSeconds<1) {
  547. dwSleepSeconds=1;
  548. }
  549. } else {
  550. dwSleepSeconds=2;
  551. }
  552. // find out if we want a limited number of samples
  553. if (FindArg(pca, L"samples", &wszParam, &nArgID)) {
  554. MarkArgUsed(pca, nArgID);
  555. bDontRunForever=true;
  556. nSamples=wcstoul(wszParam, NULL, 0);
  557. }
  558. // find out if we only want to dump data
  559. if (FindArg(pca, L"dataonly", NULL, &nArgID)) {
  560. MarkArgUsed(pca, nArgID);
  561. bDataOnly=true;
  562. }
  563. // redirect to file handled via stdout
  564. hOut=GetStdHandle(STD_OUTPUT_HANDLE);
  565. if (INVALID_HANDLE_VALUE==hOut) {
  566. _JumpLastError(hr, error, "GetStdHandle")
  567. }
  568. hr=VerifyAllArgsUsed(pca);
  569. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  570. dwTimeZoneMode=GetTimeZoneInformation(&timezoneinfo);
  571. if (TIME_ZONE_ID_INVALID==dwTimeZoneMode) {
  572. _JumpLastError(hr, error, "GetTimeZoneInformation");
  573. } else if (TIME_ZONE_ID_DAYLIGHT==dwTimeZoneMode) {
  574. nFullTzBias=(signed __int64)(timezoneinfo.Bias+timezoneinfo.DaylightBias);
  575. } else {
  576. nFullTzBias=(signed __int64)(timezoneinfo.Bias+timezoneinfo.StandardBias);
  577. }
  578. nFullTzBias*=600000000; // convert to from minutes to 10^-7s
  579. hr=OpenSocketLayer();
  580. _JumpIfError(hr, error, "OpenSocketLayer");
  581. bSocketLayerOpened=true;
  582. hr=MyGetIpAddrs(wszComputer, &rgiaLocalIpAddrs, &rgiaRemoteIpAddrs, &nIpAddrs, NULL);
  583. _JumpIfError(hr, error, "MyGetIpAddrs");
  584. // write out who we are tracking
  585. Print(hOut, L"Tracking %s [%u.%u.%u.%u].\n",
  586. wszComputer,
  587. rgiaRemoteIpAddrs[0].S_un.S_un_b.s_b1, rgiaRemoteIpAddrs[0].S_un.S_un_b.s_b2,
  588. rgiaRemoteIpAddrs[0].S_un.S_un_b.s_b3, rgiaRemoteIpAddrs[0].S_un.S_un_b.s_b4);
  589. if (bDontRunForever) {
  590. Print(hOut, L"Collecting %u samples.\n", nSamples);
  591. }
  592. // Write out the current time in full, since we will be using abbreviations later.
  593. PrintStr(hOut, L"The current time is ");
  594. AccurateGetSystemTime(&teNow.qw);
  595. PrintNtTimeAsLocalTime(hOut, teNow.qw);
  596. PrintStr(hOut, L".\n");
  597. while (false==bDontRunForever || nSamples>0) {
  598. const DWORD c_dwTimeout=1000;
  599. NtpPacket npPacket;
  600. NtTimeEpoch teDestinationTimestamp;
  601. DWORD dwSecs;
  602. DWORD dwMins;
  603. DWORD dwHours;
  604. signed int nMsMin=-10000;
  605. signed int nMsMax=10000;
  606. unsigned int nGraphWidth=55;
  607. AccurateGetSystemTime(&teNow.qw);
  608. teNow.qw-=nFullTzBias;
  609. teNow.qw/=10000000;
  610. dwSecs=(DWORD)(teNow.qw%60);
  611. teNow.qw/=60;
  612. dwMins=(DWORD)(teNow.qw%60);
  613. teNow.qw/=60;
  614. dwHours=(DWORD)(teNow.qw%24);
  615. if (!bDataOnly) {
  616. Print(hOut, L"%02u:%02u:%02u ", dwHours, dwMins, dwSecs);
  617. } else {
  618. Print(hOut, L"%02u:%02u:%02u, ", dwHours, dwMins, dwSecs);
  619. }
  620. hr=MyNtpPing(&(rgiaRemoteIpAddrs[0]), c_dwTimeout, &npPacket, &teDestinationTimestamp);
  621. if (FAILED(hr)) {
  622. Print(hOut, L"error: 0x%08X", hr);
  623. } else {
  624. // calculate the offset
  625. NtTimeEpoch teOriginateTimestamp=NtTimeEpochFromNtpTimeEpoch(npPacket.teOriginateTimestamp);
  626. NtTimeEpoch teReceiveTimestamp=NtTimeEpochFromNtpTimeEpoch(npPacket.teReceiveTimestamp);
  627. NtTimeEpoch teTransmitTimestamp=NtTimeEpochFromNtpTimeEpoch(npPacket.teTransmitTimestamp);
  628. NtTimeOffset toLocalClockOffset=
  629. (teReceiveTimestamp-teOriginateTimestamp)
  630. + (teTransmitTimestamp-teDestinationTimestamp);
  631. toLocalClockOffset/=2;
  632. // calculate the delay
  633. NtTimeOffset toRoundtripDelay=
  634. (teDestinationTimestamp-teOriginateTimestamp)
  635. - (teTransmitTimestamp-teReceiveTimestamp);
  636. if (!bDataOnly) {
  637. PrintStr(hOut, L"d:");
  638. PrintNtTimeOffset(hOut, toRoundtripDelay);
  639. PrintStr(hOut, L" o:");
  640. PrintNtTimeOffset(hOut, toLocalClockOffset);
  641. } else {
  642. PrintNtTimeOffset(hOut, toLocalClockOffset);
  643. }
  644. // draw graph
  645. if (!bDataOnly) {
  646. unsigned int nSize=nMsMax-nMsMin+1;
  647. double dRatio=((double)nGraphWidth)/nSize;
  648. signed int nPoint=(signed int)(toLocalClockOffset.qw/10000);
  649. bool bOutOfRange=false;
  650. if (nPoint>nMsMax) {
  651. nPoint=nMsMax;
  652. bOutOfRange=true;
  653. } else if (nPoint<nMsMin) {
  654. nPoint=nMsMin;
  655. bOutOfRange=true;
  656. }
  657. unsigned int nLeftOffset=(unsigned int)((nPoint-nMsMin)*dRatio);
  658. unsigned int nZeroOffset=(unsigned int)((0-nMsMin)*dRatio);
  659. PrintStr(hOut, L" [");
  660. unsigned int nIndex;
  661. for (nIndex=0; nIndex<nGraphWidth; nIndex++) {
  662. if (nIndex==nLeftOffset) {
  663. if (bOutOfRange) {
  664. PrintStr(hOut, L"@");
  665. } else {
  666. PrintStr(hOut, L"*");
  667. }
  668. } else if (nIndex==nZeroOffset) {
  669. PrintStr(hOut, L"|");
  670. } else {
  671. PrintStr(hOut, L" ");
  672. }
  673. }
  674. PrintStr(hOut, L"]");
  675. } // <- end drawing graph
  676. } // <- end if sample received
  677. PrintStr(hOut, L"\n");
  678. nSamples--;
  679. if (0!=nSamples) {
  680. Sleep(dwSleepSeconds*1000);
  681. }
  682. } // <- end sample collection loop
  683. hr=S_OK;
  684. error:
  685. if (NULL!=rgiaLocalIpAddrs) {
  686. LocalFree(rgiaLocalIpAddrs);
  687. }
  688. if (NULL!=rgiaRemoteIpAddrs) {
  689. LocalFree(rgiaRemoteIpAddrs);
  690. }
  691. if (bSocketLayerOpened) {
  692. HRESULT hr2=CloseSocketLayer();
  693. _TeardownError(hr, hr2, "CloseSocketLayer");
  694. }
  695. if (FAILED(hr)) {
  696. WCHAR * wszError;
  697. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  698. if (FAILED(hr2)) {
  699. _IgnoreError(hr2, "GetSystemErrorString");
  700. } else {
  701. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  702. LocalFree(wszError);
  703. }
  704. }
  705. return hr;
  706. }
  707. //--------------------------------------------------------------------
  708. HRESULT Config(CmdArgs * pca) {
  709. HRESULT hr;
  710. DWORD dwRetval;
  711. WCHAR * wszParam;
  712. WCHAR * wszComputer;
  713. unsigned int nArgID;
  714. bool bManualPeerList=false;
  715. bool bUpdate=false;
  716. bool bSyncFromFlags=false;
  717. bool bLocalClockDispersion=false;
  718. unsigned int nManualPeerListLenBytes;
  719. DWORD dwSyncFromFlags;
  720. DWORD dwLocalClockDispersion;
  721. // must be cleaned up
  722. WCHAR * mwszManualPeerList=NULL;
  723. HKEY hkLMRemote=NULL;
  724. HKEY hkW32TimeConfig=NULL;
  725. HKEY hkW32TimeParameters=NULL;
  726. SC_HANDLE hSCM=NULL;
  727. SC_HANDLE hTimeService=NULL;
  728. // find out what computer to talk to
  729. if (FindArg(pca, L"computer", &wszComputer, &nArgID)) {
  730. MarkArgUsed(pca, nArgID);
  731. } else {
  732. // modifying local computer
  733. wszComputer=NULL;
  734. }
  735. // find out if we want to notify the service
  736. if (FindArg(pca, L"update", NULL, &nArgID)) {
  737. MarkArgUsed(pca, nArgID);
  738. bUpdate=true;
  739. }
  740. // see if they want to change the manual peer list
  741. if (FindArg(pca, L"manualpeerlist", &wszParam, &nArgID)) {
  742. MarkArgUsed(pca, nArgID);
  743. nManualPeerListLenBytes=(wcslen(wszParam)+1)*sizeof(WCHAR);
  744. mwszManualPeerList=(WCHAR *)LocalAlloc(LPTR, nManualPeerListLenBytes);
  745. _JumpIfOutOfMemory(hr, error, mwszManualPeerList);
  746. wcscpy(mwszManualPeerList, wszParam);
  747. bManualPeerList=true;
  748. }
  749. // see if they want to change the syncfromflags
  750. if (FindArg(pca, L"syncfromflags", &wszParam, &nArgID)) {
  751. MarkArgUsed(pca, nArgID);
  752. // find keywords in the string
  753. dwSyncFromFlags=0;
  754. WCHAR * wszKeyword=wszParam;
  755. bool bLastKeyword=false;
  756. while (false==bLastKeyword) {
  757. WCHAR * wszNext=wcschr(wszKeyword, L',');
  758. if (NULL==wszNext) {
  759. bLastKeyword=true;
  760. } else {
  761. wszNext[0]=L'\0';
  762. wszNext++;
  763. }
  764. if (L'\0'==wszKeyword[0]) {
  765. // 'empty' keyword - no changes, but can be used to sync from nowhere.
  766. } else if (0==_wcsicmp(L"manual", wszKeyword)) {
  767. dwSyncFromFlags|=NCSF_ManualPeerList;
  768. } else if (0==_wcsicmp(L"domhier", wszKeyword)) {
  769. dwSyncFromFlags|=NCSF_DomainHierarchy;
  770. } else {
  771. LocalizedWPrintf2(IDS_W32TM_ERRORPARAMETER_UNKNOWN_PARAMETER_SYNCFROMFLAGS, L" '%s'.\n", wszKeyword);
  772. hr=E_INVALIDARG;
  773. _JumpError(hr, error, "command line parsing");
  774. }
  775. wszKeyword=wszNext;
  776. }
  777. bSyncFromFlags=true;
  778. }
  779. // see if they want to change the local clock dispersion
  780. if (FindArg(pca, L"localclockdispersion", &wszParam, &nArgID)) {
  781. MarkArgUsed(pca, nArgID);
  782. dwLocalClockDispersion=wcstoul(wszParam, NULL, 0);
  783. bLocalClockDispersion=true;
  784. }
  785. hr=VerifyAllArgsUsed(pca);
  786. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  787. if (!bManualPeerList && !bSyncFromFlags && !bUpdate && !bLocalClockDispersion) {
  788. LocalizedWPrintfCR(IDS_W32TM_ERRORCONFIG_NO_CHANGE_SPECIFIED);
  789. hr=E_INVALIDARG;
  790. _JumpError(hr, error, "command line parsing");
  791. }
  792. // make registry changes
  793. if (bManualPeerList || bSyncFromFlags || bLocalClockDispersion) {
  794. // open the key
  795. dwRetval=RegConnectRegistry(wszComputer, HKEY_LOCAL_MACHINE, &hkLMRemote);
  796. if (ERROR_SUCCESS!=dwRetval) {
  797. hr=HRESULT_FROM_WIN32(dwRetval);
  798. _JumpError(hr, error, "RegConnectRegistry");
  799. }
  800. // set "w32time\parameters" reg values
  801. if (bManualPeerList || bSyncFromFlags) {
  802. dwRetval=RegOpenKey(hkLMRemote, wszW32TimeRegKeyParameters, &hkW32TimeParameters);
  803. if (ERROR_SUCCESS!=dwRetval) {
  804. hr=HRESULT_FROM_WIN32(dwRetval);
  805. _JumpError(hr, error, "RegOpenKey");
  806. }
  807. if (bManualPeerList) {
  808. dwRetval=RegSetValueEx(hkW32TimeParameters, wszW32TimeRegValueNtpServer, 0, REG_SZ, (BYTE *)mwszManualPeerList, nManualPeerListLenBytes);
  809. if (ERROR_SUCCESS!=dwRetval) {
  810. hr=HRESULT_FROM_WIN32(dwRetval);
  811. _JumpError(hr, error, "RegSetValueEx");
  812. }
  813. }
  814. if (bSyncFromFlags) {
  815. LPWSTR pwszType;
  816. switch (dwSyncFromFlags) {
  817. case NCSF_NoSync: pwszType = W32TM_Type_NoSync; break;
  818. case NCSF_ManualPeerList: pwszType = W32TM_Type_NTP; break;
  819. case NCSF_DomainHierarchy: pwszType = W32TM_Type_NT5DS; break;
  820. case NCSF_ManualAndDomhier: pwszType = W32TM_Type_AllSync; break;
  821. default:
  822. hr = E_NOTIMPL;
  823. _JumpError(hr, error, "SyncFromFlags not supported.");
  824. }
  825. dwRetval=RegSetValueEx(hkW32TimeParameters, wszW32TimeRegValueType, 0, REG_SZ, (BYTE *)pwszType, (wcslen(pwszType)+1) * sizeof(WCHAR));
  826. if (ERROR_SUCCESS!=dwRetval) {
  827. hr=HRESULT_FROM_WIN32(dwRetval);
  828. _JumpError(hr, error, "RegSetValueEx");
  829. }
  830. }
  831. }
  832. if (bLocalClockDispersion) {
  833. dwRetval=RegOpenKey(hkLMRemote, wszW32TimeRegKeyConfig, &hkW32TimeConfig);
  834. if (ERROR_SUCCESS!=dwRetval) {
  835. hr=HRESULT_FROM_WIN32(dwRetval);
  836. _JumpError(hr, error, "RegOpenKey");
  837. }
  838. dwRetval=RegSetValueEx(hkW32TimeConfig, wszW32TimeRegValueLocalClockDispersion, 0, REG_DWORD, (BYTE *)&dwLocalClockDispersion, sizeof(dwLocalClockDispersion));
  839. if (ERROR_SUCCESS!=dwRetval) {
  840. hr=HRESULT_FROM_WIN32(dwRetval);
  841. _JumpError(hr, error, "RegSetValueEx");
  842. }
  843. }
  844. }
  845. // send service message
  846. if (bUpdate) {
  847. SERVICE_STATUS servicestatus;
  848. hSCM=OpenSCManager(wszComputer, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
  849. if (NULL==hSCM) {
  850. _JumpLastError(hr, error, "OpenSCManager");
  851. }
  852. hTimeService=OpenService(hSCM, L"w32time", SERVICE_PAUSE_CONTINUE);
  853. if (NULL==hTimeService) {
  854. _JumpLastError(hr, error, "OpenService");
  855. }
  856. if (!ControlService(hTimeService, SERVICE_CONTROL_PARAMCHANGE, &servicestatus)) {
  857. _JumpLastError(hr, error, "ControlService");
  858. }
  859. }
  860. hr=S_OK;
  861. error:
  862. if (NULL!=mwszManualPeerList) {
  863. LocalFree(mwszManualPeerList);
  864. }
  865. if (NULL!=hkW32TimeConfig) {
  866. RegCloseKey(hkW32TimeConfig);
  867. }
  868. if (NULL!=hkW32TimeParameters) {
  869. RegCloseKey(hkW32TimeParameters);
  870. }
  871. if (NULL!=hkLMRemote) {
  872. RegCloseKey(hkLMRemote);
  873. }
  874. if (NULL!=hTimeService) {
  875. CloseServiceHandle(hTimeService);
  876. }
  877. if (NULL!=hSCM) {
  878. CloseServiceHandle(hSCM);
  879. }
  880. if (FAILED(hr) && E_INVALIDARG!=hr) {
  881. WCHAR * wszError;
  882. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  883. if (FAILED(hr2)) {
  884. _IgnoreError(hr2, "GetSystemErrorString");
  885. } else {
  886. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  887. LocalFree(wszError);
  888. }
  889. } else if (S_OK==hr) {
  890. LocalizedWPrintfCR(IDS_W32TM_ERRORGENERAL_COMMAND_SUCCESSFUL);
  891. }
  892. return hr;
  893. }
  894. //--------------------------------------------------------------------
  895. // NOTE: this function is accessed through a hidden option, and does not need to be localized.
  896. HRESULT TestInterface(CmdArgs * pca) {
  897. HRESULT hr;
  898. WCHAR * wszComputer=NULL;
  899. WCHAR * wszComputerDisplay;
  900. unsigned int nArgID;
  901. DWORD dwResult;
  902. unsigned long ulBits;
  903. void (* pfnW32TimeVerifyJoinConfig)(void);
  904. void (* pfnW32TimeVerifyUnjoinConfig)(void);
  905. // must be cleaned up
  906. WCHAR * wszError=NULL;
  907. HMODULE hmW32Time=NULL;
  908. // check for gnsb (get netlogon service bits)
  909. if (true==CheckNextArg(pca, L"gnsb", NULL)) {
  910. // find out what computer to resync
  911. if (FindArg(pca, L"computer", &wszComputer, &nArgID)) {
  912. MarkArgUsed(pca, nArgID);
  913. }
  914. wszComputerDisplay=wszComputer;
  915. if (NULL==wszComputerDisplay) {
  916. wszComputerDisplay=L"local computer";
  917. }
  918. hr=VerifyAllArgsUsed(pca);
  919. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  920. LocalizedWPrintf2(IDS_W32TM_STATUS_CALLING_GETNETLOGONBITS_ON, L" %s.\n", wszComputerDisplay);
  921. dwResult=W32TimeGetNetlogonServiceBits(wszComputer, &ulBits);
  922. if (S_OK==dwResult) {
  923. wprintf(L"Bits: 0x%08X\n", ulBits);
  924. } else {
  925. hr=GetSystemErrorString(HRESULT_FROM_WIN32(dwResult), &wszError);
  926. _JumpIfError(hr, error, "GetSystemErrorString");
  927. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  928. }
  929. // check for vjc (verify join config)
  930. } else if (true==CheckNextArg(pca, L"vjc", NULL)) {
  931. hr=VerifyAllArgsUsed(pca);
  932. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  933. LocalizedWPrintfCR(IDS_W32TM_STATUS_CALLING_JOINCONFIG);
  934. hmW32Time=LoadLibrary(wszDLLNAME);
  935. if (NULL==hmW32Time) {
  936. _JumpLastError(hr, vjcerror, "LoadLibrary");
  937. }
  938. pfnW32TimeVerifyJoinConfig=(void (*)(void))GetProcAddress(hmW32Time, "W32TimeVerifyJoinConfig");
  939. if (NULL==pfnW32TimeVerifyJoinConfig) {
  940. _JumpLastErrorStr(hr, vjcerror, "GetProcAddress", L"W32TimeVerifyJoinConfig");
  941. }
  942. _BeginTryWith(hr) {
  943. pfnW32TimeVerifyJoinConfig();
  944. } _TrapException(hr);
  945. _JumpIfError(hr, vjcerror, "pfnW32TimeVerifyJoinConfig");
  946. hr=S_OK;
  947. vjcerror:
  948. if (FAILED(hr)) {
  949. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  950. if (FAILED(hr2)) {
  951. _IgnoreError(hr2, "GetSystemErrorString");
  952. } else {
  953. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  954. }
  955. goto error;
  956. }
  957. // check for vuc (verify unjoin config)
  958. } else if (true==CheckNextArg(pca, L"vuc", NULL)) {
  959. hr=VerifyAllArgsUsed(pca);
  960. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  961. LocalizedWPrintfCR(IDS_W32TM_STATUS_CALLING_UNJOINCONFIG);
  962. hmW32Time=LoadLibrary(wszDLLNAME);
  963. if (NULL==hmW32Time) {
  964. _JumpLastError(hr, vucerror, "LoadLibrary");
  965. }
  966. pfnW32TimeVerifyUnjoinConfig=(void (*)(void))GetProcAddress(hmW32Time, "W32TimeVerifyUnjoinConfig");
  967. if (NULL==pfnW32TimeVerifyUnjoinConfig) {
  968. _JumpLastErrorStr(hr, vucerror, "GetProcAddress", L"W32TimeVerifyJoinConfig");
  969. }
  970. _BeginTryWith(hr) {
  971. pfnW32TimeVerifyUnjoinConfig();
  972. } _TrapException(hr);
  973. _JumpIfError(hr, vucerror, "pfnW32TimeVerifyUnjoinConfig");
  974. hr=S_OK;
  975. vucerror:
  976. if (FAILED(hr)) {
  977. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  978. if (FAILED(hr2)) {
  979. _IgnoreError(hr2, "GetSystemErrorString");
  980. } else {
  981. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  982. }
  983. goto error;
  984. }
  985. // error out appropriately
  986. } else if (true==CheckNextArg(pca, L"qps", NULL)) {
  987. // find out what computer to resync
  988. if (FindArg(pca, L"computer", &wszComputer, &nArgID)) {
  989. MarkArgUsed(pca, nArgID);
  990. }
  991. wszComputerDisplay=wszComputer;
  992. if (NULL==wszComputerDisplay) {
  993. wszComputerDisplay=L"local computer";
  994. }
  995. hr=VerifyAllArgsUsed(pca);
  996. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  997. //LocalizedWPrintf2(IDS_W32TM_STATUS_CALLING_GETNETLOGONBITS_ON, L" %s.\n", wszComputerDisplay);
  998. {
  999. W32TIME_NTP_PROVIDER_DATA *ProviderInfo = NULL;
  1000. dwResult=W32TimeQueryNTPProviderStatus(wszComputer, 0, L"NtpClient", &ProviderInfo);
  1001. if (S_OK==dwResult) {
  1002. PrintNtpProviderData(ProviderInfo);
  1003. } else {
  1004. hr=GetSystemErrorString(HRESULT_FROM_WIN32(dwResult), &wszError);
  1005. _JumpIfError(hr, error, "GetSystemErrorString");
  1006. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  1007. }
  1008. }
  1009. } else {
  1010. hr=VerifyAllArgsUsed(pca);
  1011. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  1012. LocalizedWPrintf(IDS_W32TM_ERRORGENERAL_NOINTERFACE);
  1013. hr=E_INVALIDARG;
  1014. _JumpError(hr, error, "command line parsing");
  1015. }
  1016. hr=S_OK;
  1017. error:
  1018. if (NULL!=hmW32Time) {
  1019. FreeLibrary(hmW32Time);
  1020. }
  1021. if (NULL!=wszError) {
  1022. LocalFree(wszError);
  1023. }
  1024. return hr;
  1025. }
  1026. //--------------------------------------------------------------------
  1027. HRESULT ShowTimeZone(CmdArgs * pca) {
  1028. DWORD dwTimeZoneID;
  1029. HRESULT hr;
  1030. LPWSTR pwsz_IDS_W32TM_SIMPLESTRING_UNSPECIFIED = NULL;
  1031. LPWSTR pwsz_IDS_W32TM_TIMEZONE_CURRENT_TIMEZONE = NULL;
  1032. LPWSTR pwsz_IDS_W32TM_TIMEZONE_DAYLIGHT = NULL;
  1033. LPWSTR pwsz_IDS_W32TM_TIMEZONE_STANDARD = NULL;
  1034. LPWSTR pwsz_IDS_W32TM_TIMEZONE_UNKNOWN = NULL;
  1035. LPWSTR wszDaylightDate = NULL;
  1036. LPWSTR wszStandardDate = NULL;
  1037. LPWSTR wszTimeZoneId = NULL;
  1038. TIME_ZONE_INFORMATION tzi;
  1039. unsigned int nChars;
  1040. // Load the strings we'll need
  1041. struct LocalizedStrings {
  1042. UINT id;
  1043. LPWSTR *ppwsz;
  1044. } rgStrings[] = {
  1045. { IDS_W32TM_SIMPLESTRING_UNSPECIFIED, &pwsz_IDS_W32TM_SIMPLESTRING_UNSPECIFIED },
  1046. { IDS_W32TM_TIMEZONE_CURRENT_TIMEZONE, &pwsz_IDS_W32TM_TIMEZONE_CURRENT_TIMEZONE },
  1047. { IDS_W32TM_TIMEZONE_DAYLIGHT, &pwsz_IDS_W32TM_TIMEZONE_DAYLIGHT },
  1048. { IDS_W32TM_TIMEZONE_STANDARD, &pwsz_IDS_W32TM_TIMEZONE_STANDARD },
  1049. { IDS_W32TM_TIMEZONE_UNKNOWN, &pwsz_IDS_W32TM_TIMEZONE_UNKNOWN }
  1050. };
  1051. for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStrings); dwIndex++) {
  1052. if (!WriteMsg(FORMAT_MESSAGE_FROM_HMODULE, rgStrings[dwIndex].id, rgStrings[dwIndex].ppwsz)) {
  1053. hr = HRESULT_FROM_WIN32(GetLastError());
  1054. _JumpError(hr, error, "WriteMsg");
  1055. }
  1056. }
  1057. hr=VerifyAllArgsUsed(pca);
  1058. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  1059. dwTimeZoneID=GetTimeZoneInformation(&tzi);
  1060. switch (dwTimeZoneID)
  1061. {
  1062. case TIME_ZONE_ID_DAYLIGHT: wszTimeZoneId = pwsz_IDS_W32TM_TIMEZONE_DAYLIGHT; break;
  1063. case TIME_ZONE_ID_STANDARD: wszTimeZoneId = pwsz_IDS_W32TM_TIMEZONE_STANDARD; break;
  1064. case TIME_ZONE_ID_UNKNOWN: wszTimeZoneId = pwsz_IDS_W32TM_TIMEZONE_UNKNOWN; break;
  1065. default:
  1066. hr = HRESULT_FROM_WIN32(GetLastError());
  1067. LocalizedWPrintfCR(IDS_W32TM_ERRORTIMEZONE_INVALID);
  1068. _JumpError(hr, error, "GetTimeZoneInformation")
  1069. }
  1070. // Construct a string representing the "StandardDate" field of the TimeZoneInformation:
  1071. if (0==tzi.StandardDate.wMonth) {
  1072. wszStandardDate = pwsz_IDS_W32TM_SIMPLESTRING_UNSPECIFIED;
  1073. } else if (tzi.StandardDate.wMonth>12 || tzi.StandardDate.wDay>5 ||
  1074. tzi.StandardDate.wDay<1 || tzi.StandardDate.wDayOfWeek>6) {
  1075. if (!WriteMsg(FORMAT_MESSAGE_FROM_HMODULE, IDS_W32TM_INVALID_TZ_DATE, &wszStandardDate,
  1076. tzi.StandardDate.wMonth, tzi.StandardDate.wDay, tzi.StandardDate.wDayOfWeek)) {
  1077. _JumpLastError(hr, error, "WriteMsg");
  1078. }
  1079. } else {
  1080. if (!WriteMsg(FORMAT_MESSAGE_FROM_HMODULE, IDS_W32TM_VALID_TZ_DATE, &wszStandardDate,
  1081. tzi.StandardDate.wMonth, tzi.StandardDate.wDay, tzi.StandardDate.wDayOfWeek)) {
  1082. _JumpLastError(hr, error, "WriteMsg");
  1083. }
  1084. }
  1085. // Construct a string representing the "DaylightDate" field of the TimeZoneInformation:
  1086. if (0==tzi.DaylightDate.wMonth) {
  1087. wszDaylightDate = pwsz_IDS_W32TM_SIMPLESTRING_UNSPECIFIED;
  1088. } else if (tzi.DaylightDate.wMonth>12 || tzi.DaylightDate.wDay>5 ||
  1089. tzi.DaylightDate.wDay<1 || tzi.DaylightDate.wDayOfWeek>6) {
  1090. if (!WriteMsg(FORMAT_MESSAGE_FROM_HMODULE, IDS_W32TM_INVALID_TZ_DATE, &wszDaylightDate,
  1091. tzi.DaylightDate.wMonth, tzi.DaylightDate.wDay, tzi.DaylightDate.wDayOfWeek)) {
  1092. _JumpLastError(hr, error, "WriteMsg");
  1093. }
  1094. } else {
  1095. if (!WriteMsg(FORMAT_MESSAGE_FROM_HMODULE, IDS_W32TM_VALID_TZ_DATE, &wszDaylightDate,
  1096. tzi.DaylightDate.wMonth, tzi.DaylightDate.wDay, tzi.DaylightDate.wDayOfWeek)) {
  1097. _JumpLastError(hr, error, "WriteMsg");
  1098. }
  1099. }
  1100. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, IDS_W32TM_TIMEZONE_INFO,
  1101. wszTimeZoneId, tzi.Bias,
  1102. tzi.StandardName, tzi.StandardBias, wszStandardDate,
  1103. tzi.DaylightName, tzi.DaylightBias, wszDaylightDate);
  1104. hr=S_OK;
  1105. error:
  1106. // Free our localized strings:
  1107. for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStrings); dwIndex++) {
  1108. if (NULL != *(rgStrings[dwIndex].ppwsz)) { LocalFree(*(rgStrings[dwIndex].ppwsz)); }
  1109. }
  1110. if (NULL != wszDaylightDate) {
  1111. LocalFree(wszDaylightDate);
  1112. }
  1113. if (NULL != wszStandardDate) {
  1114. LocalFree(wszStandardDate);
  1115. }
  1116. if (FAILED(hr) && E_INVALIDARG!=hr) {
  1117. WCHAR * wszError;
  1118. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  1119. if (FAILED(hr2)) {
  1120. _IgnoreError(hr2, "GetSystemErrorString");
  1121. } else {
  1122. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  1123. LocalFree(wszError);
  1124. }
  1125. }
  1126. return hr;
  1127. }
  1128. //--------------------------------------------------------------------
  1129. HRESULT PrintRegLine(IN HANDLE hOut,
  1130. IN DWORD dwValueNameOffset,
  1131. IN LPWSTR pwszValueName,
  1132. IN DWORD dwValueTypeOffset,
  1133. IN LPWSTR pwszValueType,
  1134. IN DWORD dwValueDataOffset,
  1135. IN LPWSTR pwszValueData)
  1136. {
  1137. DWORD dwCurrentOffset = 0;
  1138. HRESULT hr;
  1139. WCHAR pwszLine[1024];
  1140. WCHAR wszNULL[] = L"<NULL>";
  1141. if (NULL == pwszValueName) { pwszValueName = &wszNULL[0]; }
  1142. if (NULL == pwszValueType) { pwszValueType = &wszNULL[0]; }
  1143. if (NULL == pwszValueData) { pwszValueData = &wszNULL[0]; }
  1144. // Ensure no buffer overflow:
  1145. _Verify(1024 > dwValueDataOffset + wcslen(pwszValueData), hr, error);
  1146. dwCurrentOffset = dwValueNameOffset;
  1147. dwCurrentOffset = wsprintf(&pwszLine[0] + dwCurrentOffset, L"%s", pwszValueName);
  1148. while (dwCurrentOffset < dwValueTypeOffset) {
  1149. dwCurrentOffset += wsprintf(&pwszLine[0] + dwCurrentOffset, L" ");
  1150. }
  1151. dwCurrentOffset += wsprintf(&pwszLine[0] + dwCurrentOffset, L"%s", pwszValueType);
  1152. while (dwCurrentOffset < dwValueDataOffset) {
  1153. dwCurrentOffset += wsprintf(&pwszLine[0] + dwCurrentOffset, L" ");
  1154. }
  1155. wsprintf(&pwszLine[0] + dwCurrentOffset, L"%s\n", pwszValueData);
  1156. //
  1157. PrintStr(hOut, &pwszLine[0]);
  1158. hr = S_OK;
  1159. error:
  1160. return hr;
  1161. }
  1162. HRESULT DumpReg(CmdArgs * pca)
  1163. {
  1164. BOOL fLoggedFailure = FALSE;
  1165. DWORD dwMaxValueNameLen = 0; // Size in TCHARs.
  1166. DWORD dwMaxValueDataLen = 0; // Size in bytes.
  1167. DWORD dwNumValues = 0;
  1168. DWORD dwRetval = 0;
  1169. DWORD dwType = 0;
  1170. DWORD dwValueNameLen = 0; // Size in TCHARs.
  1171. DWORD dwValueDataLen = 0; // Size in bytes.
  1172. HANDLE hOut = NULL;
  1173. HKEY hKeyConfig = NULL;
  1174. HKEY HKLM = HKEY_LOCAL_MACHINE;
  1175. HKEY HKLMRemote = NULL;
  1176. HRESULT hr = E_FAIL;
  1177. LPWSTR pwszValueName = NULL;
  1178. LPBYTE pbValueData = NULL;
  1179. LPWSTR pwszSubkeyName = NULL;
  1180. LPWSTR pwszComputerName = NULL;
  1181. unsigned int nArgID = 0;
  1182. WCHAR rgwszKeyName[1024];
  1183. // Variables to display formatted output:
  1184. DWORD dwCurrentOffset = 0;
  1185. DWORD dwValueNameOffset = 0;
  1186. DWORD dwValueTypeOffset = 0;
  1187. DWORD dwValueDataOffset = 0;
  1188. // Localized strings:
  1189. LPWSTR pwsz_VALUENAME = NULL;
  1190. LPWSTR pwsz_VALUETYPE = NULL;
  1191. LPWSTR pwsz_VALUEDATA = NULL;
  1192. LPWSTR pwsz_REGTYPE_DWORD = NULL;
  1193. LPWSTR pwsz_REGTYPE_SZ = NULL;
  1194. LPWSTR pwsz_REGTYPE_MULTISZ = NULL;
  1195. LPWSTR pwsz_REGTYPE_EXPANDSZ = NULL;
  1196. LPWSTR pwsz_REGTYPE_UNKNOWN = NULL;
  1197. LPWSTR pwsz_REGDATA_UNPARSABLE = NULL;
  1198. // Load the strings we'll need
  1199. struct LocalizedStrings {
  1200. UINT id;
  1201. LPWSTR *ppwsz;
  1202. } rgStrings[] = {
  1203. { IDS_W32TM_VALUENAME, &pwsz_VALUENAME },
  1204. { IDS_W32TM_VALUETYPE, &pwsz_VALUETYPE },
  1205. { IDS_W32TM_VALUEDATA, &pwsz_VALUEDATA },
  1206. { IDS_W32TM_REGTYPE_DWORD, &pwsz_REGTYPE_DWORD },
  1207. { IDS_W32TM_REGTYPE_SZ, &pwsz_REGTYPE_SZ },
  1208. { IDS_W32TM_REGTYPE_MULTISZ, &pwsz_REGTYPE_MULTISZ },
  1209. { IDS_W32TM_REGTYPE_EXPANDSZ, &pwsz_REGTYPE_EXPANDSZ },
  1210. { IDS_W32TM_REGTYPE_UNKNOWN, &pwsz_REGTYPE_UNKNOWN },
  1211. { IDS_W32TM_REGDATA_UNPARSABLE, &pwsz_REGDATA_UNPARSABLE }
  1212. };
  1213. for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStrings); dwIndex++) {
  1214. if (!WriteMsg(FORMAT_MESSAGE_FROM_HMODULE, rgStrings[dwIndex].id, rgStrings[dwIndex].ppwsz)) {
  1215. hr = HRESULT_FROM_WIN32(GetLastError());
  1216. _JumpError(hr, error, "WriteMsg");
  1217. }
  1218. }
  1219. dwCurrentOffset = wsprintf(&rgwszKeyName[0], wszW32TimeRegKeyRoot);
  1220. if (true==FindArg(pca, L"subkey", &pwszSubkeyName, &nArgID)) {
  1221. MarkArgUsed(pca, nArgID);
  1222. if (NULL == pwszSubkeyName) {
  1223. LocalizedWPrintfCR(IDS_W32TM_ERRORDUMPREG_NO_SUBKEY_SPECIFIED);
  1224. fLoggedFailure = TRUE;
  1225. hr = E_INVALIDARG;
  1226. _JumpError(hr, error, "command line parsing");
  1227. }
  1228. dwCurrentOffset += wsprintf(&rgwszKeyName[0] + dwCurrentOffset, L"\\");
  1229. wsprintf(&rgwszKeyName[0] + dwCurrentOffset, pwszSubkeyName);
  1230. }
  1231. if (true==FindArg(pca, L"computer", &pwszComputerName, &nArgID)) {
  1232. MarkArgUsed(pca, nArgID);
  1233. dwRetval = RegConnectRegistry(pwszComputerName, HKEY_LOCAL_MACHINE, &HKLMRemote);
  1234. if (ERROR_SUCCESS != dwRetval) {
  1235. hr = HRESULT_FROM_WIN32(dwRetval);
  1236. _JumpErrorStr(hr, error, "RegConnectRegistry", L"HKEY_LOCAL_MACHINE");
  1237. }
  1238. HKLM = HKLMRemote;
  1239. }
  1240. hr = VerifyAllArgsUsed(pca);
  1241. _JumpIfError(hr, error, "VerifyAllArgsUsed");
  1242. dwRetval = RegOpenKeyEx(HKLM, rgwszKeyName, 0, KEY_QUERY_VALUE, &hKeyConfig);
  1243. if (ERROR_SUCCESS != dwRetval) {
  1244. hr = HRESULT_FROM_WIN32(dwRetval);
  1245. _JumpErrorStr(hr, error, "RegOpenKeyEx", rgwszKeyName);
  1246. }
  1247. dwRetval = RegQueryInfoKey
  1248. (hKeyConfig,
  1249. NULL, // class buffer
  1250. NULL, // size of class buffer
  1251. NULL, // reserved
  1252. NULL, // number of subkeys
  1253. NULL, // longest subkey name
  1254. NULL, // longest class string
  1255. &dwNumValues, // number of value entries
  1256. &dwMaxValueNameLen, // longest value name
  1257. &dwMaxValueDataLen, // longest value data
  1258. NULL,
  1259. NULL
  1260. );
  1261. if (ERROR_SUCCESS != dwRetval) {
  1262. hr = HRESULT_FROM_WIN32(dwRetval);
  1263. _JumpErrorStr(hr, error, "RegQueryInfoKey", rgwszKeyName);
  1264. } else if (0 == dwNumValues) {
  1265. hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  1266. _JumpErrorStr(hr, error, "RegQueryInfoKey", rgwszKeyName);
  1267. }
  1268. dwMaxValueNameLen += sizeof(WCHAR); // Include space for NULL character
  1269. pwszValueName = (LPWSTR)LocalAlloc(LPTR, dwMaxValueNameLen * sizeof(WCHAR));
  1270. _JumpIfOutOfMemory(hr, error, pwszValueName);
  1271. pbValueData = (LPBYTE)LocalAlloc(LPTR, dwMaxValueDataLen);
  1272. _JumpIfOutOfMemory(hr, error, pbValueData);
  1273. dwValueNameOffset = 0;
  1274. dwValueTypeOffset = dwValueNameOffset + dwMaxValueNameLen + 3;
  1275. dwValueDataOffset += dwValueTypeOffset + 20;
  1276. // Print table header:
  1277. hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1278. if (INVALID_HANDLE_VALUE==hOut) {
  1279. _JumpLastError(hr, error, "GetStdHandle");
  1280. }
  1281. PrintStr(hOut, L"\n");
  1282. PrintRegLine(hOut, dwValueNameOffset, pwsz_VALUENAME, dwValueTypeOffset, pwsz_VALUETYPE, dwValueDataOffset, pwsz_VALUEDATA);
  1283. // Next line:
  1284. dwCurrentOffset = dwValueNameOffset;
  1285. for (DWORD dwIndex = dwCurrentOffset; dwIndex < (dwValueDataOffset + (dwMaxValueDataLen / 2)); dwIndex++) {
  1286. PrintStr(hOut, L"-");
  1287. }
  1288. PrintStr(hOut, L"\n\n");
  1289. for (DWORD dwIndex = 0; dwIndex < dwNumValues; dwIndex++) {
  1290. dwValueNameLen = dwMaxValueNameLen;
  1291. dwValueDataLen = dwMaxValueDataLen;
  1292. memset(reinterpret_cast<LPBYTE>(pwszValueName), 0, dwMaxValueNameLen * sizeof(WCHAR));
  1293. memset(pbValueData, 0, dwMaxValueDataLen);
  1294. dwRetval = RegEnumValue
  1295. (hKeyConfig, // handle to key to query
  1296. dwIndex, // index of value to query
  1297. pwszValueName, // value buffer
  1298. &dwValueNameLen, // size of value buffer (in TCHARs)
  1299. NULL, // reserved
  1300. &dwType, // type buffer
  1301. pbValueData, // data buffer
  1302. &dwValueDataLen // size of data buffer
  1303. );
  1304. if (ERROR_SUCCESS != dwRetval) {
  1305. hr = HRESULT_FROM_WIN32(dwRetval);
  1306. _JumpErrorStr(hr, error, "RegEnumValue", wszW32TimeRegKeyConfig);
  1307. }
  1308. _Verify(dwValueNameLen <= dwMaxValueNameLen, hr, error);
  1309. _Verify(dwValueDataLen <= dwMaxValueDataLen, hr, error);
  1310. {
  1311. LPWSTR pwszRegType = NULL;
  1312. LPWSTR pwszRegData = NULL;
  1313. switch (dwType) {
  1314. case REG_DWORD:
  1315. {
  1316. WCHAR rgwszDwordData[20];
  1317. _ltow(*(reinterpret_cast<long *>(pbValueData)), rgwszDwordData, 10);
  1318. pwszRegType = pwsz_REGTYPE_DWORD;
  1319. pwszRegData = &rgwszDwordData[0];
  1320. }
  1321. break;
  1322. case REG_MULTI_SZ:
  1323. {
  1324. WCHAR wszDelimiter[] = { L'\0', L'\0', L'\0' };
  1325. WCHAR rgwszMultiSzData[1024] = { L'\0' };
  1326. LPWSTR pwsz;
  1327. dwCurrentOffset = 0;
  1328. for (pwsz = (LPWSTR)pbValueData; L'\0' != *pwsz; pwsz += wcslen(pwsz)+1) {
  1329. dwCurrentOffset += wsprintf(&rgwszMultiSzData[0] + dwCurrentOffset, wszDelimiter);
  1330. dwCurrentOffset += wsprintf(&rgwszMultiSzData[0] + dwCurrentOffset, pwsz);
  1331. wszDelimiter[0] = L','; wszDelimiter[1] = L' ';
  1332. }
  1333. pwszRegType = pwsz_REGTYPE_MULTISZ;
  1334. pwszRegData = &rgwszMultiSzData[0];
  1335. }
  1336. break;
  1337. case REG_EXPAND_SZ:
  1338. {
  1339. pwszRegType = pwsz_REGTYPE_EXPANDSZ;
  1340. pwszRegData = reinterpret_cast<WCHAR *>(pbValueData);
  1341. }
  1342. break;
  1343. case REG_SZ:
  1344. {
  1345. pwszRegType = pwsz_REGTYPE_SZ;
  1346. pwszRegData = reinterpret_cast<WCHAR *>(pbValueData);
  1347. }
  1348. break;
  1349. default:
  1350. // Unrecognized reg type...
  1351. pwszRegType = pwsz_REGTYPE_UNKNOWN;
  1352. pwszRegData = pwsz_REGDATA_UNPARSABLE;
  1353. }
  1354. PrintRegLine(hOut, dwValueNameOffset, pwszValueName, dwValueTypeOffset, pwszRegType, dwValueDataOffset, pwszRegData);
  1355. }
  1356. }
  1357. PrintStr(hOut, L"\n");
  1358. hr = S_OK;
  1359. error:
  1360. // Free our localized strings:
  1361. for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStrings); dwIndex++) {
  1362. if (NULL != *(rgStrings[dwIndex].ppwsz)) { LocalFree(*(rgStrings[dwIndex].ppwsz)); }
  1363. }
  1364. if (NULL != hKeyConfig) { RegCloseKey(hKeyConfig); }
  1365. if (NULL != HKLMRemote) { RegCloseKey(HKLMRemote); }
  1366. if (NULL != pwszValueName) { LocalFree(pwszValueName); }
  1367. if (NULL != pbValueData) { LocalFree(pbValueData); }
  1368. if (FAILED(hr) && !fLoggedFailure) {
  1369. WCHAR * wszError;
  1370. HRESULT hr2=GetSystemErrorString(hr, &wszError);
  1371. if (FAILED(hr2)) {
  1372. _IgnoreError(hr2, "GetSystemErrorString");
  1373. } else {
  1374. LocalizedWPrintf2(IDS_W32TM_ERRORGENERAL_ERROR_OCCURED, L" %s\n", wszError);
  1375. LocalFree(wszError);
  1376. }
  1377. }
  1378. return hr;
  1379. }