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.

616 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: Util.cpp
  7. //
  8. // Contents: Generic utility functions and classes for dscmd
  9. //
  10. // History: 01-Oct-2000 JeffJon Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "pch.h"
  14. #include "util.h"
  15. #ifdef DBG
  16. //
  17. // Globals
  18. //
  19. CDebugSpew DebugSpew;
  20. //+--------------------------------------------------------------------------
  21. //
  22. // Member: CDebugSpew::EnterFunction
  23. //
  24. // Synopsis: Outputs "Enter " followed by the function name (or any passed
  25. // in string) and then calls Indent so that any output is indented
  26. //
  27. // Arguments: [nDebugLevel - IN] : the level at which this output should
  28. // be spewed
  29. // [pszFunction - IN] : a string to output to the console which
  30. // is proceeded by "Entering "
  31. //
  32. // Returns:
  33. //
  34. // History: 01-Oct-2000 JeffJon Created
  35. //
  36. //---------------------------------------------------------------------------
  37. void CDebugSpew::EnterFunction(UINT nDebugLevel, PCWSTR pszFunction)
  38. {
  39. //
  40. // Verify input parameter
  41. //
  42. if (!pszFunction)
  43. {
  44. ASSERT(pszFunction);
  45. return;
  46. }
  47. CComBSTR sbstrOutput(L"Entering ");
  48. sbstrOutput += pszFunction;
  49. //
  50. // Output the debug spew
  51. //
  52. Output(nDebugLevel, sbstrOutput);
  53. //
  54. // Indent
  55. //
  56. Indent();
  57. }
  58. //+--------------------------------------------------------------------------
  59. //
  60. // Member: CDebugSpew::LeaveFunction
  61. //
  62. // Synopsis: Outputs "Exit " followed by the function name (or any passed
  63. // in string) and then calls Outdent
  64. //
  65. // Arguments: [nDebugLevel - IN] : the level at which this output should
  66. // be spewed
  67. // [pszFunction - IN] : a string to output to the console which
  68. // is proceeded by "Leaving "
  69. //
  70. // Returns:
  71. //
  72. // History: 01-Oct-2000 JeffJon Created
  73. //
  74. //---------------------------------------------------------------------------
  75. void CDebugSpew::LeaveFunction(UINT nDebugLevel, PCWSTR pszFunction)
  76. {
  77. //
  78. // Verify input parameter
  79. //
  80. if (!pszFunction)
  81. {
  82. ASSERT(pszFunction);
  83. return;
  84. }
  85. //
  86. // Outdent
  87. //
  88. Outdent();
  89. CComBSTR sbstrOutput(L"Leaving ");
  90. sbstrOutput += pszFunction;
  91. //
  92. // Output the debug spew
  93. //
  94. Output(nDebugLevel, sbstrOutput);
  95. }
  96. //+--------------------------------------------------------------------------
  97. //
  98. // Member: CDebugSpew::LeaveFunctionHr
  99. //
  100. // Synopsis: Outputs "Exit " followed by the function name (or any passed
  101. // in string), the HRESULT return value, and then calls Outdent
  102. //
  103. // Arguments: [nDebugLevel - IN] : the level at which this output should
  104. // be spewed
  105. // [pszFunction - IN] : a string to output to the console which
  106. // is proceeded by "Leaving "
  107. // [hr - IN] : the HRESULT result value that is being
  108. // returned by the function
  109. //
  110. // Returns:
  111. //
  112. // History: 01-Oct-2000 JeffJon Created
  113. //
  114. //---------------------------------------------------------------------------
  115. void CDebugSpew::LeaveFunctionHr(UINT nDebugLevel, PCWSTR pszFunction, HRESULT hr)
  116. {
  117. //
  118. // Verify input parameter
  119. //
  120. if (!pszFunction)
  121. {
  122. ASSERT(pszFunction);
  123. return;
  124. }
  125. //
  126. // Outdent
  127. //
  128. Outdent();
  129. CComBSTR sbstrOutput(L"Leaving ");
  130. sbstrOutput += pszFunction;
  131. //
  132. // Append the return value
  133. //
  134. WCHAR pszReturn[30];
  135. wsprintf(pszReturn, L" returning 0x%x", hr);
  136. sbstrOutput += pszReturn;
  137. //
  138. // Output the debug spew
  139. //
  140. Output(nDebugLevel, sbstrOutput);
  141. }
  142. //+--------------------------------------------------------------------------
  143. //
  144. // Member: OsName
  145. //
  146. // Synopsis: Returns a readable string of the platform
  147. //
  148. // Arguments: [refInfo IN] : reference the OS version info structure
  149. // retrieved from GetVersionEx()
  150. //
  151. // Returns: PWSTR : returns a pointer to static text describing the
  152. // platform. The returned string does not have to
  153. // be freed.
  154. //
  155. // History: 20-Dec-2000 JeffJon Created
  156. //
  157. //---------------------------------------------------------------------------
  158. PWSTR OsName(const OSVERSIONINFO& refInfo)
  159. {
  160. switch (refInfo.dwPlatformId)
  161. {
  162. case VER_PLATFORM_WIN32s:
  163. {
  164. return L"Win32s on Windows 3.1";
  165. }
  166. case VER_PLATFORM_WIN32_WINDOWS:
  167. {
  168. switch (refInfo.dwMinorVersion)
  169. {
  170. case 0:
  171. {
  172. return L"Windows 95";
  173. }
  174. case 1:
  175. {
  176. return L"Windows 98";
  177. }
  178. default:
  179. {
  180. return L"Windows 9X";
  181. }
  182. }
  183. }
  184. case VER_PLATFORM_WIN32_NT:
  185. {
  186. return L"Windows NT";
  187. }
  188. default:
  189. {
  190. ASSERT(false);
  191. break;
  192. }
  193. }
  194. return L"Some Unknown Windows Version";
  195. }
  196. //+--------------------------------------------------------------------------
  197. //
  198. // Member: CDebugSpew::SpewHeader
  199. //
  200. // Synopsis: Outputs debug information like command line and build info
  201. //
  202. // Arguments:
  203. //
  204. // Returns:
  205. //
  206. // History: 20-Dec-2000 JeffJon Created
  207. //
  208. //---------------------------------------------------------------------------
  209. void CDebugSpew::SpewHeader()
  210. {
  211. //
  212. // First output the command line
  213. //
  214. PWSTR pszCommandLine = GetCommandLine();
  215. if (pszCommandLine)
  216. {
  217. Output(MINIMAL_LOGGING,
  218. L"Command line: %s",
  219. GetCommandLine());
  220. }
  221. //
  222. // Output the module being used
  223. //
  224. do // false loop
  225. {
  226. //
  227. // Get the file path
  228. //
  229. WCHAR pszFileName[MAX_PATH + 1];
  230. ::ZeroMemory(pszFileName, sizeof(pszFileName));
  231. if (::GetModuleFileNameW(::GetModuleHandle(NULL), pszFileName, MAX_PATH) == 0)
  232. {
  233. break;
  234. }
  235. Output(MINIMAL_LOGGING,
  236. L"Module: %s",
  237. pszFileName);
  238. //
  239. // get the file attributes
  240. //
  241. WIN32_FILE_ATTRIBUTE_DATA attr;
  242. ::ZeroMemory(&attr, sizeof(attr));
  243. if (::GetFileAttributesEx(pszFileName, GetFileExInfoStandard, &attr) == 0)
  244. {
  245. break;
  246. }
  247. //
  248. // convert the filetime to a system time
  249. //
  250. FILETIME localtime;
  251. ::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &localtime);
  252. SYSTEMTIME systime;
  253. ::FileTimeToSystemTime(&localtime, &systime);
  254. //
  255. // output the timestamp
  256. //
  257. Output(MINIMAL_LOGGING,
  258. L"Timestamp: %2d/%2d/%4d %2d:%2d:%d.%d",
  259. systime.wMonth,
  260. systime.wDay,
  261. systime.wYear,
  262. systime.wHour,
  263. systime.wMinute,
  264. systime.wSecond,
  265. systime.wMilliseconds);
  266. } while (false);
  267. //
  268. // Get the system info
  269. //
  270. OSVERSIONINFO info;
  271. info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  272. BOOL success = ::GetVersionEx(&info);
  273. ASSERT(success);
  274. //
  275. // Get the Whistler build lab version
  276. //
  277. CComBSTR sbstrLabInfo;
  278. do // false loop
  279. {
  280. HKEY key = 0;
  281. LONG err = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  282. L"Software\\Microsoft\\Windows NT\\CurrentVersion",
  283. 0,
  284. KEY_READ,
  285. &key);
  286. if (err != ERROR_SUCCESS)
  287. {
  288. break;
  289. }
  290. WCHAR buf[MAX_PATH + 1];
  291. ::ZeroMemory(buf, sizeof(buf));
  292. DWORD type = 0;
  293. DWORD bufSize = MAX_PATH + 1;
  294. err = ::RegQueryValueEx(key,
  295. L"BuildLab",
  296. 0,
  297. &type,
  298. reinterpret_cast<BYTE*>(buf),
  299. &bufSize);
  300. if (err != ERROR_SUCCESS)
  301. {
  302. break;
  303. }
  304. sbstrLabInfo = buf;
  305. } while (false);
  306. Output(MINIMAL_LOGGING,
  307. L"Build: %s %d.%d build %d %s (BuildLab:%s)",
  308. OsName(info),
  309. info.dwMajorVersion,
  310. info.dwMinorVersion,
  311. info.dwBuildNumber,
  312. info.szCSDVersion,
  313. sbstrLabInfo);
  314. //
  315. // Output a blank line to separate the header from the rest of the output
  316. //
  317. Output(MINIMAL_LOGGING,
  318. L"\n");
  319. }
  320. //+--------------------------------------------------------------------------
  321. //
  322. // Member: CDebugSpew::Output
  323. //
  324. // Synopsis: Outputs the passed in string to stdout proceeded by the number
  325. // of spaces specified by GetIndent()
  326. //
  327. // Arguments: [nDebugLevel - IN] : the level at which this output should
  328. // be spewed
  329. // [pszOutput - IN] : a format string to output to the console
  330. // [... - IN] : a variable argument list to be formatted
  331. // into pszOutput similar to wprintf
  332. //
  333. // Returns:
  334. //
  335. // History: 01-Oct-2000 JeffJon Created
  336. //
  337. //---------------------------------------------------------------------------
  338. void CDebugSpew::Output(UINT nDebugLevel, PCWSTR pszOutput, ...)
  339. {
  340. if (nDebugLevel <= GetDebugLevel())
  341. {
  342. //
  343. // Verify parameters
  344. //
  345. if (!pszOutput)
  346. {
  347. ASSERT(pszOutput);
  348. return;
  349. }
  350. va_list args;
  351. va_start(args, pszOutput);
  352. int nBuf;
  353. WCHAR szBuffer[1024];
  354. nBuf = _vsnwprintf(szBuffer, sizeof(szBuffer)/sizeof(WCHAR), pszOutput, args);
  355. CComBSTR sbstrOutput;
  356. //
  357. // Insert the spaces for the indent
  358. //
  359. for (UINT nCount = 0; nCount < GetIndent(); nCount++)
  360. {
  361. sbstrOutput += L" ";
  362. }
  363. //
  364. // Append the output string
  365. //
  366. sbstrOutput += szBuffer;
  367. //
  368. // Output the results
  369. //
  370. WriteStandardOut(L"%s\n", sbstrOutput);
  371. va_end(args);
  372. }
  373. }
  374. #endif // DBG
  375. //+--------------------------------------------------------------------------
  376. //
  377. // Macro: MyA2WHelper
  378. //
  379. // Synopsis: Converts a string from Ansi to Unicode in the OEM codepage
  380. //
  381. // Arguments: [lpw - IN/OUT] : buffer to receive the Unicode string
  382. // [lpa - IN] : Ansi string to be converted
  383. // [nChars - IN] : maximum number of characters that can fit in the buffer
  384. // [acp - IN] : the codepage to use
  385. //
  386. // Returns: PWSTR : the Unicode string in the OEM codepage
  387. //
  388. // History: 04-Oct-2000 JeffJon Created
  389. //
  390. //---------------------------------------------------------------------------
  391. inline PWSTR WINAPI MyA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
  392. {
  393. ATLASSERT(lpa != NULL);
  394. ATLASSERT(lpw != NULL);
  395. // verify that no illegal character present
  396. // since lpw was allocated based on the size of lpa
  397. // don't worry about the number of chars
  398. lpw[0] = '\0';
  399. MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
  400. return lpw;
  401. }
  402. //+--------------------------------------------------------------------------
  403. //
  404. // Macro: A2W_OEM
  405. //
  406. // Synopsis: Converts a string from Ansi to Unicode in the OEM codepage
  407. //
  408. // Arguments: [lpa - IN] : the string to be converted
  409. //
  410. // Returns: PWSTR : the Unicode string in the OEM codepage
  411. //
  412. // History: 04-Oct-2000 JeffJon Created
  413. //
  414. //---------------------------------------------------------------------------
  415. #define A2W_OEM(lpa) (\
  416. ((_lpaMine = lpa) == NULL) ? NULL : (\
  417. _convert = (lstrlenA(_lpaMine)+1),\
  418. MyA2WHelper((LPWSTR) alloca(_convert*2), _lpaMine, _convert, CP_OEMCP)))
  419. //+--------------------------------------------------------------------------
  420. //
  421. // Function: _UnicodeToOemConvert
  422. //
  423. // Synopsis: takes the passed in string (pszUnicode) and converts it to
  424. // the OEM code page
  425. //
  426. // Arguments: [pszUnicode - IN] : the string to be converted
  427. // [sbstrOemUnicode - OUT] : the converted string
  428. //
  429. // Returns:
  430. //
  431. // History: 04-Oct-2000 JeffJon Created
  432. //
  433. //---------------------------------------------------------------------------
  434. void _UnicodeToOemConvert(PCWSTR pszUnicode, CComBSTR& sbstrOemUnicode)
  435. {
  436. USES_CONVERSION;
  437. //
  438. // add this for the macro to work
  439. //
  440. LPCSTR _lpaMine = NULL;
  441. //
  442. // convert to CHAR OEM
  443. //
  444. int nLen = lstrlen(pszUnicode);
  445. LPSTR pszOemAnsi = new CHAR[3*(nLen+1)]; // more, to be sure...
  446. if (pszOemAnsi)
  447. {
  448. CharToOem(pszUnicode, pszOemAnsi);
  449. //
  450. // convert it back to WCHAR on OEM CP
  451. //
  452. sbstrOemUnicode = A2W_OEM(pszOemAnsi);
  453. delete[] pszOemAnsi;
  454. pszOemAnsi = 0;
  455. }
  456. }
  457. //+--------------------------------------------------------------------------
  458. //
  459. // Function: SpewAttrs(ADS_ATTR_INFO* pCreateAttrs, DWORD dwNumAttrs);
  460. //
  461. // Synopsis: Uses the DEBUG_OUTPUT macro to output the attributes and the
  462. // values specified
  463. //
  464. // Arguments: [pAttrs - IN] : The ADS_ATTR_INFO
  465. // [dwNumAttrs - IN] : The number of attributes in pAttrs
  466. //
  467. // Returns:
  468. //
  469. // History: 04-Oct-2000 JeffJon Created
  470. //
  471. //---------------------------------------------------------------------------
  472. #ifdef DBG
  473. void SpewAttrs(ADS_ATTR_INFO* pAttrs, DWORD dwNumAttrs)
  474. {
  475. for (DWORD dwAttrIdx = 0; dwAttrIdx < dwNumAttrs; dwAttrIdx++)
  476. {
  477. if (pAttrs[dwAttrIdx].dwADsType == ADSTYPE_DN_STRING ||
  478. pAttrs[dwAttrIdx].dwADsType == ADSTYPE_CASE_EXACT_STRING ||
  479. pAttrs[dwAttrIdx].dwADsType == ADSTYPE_CASE_IGNORE_STRING ||
  480. pAttrs[dwAttrIdx].dwADsType == ADSTYPE_PRINTABLE_STRING)
  481. {
  482. for (DWORD dwValueIdx = 0; dwValueIdx < pAttrs[dwAttrIdx].dwNumValues; dwValueIdx++)
  483. {
  484. if (pAttrs[dwAttrIdx].pADsValues[dwValueIdx].CaseIgnoreString)
  485. {
  486. DEBUG_OUTPUT(FULL_LOGGING, L" %s = %s",
  487. pAttrs[dwAttrIdx].pszAttrName,
  488. pAttrs[dwAttrIdx].pADsValues[dwValueIdx].CaseIgnoreString);
  489. }
  490. else
  491. {
  492. DEBUG_OUTPUT(FULL_LOGGING, L" %s = value being cleared",
  493. pAttrs[dwAttrIdx].pszAttrName);
  494. }
  495. }
  496. }
  497. }
  498. }
  499. #endif // DBG
  500. //+--------------------------------------------------------------------------
  501. //
  502. // Function: litow
  503. //
  504. // Synopsis:
  505. //
  506. // Arguments: [li - IN] : reference to large integer to be converted to string
  507. // [sResult - OUT] : Gets the output string
  508. // Returns: void
  509. //
  510. // History: 25-Sep-2000 hiteshr Created
  511. // Copied from dsadmin code base, changed work with CComBSTR
  512. //---------------------------------------------------------------------------
  513. void litow(LARGE_INTEGER& li, CComBSTR& sResult)
  514. {
  515. LARGE_INTEGER n;
  516. n.QuadPart = li.QuadPart;
  517. if (n.QuadPart == 0)
  518. {
  519. sResult = L"0";
  520. }
  521. else
  522. {
  523. CComBSTR sNeg;
  524. sResult = L"";
  525. if (n.QuadPart < 0)
  526. {
  527. sNeg = CComBSTR(L'-');
  528. n.QuadPart *= -1;
  529. }
  530. while (n.QuadPart > 0)
  531. {
  532. WCHAR ch[2];
  533. ch[0] = static_cast<WCHAR>(L'0' + static_cast<WCHAR>(n.QuadPart % 10));
  534. ch[1] = L'\0';
  535. sResult += ch;
  536. n.QuadPart = n.QuadPart / 10;
  537. }
  538. sResult += sNeg;
  539. }
  540. //Reverse the string
  541. WCHAR szTemp[256];
  542. wcscpy(szTemp,sResult);
  543. LPWSTR pStart,pEnd;
  544. pStart = szTemp;
  545. pEnd = pStart + wcslen(pStart) -1;
  546. while(pStart < pEnd)
  547. {
  548. WCHAR ch = *pStart;
  549. *pStart++ = *pEnd;
  550. *pEnd-- = ch;
  551. }
  552. sResult = szTemp;
  553. }