Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1747 lines
61 KiB

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