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.

957 lines
20 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: config.cpp
  8. //
  9. // Contents: ICertConfig IDispatch helper functions
  10. //
  11. //--------------------------------------------------------------------------
  12. #include <pch.cpp>
  13. #pragma hdrstop
  14. #include <stdlib.h>
  15. #include "csdisp.h"
  16. #define __dwFILE__ __dwFILE_CERTLIB_CONFIG_CPP__
  17. //+------------------------------------------------------------------------
  18. // ICertConfig dispatch support
  19. // TCHAR szRegKeyConfigClsid[] = wszCLASS_CERTCONFIG TEXT("\\Clsid");
  20. //+------------------------------------
  21. // Reset method:
  22. static OLECHAR *_apszReset[] = {
  23. TEXT("Reset"),
  24. TEXT("Index"),
  25. };
  26. //+------------------------------------
  27. // Next method:
  28. static OLECHAR *_apszNext[] = {
  29. TEXT("Next"),
  30. };
  31. //+------------------------------------
  32. // GetField method:
  33. static OLECHAR *_apszGetField[] = {
  34. TEXT("GetField"),
  35. TEXT("strFieldName"),
  36. };
  37. //+------------------------------------
  38. // GetConfig method:
  39. static OLECHAR *_apszGetConfig[] = {
  40. TEXT("GetConfig"),
  41. TEXT("Flags"),
  42. };
  43. //+------------------------------------
  44. // SetSharedFolder method:
  45. static OLECHAR *_apszSetSharedFolder[] = {
  46. TEXT("SetSharedFolder"),
  47. TEXT("strSharedFolder"),
  48. };
  49. //+------------------------------------
  50. // Dispatch Table:
  51. DISPATCHTABLE s_adtConfig[] =
  52. {
  53. #define CONFIG_RESET 0
  54. DECLARE_DISPATCH_ENTRY(_apszReset)
  55. #define CONFIG_NEXT 1
  56. DECLARE_DISPATCH_ENTRY(_apszNext)
  57. #define CONFIG_GETFIELD 2
  58. DECLARE_DISPATCH_ENTRY(_apszGetField)
  59. #define CONFIG_GETCONFIG 3
  60. DECLARE_DISPATCH_ENTRY(_apszGetConfig)
  61. #define CONFIG2_SETSHAREDFOLDER 4
  62. DECLARE_DISPATCH_ENTRY(_apszSetSharedFolder)
  63. };
  64. #define CCONFIGDISPATCH (ARRAYSIZE(s_adtConfig))
  65. #define CCONFIGDISPATCH_V1 CONFIG2_SETSHAREDFOLDER
  66. #define CCONFIGDISPATCH_V2 CCONFIGDISPATCH
  67. DWORD s_acConfigDispatch[] = {
  68. CCONFIGDISPATCH_V2,
  69. CCONFIGDISPATCH_V1,
  70. };
  71. IID const *s_apConfigiid[] = {
  72. &IID_ICertConfig2,
  73. &IID_ICertConfig,
  74. };
  75. HRESULT
  76. Config_Init(
  77. IN DWORD Flags,
  78. OUT DISPATCHINTERFACE *pdiConfig)
  79. {
  80. HRESULT hr;
  81. hr = DispatchSetup2(
  82. Flags,
  83. CLSCTX_INPROC_SERVER,
  84. wszCLASS_CERTCONFIG,
  85. &CLSID_CCertConfig,
  86. ARRAYSIZE(s_acConfigDispatch), // cver
  87. s_apConfigiid,
  88. s_acConfigDispatch,
  89. s_adtConfig,
  90. pdiConfig);
  91. _JumpIfError(hr, error, "DispatchSetup2(ICertConfig)");
  92. error:
  93. return(hr);
  94. }
  95. VOID
  96. Config_Release(
  97. IN OUT DISPATCHINTERFACE *pdiConfig)
  98. {
  99. DispatchRelease(pdiConfig);
  100. }
  101. HRESULT
  102. ConfigVerifyVersion(
  103. IN DISPATCHINTERFACE *pdiConfig,
  104. IN DWORD RequiredVersion)
  105. {
  106. HRESULT hr;
  107. CSASSERT(NULL != pdiConfig && NULL != pdiConfig->pDispatchTable);
  108. switch (pdiConfig->m_dwVersion)
  109. {
  110. case 1:
  111. CSASSERT(
  112. NULL == pdiConfig->pDispatch ||
  113. CCONFIGDISPATCH_V1 == pdiConfig->m_cDispatchTable);
  114. break;
  115. case 2:
  116. CSASSERT(
  117. NULL == pdiConfig->pDispatch ||
  118. CCONFIGDISPATCH_V2 == pdiConfig->m_cDispatchTable);
  119. break;
  120. default:
  121. hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
  122. _JumpError(hr, error, "m_dwVersion");
  123. }
  124. if (pdiConfig->m_dwVersion < RequiredVersion)
  125. {
  126. hr = E_NOTIMPL;
  127. _JumpError(hr, error, "old interface");
  128. }
  129. hr = S_OK;
  130. error:
  131. return(hr);
  132. }
  133. HRESULT
  134. Config_Reset(
  135. IN DISPATCHINTERFACE *pdiConfig,
  136. IN LONG Index,
  137. OUT LONG *pCount)
  138. {
  139. HRESULT hr;
  140. CSASSERT(NULL != pdiConfig && NULL != pdiConfig->pDispatchTable);
  141. if (NULL != pdiConfig->pDispatch)
  142. {
  143. VARIANT avar[1];
  144. avar[0].vt = VT_I4;
  145. avar[0].lVal = Index;
  146. hr = DispatchInvoke(
  147. pdiConfig,
  148. CONFIG_RESET,
  149. ARRAYSIZE(avar),
  150. avar,
  151. VT_I4,
  152. pCount);
  153. _JumpIfError(hr, error, "Invoke(Reset)");
  154. }
  155. else
  156. {
  157. hr = ((ICertConfig *) pdiConfig->pUnknown)->Reset(Index, pCount);
  158. _JumpIfError(hr, error, "ICertConfig::Reset");
  159. }
  160. error:
  161. return(hr);
  162. }
  163. HRESULT
  164. Config_Next(
  165. IN DISPATCHINTERFACE *pdiConfig,
  166. IN LONG *pIndex)
  167. {
  168. HRESULT hr;
  169. CSASSERT(NULL != pdiConfig && NULL != pdiConfig->pDispatchTable);
  170. if (NULL != pdiConfig->pDispatch)
  171. {
  172. hr = DispatchInvoke(
  173. pdiConfig,
  174. CONFIG_NEXT,
  175. 0,
  176. NULL,
  177. VT_I4,
  178. pIndex);
  179. _JumpIfError(hr, error, "Invoke(Next)");
  180. }
  181. else
  182. {
  183. hr = ((ICertConfig *) pdiConfig->pUnknown)->Next(pIndex);
  184. if (S_FALSE != hr)
  185. {
  186. _JumpIfError(hr, error, "ICertConfig::Next");
  187. }
  188. }
  189. error:
  190. return(hr);
  191. }
  192. HRESULT
  193. Config_GetField(
  194. IN DISPATCHINTERFACE *pdiConfig,
  195. IN WCHAR const *pwszField,
  196. OUT BSTR *pstr)
  197. {
  198. HRESULT hr;
  199. BSTR strField = NULL;
  200. CSASSERT(NULL != pdiConfig && NULL != pdiConfig->pDispatchTable);
  201. if (!ConvertWszToBstr(&strField, pwszField, -1))
  202. {
  203. hr = E_OUTOFMEMORY;
  204. _JumpError(hr, error, "ConvertWszToBstr");
  205. }
  206. //wprintf(L"str=%ws, len=%u\n", strField, ((ULONG *) strField)[-1]);
  207. if (NULL != pdiConfig->pDispatch)
  208. {
  209. VARIANT avar[1];
  210. avar[0].vt = VT_BSTR;
  211. avar[0].bstrVal = strField;
  212. hr = DispatchInvoke(
  213. pdiConfig,
  214. CONFIG_GETFIELD,
  215. ARRAYSIZE(avar),
  216. avar,
  217. VT_BSTR,
  218. pstr);
  219. _JumpIfError(hr, error, "Invoke(GetField)");
  220. }
  221. else
  222. {
  223. hr = ((ICertConfig *) pdiConfig->pUnknown)->GetField(strField, pstr);
  224. _JumpIfErrorNotSpecific(
  225. hr,
  226. error,
  227. "ICertConfig::GetField",
  228. CERTSRV_E_PROPERTY_EMPTY);
  229. }
  230. hr = S_OK;
  231. error:
  232. if (NULL != strField)
  233. {
  234. SysFreeString(strField);
  235. }
  236. return(hr);
  237. }
  238. HRESULT
  239. Config_GetConfig(
  240. IN DISPATCHINTERFACE *pdiConfig,
  241. IN LONG Flags,
  242. OUT BSTR *pstrConfig)
  243. {
  244. HRESULT hr;
  245. CSASSERT(NULL != pdiConfig && NULL != pdiConfig->pDispatchTable);
  246. if (NULL != pdiConfig->pDispatch)
  247. {
  248. VARIANT avar[1];
  249. avar[0].vt = VT_I4;
  250. avar[0].lVal = Flags;
  251. hr = DispatchInvoke(
  252. pdiConfig,
  253. CONFIG_GETCONFIG,
  254. ARRAYSIZE(avar),
  255. avar,
  256. VT_BSTR,
  257. pstrConfig);
  258. _JumpIfError(hr, error, "Invoke(GetConfig)");
  259. }
  260. else
  261. {
  262. hr = ((ICertConfig *) pdiConfig->pUnknown)->GetConfig(Flags, pstrConfig);
  263. _JumpIfError(hr, error, "ICertConfig::GetConfig");
  264. }
  265. error:
  266. return(hr);
  267. }
  268. HRESULT
  269. Config2_SetSharedFolder(
  270. IN DISPATCHINTERFACE *pdiConfig,
  271. IN WCHAR const *pwszSharedFolder)
  272. {
  273. HRESULT hr;
  274. BSTR strSharedFolder = NULL;
  275. CSASSERT(NULL != pdiConfig && NULL != pdiConfig->pDispatchTable);
  276. hr = ConfigVerifyVersion(pdiConfig, 2);
  277. _JumpIfError(hr, error, "ConfigVerifyVersion");
  278. if (!ConvertWszToBstr(&strSharedFolder, pwszSharedFolder, -1))
  279. {
  280. hr = E_OUTOFMEMORY;
  281. _JumpError(hr, error, "ConvertWszToBstr");
  282. }
  283. //wprintf(L"str=%ws, len=%u\n", strSharedFolder, ((ULONG *) strSharedFolder)[-1]);
  284. if (NULL != pdiConfig->pDispatch)
  285. {
  286. VARIANT avar[1];
  287. avar[0].vt = VT_BSTR;
  288. avar[0].bstrVal = strSharedFolder;
  289. hr = DispatchInvoke(
  290. pdiConfig,
  291. CONFIG2_SETSHAREDFOLDER,
  292. ARRAYSIZE(avar),
  293. avar,
  294. 0,
  295. NULL);
  296. _JumpIfError(hr, error, "Invoke(SetSharedFolder)");
  297. }
  298. else
  299. {
  300. hr = ((ICertConfig2 *) pdiConfig->pUnknown)->SetSharedFolder(strSharedFolder);
  301. _JumpIfError(hr, error, "ICertConfig::GetConfig");
  302. }
  303. error:
  304. if (NULL != strSharedFolder)
  305. {
  306. SysFreeString(strSharedFolder);
  307. }
  308. return(hr);
  309. }
  310. WCHAR const * const s_apwszFieldNames[] = {
  311. wszCONFIG_COMMONNAME,
  312. wszCONFIG_ORGUNIT,
  313. wszCONFIG_ORGANIZATION,
  314. wszCONFIG_LOCALITY,
  315. wszCONFIG_STATE,
  316. wszCONFIG_COUNTRY,
  317. wszCONFIG_CONFIG,
  318. wszCONFIG_EXCHANGECERTIFICATE,
  319. wszCONFIG_SIGNATURECERTIFICATE,
  320. wszCONFIG_DESCRIPTION,
  321. wszCONFIG_SERVER,
  322. wszCONFIG_AUTHORITY,
  323. wszCONFIG_SANITIZEDNAME,
  324. wszCONFIG_SHORTNAME,
  325. wszCONFIG_SANITIZEDSHORTNAME,
  326. wszCONFIG_FLAGS,
  327. };
  328. #define CSTRING (sizeof(s_apwszFieldNames)/sizeof(s_apwszFieldNames[0]))
  329. WCHAR const *s_apwszDisplayNames[CSTRING] = {
  330. wszCONFIG_COMMONNAME L":",
  331. wszCONFIG_ORGUNIT L":",
  332. wszCONFIG_ORGANIZATION L":",
  333. wszCONFIG_LOCALITY L":",
  334. wszCONFIG_STATE L":",
  335. wszCONFIG_COUNTRY L":",
  336. wszCONFIG_CONFIG L":",
  337. wszCONFIG_EXCHANGECERTIFICATE L":",
  338. wszCONFIG_SIGNATURECERTIFICATE L":",
  339. wszCONFIG_DESCRIPTION L":",
  340. wszCONFIG_SERVER L":",
  341. wszCONFIG_AUTHORITY L":",
  342. wszCONFIG_SANITIZEDNAME L":",
  343. wszCONFIG_SHORTNAME L":",
  344. wszCONFIG_SANITIZEDSHORTNAME L":",
  345. wszCONFIG_FLAGS L":",
  346. };
  347. HRESULT
  348. ConfigDumpSetDisplayNames(
  349. IN WCHAR const * const *apwszFieldNames,
  350. IN WCHAR const * const *apwszDisplayNames,
  351. IN DWORD cNames)
  352. {
  353. DWORD i;
  354. DWORD j;
  355. HRESULT hr;
  356. for (i = 0; i < cNames; i++)
  357. {
  358. for (j = 0; j < CSTRING; j++)
  359. {
  360. if (0 == mylstrcmpiS(s_apwszFieldNames[j], apwszFieldNames[i]) ||
  361. (0 == LSTRCMPIS(s_apwszFieldNames[j], wszCONFIG_DESCRIPTION) &&
  362. 0 == LSTRCMPIS(apwszFieldNames[i], wszCONFIG_COMMENT)))
  363. {
  364. s_apwszDisplayNames[j] = apwszDisplayNames[i];
  365. break;
  366. }
  367. }
  368. if (CSTRING <= j)
  369. {
  370. hr = E_INVALIDARG;
  371. _JumpErrorStr(hr, error, "column name", apwszFieldNames[i]);
  372. }
  373. }
  374. hr = S_OK;
  375. error:
  376. return(hr);
  377. }
  378. HRESULT
  379. ConfigDumpEntry(
  380. IN DISPATCHINTERFACE *pdiConfig,
  381. IN WCHAR const *pwszEntry, // localized L"Entry"
  382. IN LONG Index, // less than 0 skip index, entry, & suffix print
  383. OPTIONAL IN WCHAR const *pwszSuffix)
  384. {
  385. HRESULT hr;
  386. DWORD i;
  387. BSTR strings[CSTRING];
  388. for (i = 0; i < CSTRING; i++)
  389. {
  390. strings[i] = NULL;
  391. }
  392. for (i = 0; i < CSTRING; i++)
  393. {
  394. hr = Config_GetField(pdiConfig, s_apwszFieldNames[i], &strings[i]);
  395. _JumpIfError(hr, error, "Config_GetField");
  396. }
  397. if (-1 < Index)
  398. {
  399. myConsolePrintf(
  400. L"%ws%ws %u:%ws%ws\n",
  401. 0 == Index? L"" : L"\n",
  402. pwszEntry,
  403. Index,
  404. NULL != pwszSuffix? L" " : L"",
  405. NULL != pwszSuffix? pwszSuffix : L"");
  406. }
  407. for (i = 0; i < CSTRING; i++)
  408. {
  409. myConsolePrintf(L" ");
  410. myConsolePrintString(24, s_apwszDisplayNames[i]);
  411. myConsolePrintf(L"\t`");
  412. if (0 != wcscmp(s_apwszFieldNames[i], L"ExchangeCertificate"))
  413. {
  414. if (NULL != strings[i])
  415. {
  416. myConsolePrintf(L"%ws", strings[i]);
  417. }
  418. }
  419. myConsolePrintf(L"'\n");
  420. }
  421. hr = S_OK;
  422. error:
  423. for (i = 0; i < CSTRING; i++)
  424. {
  425. if (NULL != strings[i])
  426. {
  427. SysFreeString(strings[i]);
  428. }
  429. }
  430. return(hr);
  431. }
  432. HRESULT
  433. ConfigDump(
  434. IN DWORD Flags, // See DispatchSetup() Flags
  435. IN WCHAR const *pwszEntry, // localized L"Entry"
  436. OPTIONAL IN WCHAR const *pwszLocalSuffix, // localized L"(Local)"
  437. OPTIONAL IN WCHAR const *pwszMach1,
  438. OPTIONAL IN WCHAR const *pwszMach2)
  439. {
  440. HRESULT hr;
  441. LONG i;
  442. LONG count;
  443. LONG Index;
  444. BSTR strServer = NULL;
  445. WCHAR const *pwszSuffix;
  446. DISPATCHINTERFACE diConfig;
  447. hr = Config_Init(Flags, &diConfig);
  448. _JumpIfError(hr, error, "Config_Init");
  449. hr = Config_Reset(&diConfig, 0, &count);
  450. _JumpIfError(hr, error, "Config_Reset");
  451. Index = 0;
  452. for (i = 0; i < count; i++)
  453. {
  454. hr = Config_Next(&diConfig, &Index);
  455. if (S_OK != hr && S_FALSE != hr)
  456. {
  457. _JumpError(hr, error, "Config_Next");
  458. }
  459. hr = S_OK;
  460. if (-1 == Index)
  461. {
  462. break;
  463. }
  464. pwszSuffix = NULL;
  465. if (NULL != pwszLocalSuffix)
  466. {
  467. hr = Config_GetField(&diConfig, wszCONFIG_SERVER, &strServer);
  468. _JumpIfError(hr, error, "Config_GetField");
  469. if ((NULL != pwszMach1 && 0 == mylstrcmpiL(strServer, pwszMach1)) ||
  470. (NULL != pwszMach2 && 0 == mylstrcmpiL(strServer, pwszMach2)))
  471. {
  472. pwszSuffix = pwszLocalSuffix;
  473. }
  474. }
  475. hr = ConfigDumpEntry(&diConfig, pwszEntry, Index, pwszSuffix);
  476. _JumpIfError(hr, error, "ConfigDumpEntry");
  477. }
  478. error:
  479. if (NULL != strServer)
  480. {
  481. SysFreeString(strServer);
  482. }
  483. Config_Release(&diConfig);
  484. return(hr);
  485. }
  486. HRESULT
  487. ConfigGetConfig(
  488. IN DWORD Flags,
  489. IN DWORD dwUIFlag,
  490. OUT BSTR *pstrConfig)
  491. {
  492. HRESULT hr;
  493. DISPATCHINTERFACE diConfig;
  494. hr = Config_Init(Flags, &diConfig);
  495. _JumpIfError(hr, error, "Config_Init");
  496. hr = Config_GetConfig(&diConfig, dwUIFlag, pstrConfig);
  497. _JumpIfError(hr, error, "Config_GetConfig");
  498. error:
  499. Config_Release(&diConfig);
  500. return(hr);
  501. }
  502. DWORD
  503. myGetDisplayLength(
  504. IN WCHAR const *pwsz)
  505. {
  506. HRESULT hr;
  507. LONG ccol;
  508. CSASSERT(NULL != pwsz);
  509. ccol = WideCharToMultiByte(
  510. GetACP(), // CodePage
  511. 0, // dwFlags
  512. pwsz, // lpWideCharStr
  513. -1, // cchWideChar, -1 => L'\0' terminated
  514. NULL, // lpMultiByteStr
  515. 0, // cbMultiByte
  516. NULL, // lpDefaultChar
  517. NULL); // lpUsedDefaultChar
  518. if (0 >= ccol)
  519. {
  520. if (0 > ccol || L'\0' != *pwsz)
  521. {
  522. hr = myHLastError();
  523. _PrintError(hr, "WideCharToMultiByte");
  524. }
  525. ccol = wcslen(pwsz);
  526. }
  527. else
  528. {
  529. ccol--; // don't include trailing L'\0'
  530. }
  531. //error:
  532. return(ccol);
  533. }
  534. LONG
  535. myConsolePrintString(
  536. IN DWORD ccolMin,
  537. IN WCHAR const *pwszString)
  538. {
  539. DWORD ccolDisplay;
  540. DWORD ccolRet;
  541. ccolRet = myGetDisplayLength(pwszString);
  542. ccolDisplay = ccolRet;
  543. if (ccolMin < ccolDisplay)
  544. {
  545. ccolDisplay = ccolMin;
  546. }
  547. myConsolePrintf(L"%ws%*ws", pwszString, ccolMin - ccolDisplay, L"");
  548. return(ccolRet);
  549. }
  550. static BOOL s_fConsolePrintfDisable = FALSE;
  551. BOOL
  552. myConsolePrintfDisable(
  553. IN BOOL fDisable)
  554. {
  555. BOOL fDisableOld = s_fConsolePrintfDisable;
  556. s_fConsolePrintfDisable = fDisable;
  557. return(fDisableOld);
  558. }
  559. // Fall back to stdio if s_fConsolePrintfDisable is set OR
  560. // if _vsnwprintf doesn't exist in ntdll.dll and msvcrt.dll OR
  561. // if we run out of memory allocating a working buffer.
  562. //
  563. // Otherwise:
  564. // if redirected, use WriteFile
  565. // if not redirected, use WriteConsole
  566. #define cwcBUFMIN 512
  567. #define cwcBUFMAX (64 * 1024)
  568. int __cdecl
  569. myConsolePrintf(
  570. OPTIONAL IN WCHAR const *pwszFmt,
  571. ...)
  572. {
  573. HRESULT hr;
  574. va_list pva;
  575. int cwc;
  576. DWORD cwcOut;
  577. HANDLE hStdOut;
  578. WCHAR wszBuf[cwcBUFMIN];
  579. WCHAR *pwszBuf = wszBuf;
  580. DWORD cwcBuf = ARRAYSIZE(wszBuf);
  581. CHAR szAnsi[2 * cwcBUFMIN];
  582. CHAR *pszAnsi = NULL;
  583. DWORD cchAnsi;
  584. BOOL fRedirected = FALSE;
  585. typedef int (__cdecl FN_VSNWPRINTF)(
  586. OUT wchar_t *,
  587. IN size_t,
  588. IN const wchar_t *,
  589. IN va_list);
  590. HMODULE hModule;
  591. static FN_VSNWPRINTF *s_pfn = NULL;
  592. if (NULL == pwszFmt)
  593. {
  594. pwszFmt = L"(null)";
  595. }
  596. if (L'\0' == *pwszFmt)
  597. {
  598. cwcOut = 0;
  599. goto error;
  600. }
  601. if (NULL == s_pfn)
  602. {
  603. hModule = GetModuleHandle(TEXT("ntdll.dll"));
  604. if (NULL != hModule)
  605. {
  606. s_pfn = (FN_VSNWPRINTF *) GetProcAddress(hModule, "_vsnwprintf");
  607. }
  608. if (NULL == s_pfn)
  609. {
  610. hModule = GetModuleHandle(TEXT("msvcrt.dll"));
  611. s_pfn = (FN_VSNWPRINTF *) GetProcAddress(hModule, "_vsnwprintf");
  612. }
  613. }
  614. hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  615. if (NULL == s_pfn || s_fConsolePrintfDisable)
  616. {
  617. hStdOut = INVALID_HANDLE_VALUE; // use stdio fallback
  618. }
  619. cwc = 0;
  620. if (INVALID_HANDLE_VALUE != hStdOut)
  621. {
  622. for (;;)
  623. {
  624. va_start(pva, pwszFmt);
  625. cwc = (*s_pfn)(pwszBuf, cwcBuf, pwszFmt, pva);
  626. va_end(pva);
  627. if (-1 != cwc)
  628. {
  629. break;
  630. }
  631. if (cwcBUFMAX <= cwcBuf)
  632. {
  633. _PrintError(
  634. HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW),
  635. "_vsnwprintf");
  636. hStdOut = INVALID_HANDLE_VALUE;
  637. break;
  638. }
  639. if (pwszBuf != wszBuf)
  640. {
  641. LocalFree(pwszBuf);
  642. }
  643. cwcBuf *= 2;
  644. if (cwcBUFMAX < cwcBuf)
  645. {
  646. cwcBuf = cwcBUFMAX;
  647. }
  648. pwszBuf = (WCHAR *) LocalAlloc(LMEM_FIXED, cwcBuf * sizeof(WCHAR));
  649. if (NULL == pwszBuf)
  650. {
  651. _PrintError(E_OUTOFMEMORY, "LocalAlloc");
  652. hStdOut = INVALID_HANDLE_VALUE;
  653. break;
  654. }
  655. }
  656. }
  657. if (INVALID_HANDLE_VALUE != hStdOut)
  658. {
  659. // time for output -- where are we going, to a file or the console?
  660. switch (~FILE_TYPE_REMOTE & GetFileType(hStdOut))
  661. {
  662. //case FILE_TYPE_PIPE:
  663. //case FILE_TYPE_DISK:
  664. default:
  665. // if redirected to a pipe or a file, don't use WriteConsole;
  666. // it drops redirected output on the floor
  667. fRedirected = TRUE;
  668. break;
  669. case FILE_TYPE_UNKNOWN:
  670. _PrintError2(
  671. E_UNEXPECTED,
  672. "GetFileType(FILE_TYPE_UNKNOWN)",
  673. E_UNEXPECTED);
  674. hStdOut = INVALID_HANDLE_VALUE;
  675. s_fConsolePrintfDisable = TRUE;
  676. break;
  677. case FILE_TYPE_CHAR:
  678. break;
  679. }
  680. }
  681. cwcOut = 0;
  682. if (INVALID_HANDLE_VALUE != hStdOut)
  683. {
  684. if (!fRedirected)
  685. {
  686. if (!WriteConsole(hStdOut, pwszBuf, cwc, &cwcOut, NULL))
  687. {
  688. hr = myHLastError();
  689. _PrintError(hr, "WriteConsole");
  690. hStdOut = INVALID_HANDLE_VALUE;
  691. }
  692. }
  693. else // WriteConsole is out of the question
  694. {
  695. DWORD cch;
  696. // Expand all \n chars to \r\n so the WriteFile ends up clean.
  697. // Alloc new buffer big enough to hold two bytes per WCHAR for
  698. // worst case MultiByte translation + inserted \r chars.
  699. cchAnsi = 2 * (cwc + 1);
  700. if (ARRAYSIZE(szAnsi) >= cchAnsi)
  701. {
  702. pszAnsi = szAnsi;
  703. }
  704. else
  705. {
  706. pszAnsi = (LPSTR) LocalAlloc(LMEM_FIXED, cchAnsi);
  707. if (NULL == pszAnsi)
  708. {
  709. _PrintError(E_OUTOFMEMORY, "LocalAlloc");
  710. hStdOut = INVALID_HANDLE_VALUE;
  711. }
  712. }
  713. cch = 0;
  714. if (INVALID_HANDLE_VALUE != hStdOut)
  715. {
  716. // if going to a file, we should not use console codepage, we
  717. // should use ANSI codepage OR write unicode & a unicode
  718. // filemarker at beginning of file.
  719. // Since we don't know if this is the first thing in the file,
  720. // let's go the ANSI route.
  721. cch = WideCharToMultiByte(
  722. GetACP(), // GetConsoleOutputCP(),
  723. 0,
  724. pwszBuf,
  725. cwc,
  726. pszAnsi,
  727. cchAnsi,
  728. NULL,
  729. NULL);
  730. if (0 == cch)
  731. {
  732. hr = myHLastError();
  733. _PrintError(hr, "WideCharToMultiByte");
  734. _PrintErrorStr(GetACP(), "WideCharToMultiByte", pwszBuf);
  735. hStdOut = INVALID_HANDLE_VALUE;
  736. }
  737. }
  738. if (INVALID_HANDLE_VALUE != hStdOut)
  739. {
  740. CHAR *pchWork = pszAnsi;
  741. DWORD cchOut;
  742. // expand all \n chars to \r\n
  743. cwcOut = cwc;
  744. for (unsigned int j = 0; j < cch; j++, pchWork++)
  745. {
  746. if (*pchWork == '\n')
  747. {
  748. // create a 1-char space before \n
  749. MoveMemory(&pchWork[1], pchWork, cch - j);
  750. // Fill with \r and skip past \r (this statement) and
  751. // \n (automatic via loop incr).
  752. *pchWork++ = '\r';
  753. j++;
  754. cch++; // write one more char for each \n
  755. }
  756. }
  757. CSASSERT(pchWork <= &pszAnsi[2 * cwc]);
  758. if (!WriteFile(hStdOut, pszAnsi, cch, &cchOut, NULL))
  759. {
  760. hr = myHLastError();
  761. _PrintError(hr, "WriteFile");
  762. if (E_HANDLE == hr)
  763. {
  764. hStdOut = INVALID_HANDLE_VALUE;
  765. s_fConsolePrintfDisable = TRUE;
  766. }
  767. else
  768. {
  769. // This is the only case we drop output on the floor.
  770. // Most likely cause is disk full, so stdio won't help.
  771. }
  772. }
  773. }
  774. } // else WriteConsole
  775. }
  776. if (INVALID_HANDLE_VALUE == hStdOut)
  777. {
  778. BOOL fRetried = FALSE;
  779. for (;;)
  780. {
  781. ALIGNIOB(stdout);
  782. va_start(pva, pwszFmt);
  783. hr = S_OK;
  784. __try
  785. {
  786. cwcOut = vfwprintf(stdout, pwszFmt, pva);
  787. }
  788. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  789. {
  790. cwcOut = MAXDWORD;
  791. DBGPRINT((
  792. DBG_SS_ERROR,
  793. "Exception %x: myConsolePrintf(%ws)",
  794. hr,
  795. pwszFmt));
  796. }
  797. va_end(pva);
  798. #pragma warning(push)
  799. #pragma warning(disable: 4127) // conditional expression is constant
  800. if (S_OK == hr || fRetried || !IOBUNALIGNED(stdout))
  801. #pragma warning(pop)
  802. {
  803. break;
  804. }
  805. fRetried = TRUE;
  806. }
  807. }
  808. error:
  809. if (NULL != pwszBuf && wszBuf != pwszBuf)
  810. {
  811. LocalFree(pwszBuf);
  812. }
  813. if (NULL != pszAnsi && szAnsi != pszAnsi)
  814. {
  815. LocalFree(pszAnsi);
  816. }
  817. return((int) cwcOut);
  818. }