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.

942 lines
24 KiB

  1. /************************************************************************
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name :
  4. utils.cpp
  5. Abstract :
  6. Utility functions for BITSADMIN
  7. Author :
  8. Mike Zoran mzoran May 2002.
  9. Revision History :
  10. Notes:
  11. ***********************************************************************/
  12. #include "bitsadmin.h"
  13. //
  14. // Globals
  15. //
  16. bool g_Shutdown = false;
  17. HANDLE g_MainThreadHandle = NULL;
  18. WCHAR* pComputerName;
  19. SmartManagerPointer g_Manager;
  20. bool bRawReturn = false;
  21. bool bWrap = true;
  22. bool bExplicitWrap = false;
  23. bool bConsoleInfoRetrieved = false;
  24. HANDLE hConsole;
  25. CRITICAL_SECTION CritSection;
  26. CONSOLE_SCREEN_BUFFER_INFO StartConsoleInfo;
  27. DWORD StartConsoleMode;
  28. BITSOUTStream bcout( STD_OUTPUT_HANDLE );
  29. BITSOUTStream bcerr( STD_ERROR_HANDLE );
  30. void BITSADMINSetThreadUILanguage()
  31. {
  32. LANGID LangId;
  33. switch (GetConsoleOutputCP())
  34. {
  35. case 932:
  36. LangId = MAKELANGID( LANG_JAPANESE, SUBLANG_DEFAULT );
  37. break;
  38. case 949:
  39. LangId = MAKELANGID( LANG_KOREAN, SUBLANG_KOREAN );
  40. break;
  41. case 936:
  42. LangId = MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED );
  43. break;
  44. case 950:
  45. LangId = MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL );
  46. break;
  47. default:
  48. LangId = PRIMARYLANGID(LANGIDFROMLCID( GetUserDefaultLCID() ));
  49. if (LangId == LANG_JAPANESE ||
  50. LangId == LANG_KOREAN ||
  51. LangId == LANG_CHINESE )
  52. {
  53. LangId = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
  54. }
  55. else
  56. {
  57. LangId = MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT );
  58. }
  59. break;
  60. }
  61. SetThreadLocale( MAKELCID(LangId, SORT_DEFAULT) );
  62. return;
  63. }
  64. void
  65. BITSOUTStream::OutputString( const WCHAR *RawString )
  66. {
  67. SIZE_T CurrentPos = 0;
  68. PollShutdown();
  69. if ( !RawString )
  70. RawString = L"NULL";
  71. while( RawString[ CurrentPos ] != '\0' )
  72. {
  73. if ( L'\n' == RawString[ CurrentPos ] )
  74. {
  75. Buffer[ BufferUsed++ ] = L'\x000D';
  76. Buffer[ BufferUsed++ ] = L'\x000A';
  77. CurrentPos++;
  78. FlushBuffer( true );
  79. }
  80. else if ( L'\t' == RawString[ CurrentPos ] )
  81. {
  82. // Tabs complicate things, flush them
  83. FlushBuffer();
  84. Buffer[ BufferUsed++ ] = RawString[ CurrentPos++ ];
  85. FlushBuffer();
  86. }
  87. else
  88. {
  89. Buffer[ BufferUsed++ ] = RawString[ CurrentPos++ ];
  90. if ( BufferUsed >= ( 4096 - 10 ) ) // keep a pad of 10 chars
  91. FlushBuffer();
  92. }
  93. }
  94. }
  95. void
  96. BITSOUTStream::FlushBuffer( bool HasNewLine )
  97. {
  98. if (!BufferUsed)
  99. return;
  100. if( GetFileType(Handle) == FILE_TYPE_CHAR )
  101. {
  102. DWORD CharsWritten;
  103. if ( bWrap )
  104. WriteConsoleW( Handle, Buffer, BufferUsed, &CharsWritten, 0);
  105. else
  106. {
  107. // The console code has what appears to be a bug in that it doesn't
  108. // handle the case were line wrapping is disabled and WriteConsoleW
  109. // is called. Need to manually handle the truncation.
  110. CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
  111. GetConsoleScreenBufferInfo( Handle, &ConsoleScreenBufferInfo );
  112. SHORT Columns = ( ConsoleScreenBufferInfo.dwSize.X - 1 ) -
  113. ( ConsoleScreenBufferInfo.dwCursorPosition.X );
  114. DWORD ActualChars = HasNewLine ? ( BufferUsed - 2 ) : BufferUsed;
  115. if ( Columns >= (INT32)ActualChars )
  116. WriteConsoleW( Handle, Buffer, BufferUsed, &CharsWritten, 0 );
  117. else
  118. {
  119. WriteConsoleW( Handle, Buffer, Columns, &CharsWritten, 0 );
  120. if ( HasNewLine )
  121. WriteConsoleW( Handle, Buffer + ActualChars, 2, &CharsWritten, 0 );
  122. }
  123. }
  124. }
  125. else
  126. {
  127. int ByteCount = WideCharToMultiByte( GetConsoleOutputCP(), 0, Buffer, BufferUsed, MBBuffer, sizeof(MBBuffer), 0, 0); // SEC-REVIEWED: 2002-03-21
  128. if ( ByteCount )
  129. {
  130. if ( MBBuffer[ByteCount-1] == '\0' )
  131. ByteCount--;
  132. DWORD BytesWritten;
  133. while( ByteCount )
  134. {
  135. if ( !WriteFile(Handle, MBBuffer, ByteCount, &BytesWritten, 0) ) // SEC-REVIEWED: 2002-03-21
  136. CheckHR( L"Unable to write to the output file",
  137. HRESULT_FROM_WIN32( GetLastError() ) );
  138. ByteCount -= BytesWritten;
  139. }
  140. }
  141. }
  142. BufferUsed = 0;
  143. }
  144. BITSOUTStream& operator<< (BITSOUTStream &s, const WCHAR * String )
  145. {
  146. s.OutputString( String );
  147. return s;
  148. }
  149. BITSOUTStream& operator<< (BITSOUTStream &s, UINT64 Number )
  150. {
  151. static WCHAR Buffer[256];
  152. if ( FAILED( StringCbPrintf( Buffer, sizeof(Buffer), L"%I64u", Number ) ) )
  153. return s;
  154. return ( s << Buffer );
  155. }
  156. WCHAR * HRESULTToString( HRESULT Hr )
  157. {
  158. static WCHAR ErrorCode[12];
  159. if ( FAILED( StringCbPrintf( ErrorCode, sizeof(ErrorCode), L"0x%8.8x", Hr ) ) )
  160. {
  161. ErrorCode[0] = '\0';
  162. }
  163. return ErrorCode;
  164. }
  165. BITSOUTStream& operator<< ( BITSOUTStream &s, AutoStringPointer & String )
  166. {
  167. return ( s << String.Get() );
  168. }
  169. BITSOUTStream& operator<< ( BITSOUTStream &s, GUID & guid )
  170. {
  171. WCHAR GUIDSTR[40];
  172. if (!StringFromGUID2( guid, GUIDSTR, 40 ))
  173. {
  174. bcout << L"Internal error converting guid to string.\n";
  175. throw AbortException(1);
  176. }
  177. return ( s << GUIDSTR );
  178. }
  179. BITSOUTStream& operator<< ( BITSOUTStream &s, FILETIME & filetime )
  180. {
  181. // Convert the time and date into a localized string.
  182. // If an error occures, ignore it and print ERROR instead
  183. if ( !filetime.dwLowDateTime && !filetime.dwHighDateTime )
  184. return ( s << L"UNKNOWN" );
  185. FILETIME localtime;
  186. FileTimeToLocalFileTime( &filetime, &localtime );
  187. SYSTEMTIME systemtime;
  188. FileTimeToSystemTime( &localtime, &systemtime );
  189. // Get the required date size
  190. int RequiredDateSize =
  191. GetDateFormatW(
  192. LOCALE_USER_DEFAULT,
  193. 0,
  194. &systemtime,
  195. NULL,
  196. NULL,
  197. 0 );
  198. if (!RequiredDateSize)
  199. return ( s << L"ERROR" );
  200. CAutoString DateBuffer( new WCHAR[ RequiredDateSize + 1 ]);
  201. // Actually retrieve the date
  202. int DateSize =
  203. GetDateFormatW( LOCALE_USER_DEFAULT,
  204. 0,
  205. &systemtime,
  206. NULL,
  207. DateBuffer.get(),
  208. RequiredDateSize );
  209. if (!DateSize)
  210. return ( s << L"ERROR" );
  211. // Get the required time size
  212. int RequiredTimeSize =
  213. GetTimeFormatW( LOCALE_USER_DEFAULT,
  214. 0,
  215. &systemtime,
  216. NULL,
  217. NULL,
  218. 0 );
  219. if (!RequiredTimeSize)
  220. return ( s << L"ERROR" );
  221. CAutoString TimeBuffer( new WCHAR[ RequiredTimeSize + 1 ]);
  222. int TimeSize =
  223. GetTimeFormatW( LOCALE_USER_DEFAULT,
  224. 0,
  225. &systemtime,
  226. NULL,
  227. TimeBuffer.get(),
  228. RequiredTimeSize );
  229. if (!TimeSize)
  230. return ( s << L"ERROR" );
  231. return ( s << DateBuffer.get() << L" " << TimeBuffer.get() );
  232. }
  233. BITSOUTStream& operator<< ( BITSOUTStream &s, BG_JOB_PROXY_USAGE ProxyUsage )
  234. {
  235. switch( ProxyUsage )
  236. {
  237. case BG_JOB_PROXY_USAGE_PRECONFIG:
  238. return (s << L"PRECONFIG");
  239. case BG_JOB_PROXY_USAGE_NO_PROXY:
  240. return (s << L"NO_PROXY");
  241. case BG_JOB_PROXY_USAGE_OVERRIDE:
  242. return (s << L"OVERRIDE");
  243. default:
  244. return (s << L"UNKNOWN");
  245. }
  246. }
  247. ULONG InputULONG( WCHAR *pText )
  248. {
  249. ULONG number;
  250. if ( 1 != swscanf( pText, L"%u", &number ) )
  251. {
  252. bcout << L"Invalid number.\n";
  253. throw AbortException(1);
  254. }
  255. return number;
  256. }
  257. BOOL
  258. LocalConvertStringSidToSid (
  259. IN PWSTR StringSid,
  260. OUT PSID *Sid,
  261. OUT PWSTR *End
  262. )
  263. /*++
  264. Routine Description:
  265. This routine will convert a string representation of a SID back into
  266. a sid. The expected format of the string is:
  267. "S-1-5-32-549"
  268. If a string in a different format or an incorrect or incomplete string
  269. is given, the operation is failed.
  270. The returned sid must be free via a call to LocalFree
  271. Arguments:
  272. StringSid - The string to be converted
  273. Sid - Where the created SID is to be returned
  274. End - Where in the string we stopped processing
  275. Return Value:
  276. TRUE - Success.
  277. FALSE - Failure. Additional information returned from GetLastError(). Errors set are:
  278. ERROR_SUCCESS indicates success
  279. ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput sid
  280. failed
  281. ERROR_INVALID_SID indicates that the given string did not represent a sid
  282. --*/
  283. {
  284. DWORD Err = ERROR_SUCCESS;
  285. UCHAR Revision, Subs;
  286. SID_IDENTIFIER_AUTHORITY IDAuth;
  287. PULONG SubAuth = NULL;
  288. PWSTR CurrEnd, Curr, Next;
  289. WCHAR Stub, *StubPtr = NULL;
  290. ULONG Index;
  291. INT gBase=10;
  292. INT lBase=10;
  293. ULONG Auto;
  294. if ( NULL == StringSid || NULL == Sid || NULL == End ) {
  295. SetLastError( ERROR_INVALID_PARAMETER );
  296. return( FALSE );
  297. }
  298. //
  299. // no need to check length because StringSid is NULL
  300. // and if the first char is NULL, it won't access the second char
  301. //
  302. if ( (*StringSid != L'S' && *StringSid != L's') ||
  303. *( StringSid + 1 ) != L'-' ) {
  304. //
  305. // string sid should always start with S-
  306. //
  307. SetLastError( ERROR_INVALID_SID );
  308. return( FALSE );
  309. }
  310. Curr = StringSid + 2;
  311. if ( (*Curr == L'0') &&
  312. ( *(Curr+1) == L'x' ||
  313. *(Curr+1) == L'X' ) ) {
  314. gBase = 16;
  315. }
  316. Revision = ( UCHAR )wcstol( Curr, &CurrEnd, gBase );
  317. if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
  318. //
  319. // no revision is provided, or invalid delimeter
  320. //
  321. SetLastError( ERROR_INVALID_SID );
  322. return( FALSE );
  323. }
  324. Curr = CurrEnd + 1;
  325. //
  326. // Count the number of characters in the indentifer authority...
  327. //
  328. Next = wcschr( Curr, L'-' );
  329. if ( (*Curr == L'0') &&
  330. ( *(Curr+1) == L'x' ||
  331. *(Curr+1) == L'X' ) ) {
  332. lBase = 16;
  333. } else {
  334. lBase = gBase;
  335. }
  336. Auto = wcstoul( Curr, &CurrEnd, lBase );
  337. if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
  338. //
  339. // no revision is provided, or invalid delimeter
  340. //
  341. SetLastError( ERROR_INVALID_SID );
  342. return( FALSE );
  343. }
  344. IDAuth.Value[0] = IDAuth.Value[1] = 0;
  345. IDAuth.Value[5] = ( UCHAR )Auto & 0xFF;
  346. IDAuth.Value[4] = ( UCHAR )(( Auto >> 8 ) & 0xFF );
  347. IDAuth.Value[3] = ( UCHAR )(( Auto >> 16 ) & 0xFF );
  348. IDAuth.Value[2] = ( UCHAR )(( Auto >> 24 ) & 0xFF );
  349. Curr = CurrEnd;
  350. //
  351. // Now, count the number of sub auths, at least one sub auth is required
  352. //
  353. Subs = 0;
  354. Next = Curr;
  355. //
  356. // We'll have to count our sub authoritys one character at a time,
  357. // since there are several deliminators that we can have...
  358. //
  359. while ( Next ) {
  360. if ( *Next == L'-' && *(Next-1) != L'-') {
  361. //
  362. // do not allow two continuous '-'s
  363. // We've found one!
  364. //
  365. Subs++;
  366. if ( (*(Next+1) == L'0') &&
  367. ( *(Next+2) == L'x' ||
  368. *(Next+2) == L'X' ) ) {
  369. //
  370. // this is hex indicator
  371. //
  372. Next += 2;
  373. }
  374. } else if ( *Next == SDDL_SEPERATORC || *Next == L'\0' ||
  375. *Next == SDDL_ACE_ENDC || *Next == L' ' ||
  376. ( *(Next+1) == SDDL_DELIMINATORC &&
  377. (*Next == L'G' || *Next == L'O' || *Next == L'S')) ) {
  378. //
  379. // space is a terminator too
  380. //
  381. if ( *( Next - 1 ) == L'-' ) {
  382. //
  383. // shouldn't allow a SID terminated with '-'
  384. //
  385. Err = ERROR_INVALID_SID;
  386. Next--;
  387. } else {
  388. Subs++;
  389. }
  390. *End = Next;
  391. break;
  392. } else if ( !iswxdigit( *Next ) ) {
  393. Err = ERROR_INVALID_SID;
  394. *End = Next;
  395. break;
  396. } else {
  397. //
  398. // Note: SID is also used as a owner or group
  399. //
  400. // Some of the tags (namely 'D' for Dacl) fall under the category of iswxdigit, so
  401. // if the current character is a character we care about and the next one is a
  402. // delminiator, we'll quit
  403. //
  404. if ( *Next == L'D' && *( Next + 1 ) == SDDL_DELIMINATORC ) {
  405. //
  406. // We'll also need to temporarily truncate the string to this length so
  407. // we don't accidentally include the character in one of the conversions
  408. //
  409. Stub = *Next;
  410. StubPtr = Next;
  411. *StubPtr = UNICODE_NULL;
  412. *End = Next;
  413. Subs++;
  414. break;
  415. }
  416. }
  417. Next++;
  418. }
  419. if ( Err == ERROR_SUCCESS ) {
  420. if ( Subs != 0 ) Subs--;
  421. if ( Subs != 0 ) {
  422. Curr++;
  423. SubAuth = ( PULONG )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Subs * sizeof( ULONG ) );
  424. if ( SubAuth == NULL ) {
  425. Err = ERROR_NOT_ENOUGH_MEMORY;
  426. } else {
  427. for ( Index = 0; Index < Subs; Index++ ) {
  428. if ( (*Curr == L'0') &&
  429. ( *(Curr+1) == L'x' ||
  430. *(Curr+1) == L'X' ) ) {
  431. lBase = 16;
  432. } else {
  433. lBase = gBase;
  434. }
  435. SubAuth[Index] = wcstoul( Curr, &CurrEnd, lBase );
  436. Curr = CurrEnd + 1;
  437. }
  438. }
  439. } else {
  440. Err = ERROR_INVALID_SID;
  441. }
  442. }
  443. //
  444. // Now, create the SID
  445. //
  446. if ( Err == ERROR_SUCCESS ) {
  447. *Sid = ( PSID )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  448. sizeof( SID ) + Subs * sizeof( ULONG ) );
  449. if ( *Sid == NULL ) {
  450. Err = ERROR_NOT_ENOUGH_MEMORY;
  451. } else {
  452. PISID ISid = ( PISID )*Sid;
  453. ISid->Revision = Revision;
  454. ISid->SubAuthorityCount = Subs;
  455. ISid->IdentifierAuthority = IDAuth;
  456. RtlCopyMemory( ISid->SubAuthority, SubAuth, Subs * sizeof( ULONG ) ); // SEC-REVIEWED: 2002-03-21
  457. }
  458. }
  459. LocalFree( SubAuth );
  460. //
  461. // Restore any character we may have stubbed out
  462. //
  463. if ( StubPtr ) {
  464. *StubPtr = Stub;
  465. }
  466. SetLastError( Err );
  467. return( Err == ERROR_SUCCESS );
  468. }
  469. BOOL
  470. AltConvertStringSidToSid(
  471. IN LPCWSTR StringSid,
  472. OUT PSID *Sid
  473. )
  474. /*++
  475. Routine Description:
  476. This routine converts a stringized SID into a valid, functional SID
  477. Arguments:
  478. StringSid - SID to be converted.
  479. Sid - Where the converted SID is returned. Buffer is allocated via LocalAlloc and should
  480. be free via LocalFree.
  481. Return Value:
  482. TRUE - Success
  483. FALSE - Failure
  484. Extended error status is available using GetLastError.
  485. ERROR_INVALID_PARAMETER - A NULL name was given
  486. ERROR_INVALID_SID - The format of the given sid was incorrect
  487. --*/
  488. {
  489. PWSTR End = NULL;
  490. BOOL ReturnValue = FALSE;
  491. PSID pSASid=NULL;
  492. ULONG Len=0;
  493. DWORD SaveCode=0;
  494. DWORD Err=0;
  495. if ( StringSid == NULL || Sid == NULL )
  496. {
  497. SetLastError( ERROR_INVALID_PARAMETER );
  498. return ReturnValue;
  499. }
  500. ReturnValue = LocalConvertStringSidToSid( ( PWSTR )StringSid, Sid, &End );
  501. if ( !ReturnValue )
  502. {
  503. SetLastError( ERROR_INVALID_PARAMETER );
  504. return ReturnValue;
  505. }
  506. if ( ( ULONG )( End - StringSid ) != wcslen( StringSid ) ) {
  507. SetLastError( ERROR_INVALID_SID );
  508. LocalFree( *Sid );
  509. *Sid = FALSE;
  510. ReturnValue = FALSE;
  511. } else {
  512. SetLastError(ERROR_SUCCESS);
  513. }
  514. return ReturnValue;
  515. }
  516. BITSOUTStream& operator<< ( BITSOUTStream &s, PrintSidString SidString )
  517. {
  518. // Convert the SID string into the user name
  519. // in domain\account format.
  520. // If an error occures, just return the SID string
  521. PSID pSid = NULL;
  522. BOOL bResult =
  523. AltConvertStringSidToSid(
  524. SidString.m_SidString,
  525. &pSid );
  526. if ( !bResult )
  527. {
  528. return ( s << SidString.m_SidString );
  529. }
  530. SID_NAME_USE NameUse;
  531. DWORD dwNameSize = 0;
  532. DWORD dwDomainSize = 0;
  533. bResult = LookupAccountSid(
  534. NULL,
  535. pSid,
  536. NULL,
  537. &dwNameSize,
  538. NULL,
  539. &dwDomainSize,
  540. &NameUse);
  541. if ( bResult ||
  542. ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) )
  543. {
  544. LocalFree( pSid );
  545. return ( s << SidString.m_SidString );
  546. }
  547. CAutoString pName( new WCHAR[ dwNameSize ] );
  548. CAutoString pDomain( new WCHAR[ dwDomainSize ] );
  549. bResult = LookupAccountSid(
  550. NULL,
  551. pSid,
  552. pName.get(),
  553. &dwNameSize,
  554. pDomain.get(),
  555. &dwDomainSize,
  556. &NameUse);
  557. if (!bResult)
  558. {
  559. LocalFree( pSid );
  560. return ( s << SidString.m_SidString );
  561. }
  562. LocalFree( pSid );
  563. return ( s << pDomain.get() << L"\\" << pName.get() );
  564. }
  565. void * _cdecl operator new( size_t Size )
  566. {
  567. void *Memory = CoTaskMemAlloc( Size );
  568. if ( !Memory )
  569. {
  570. bcout << L"Out of memory while allocating " << Size << L" bytes.\n";
  571. throw AbortException( (int)E_OUTOFMEMORY );
  572. }
  573. return Memory;
  574. }
  575. void _cdecl operator delete( void *Mem )
  576. {
  577. CoTaskMemFree( Mem );
  578. }
  579. void PollShutdown()
  580. {
  581. if ( g_Shutdown )
  582. throw AbortException( (DWORD)CONTROL_C_EXIT );
  583. }
  584. void ShutdownAPC( ULONG_PTR )
  585. {
  586. return;
  587. }
  588. void SignalShutdown( DWORD MilliTimeout )
  589. {
  590. g_Shutdown = true;
  591. // Queue a shutdown APC
  592. if ( g_MainThreadHandle )
  593. {
  594. QueueUserAPC( ShutdownAPC, g_MainThreadHandle, NULL );
  595. }
  596. Sleep( MilliTimeout );
  597. RestoreConsole();
  598. TerminateProcess( GetCurrentProcess(), (DWORD)CONTROL_C_EXIT );
  599. }
  600. void CheckHR( const WCHAR *pFailTxt, HRESULT Hr )
  601. {
  602. // Check error code for success, and exit
  603. // with a failure message if unsuccessfull.
  604. if ( !SUCCEEDED(Hr) ) {
  605. WCHAR ErrorCode[12];
  606. if ( SUCCEEDED( StringCbPrintf( ErrorCode, sizeof(ErrorCode), L"0x%8.8x", Hr ) ) )
  607. {
  608. bcout << pFailTxt << L" - " << ErrorCode << L"\n";
  609. WCHAR *pMessage = NULL;
  610. if ( FormatMessage(
  611. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  612. NULL,
  613. (DWORD)Hr,
  614. GetThreadLocale(),
  615. (WCHAR*)&pMessage,
  616. 0,
  617. NULL ) )
  618. {
  619. bcout << pMessage << L"\n";
  620. LocalFree( pMessage );
  621. }
  622. }
  623. throw AbortException( Hr );
  624. }
  625. }
  626. void SetupConsole()
  627. {
  628. if (!( GetFileType( bcout.GetHandle() ) == FILE_TYPE_CHAR ) )
  629. return;
  630. hConsole = bcout.GetHandle();
  631. if ( INVALID_HANDLE_VALUE == hConsole )
  632. CheckHR( L"Unable to get console handle", HRESULT_FROM_WIN32( GetLastError() ) );
  633. if (!GetConsoleScreenBufferInfo( hConsole, &StartConsoleInfo ) )
  634. CheckHR( L"Unable get setup console information", HRESULT_FROM_WIN32( GetLastError() ) );
  635. if (!GetConsoleMode( hConsole, &StartConsoleMode ) )
  636. CheckHR( L"Unable get setup console information", HRESULT_FROM_WIN32( GetLastError() ) );
  637. InitializeCriticalSection( &CritSection );
  638. bConsoleInfoRetrieved = true;
  639. EnterCriticalSection( &CritSection );
  640. DWORD NewConsoleMode = ( bWrap ) ?
  641. ( StartConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT ) :
  642. ( StartConsoleMode & ~ENABLE_WRAP_AT_EOL_OUTPUT );
  643. if (!SetConsoleMode( hConsole, NewConsoleMode ) )
  644. CheckHR( L"Unable set console mode", HRESULT_FROM_WIN32( GetLastError() ) );
  645. LeaveCriticalSection( &CritSection );
  646. }
  647. void ChangeConsoleMode()
  648. {
  649. EnterCriticalSection( &CritSection );
  650. DWORD NewConsoleMode = ( bWrap ) ?
  651. ( StartConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT ) :
  652. ( StartConsoleMode & ~ENABLE_WRAP_AT_EOL_OUTPUT );
  653. if (!SetConsoleMode( hConsole, NewConsoleMode ) )
  654. CheckHR( L"Unable set console mode", HRESULT_FROM_WIN32( GetLastError() ) );
  655. LeaveCriticalSection( &CritSection );
  656. }
  657. void RestoreConsole()
  658. {
  659. if ( bConsoleInfoRetrieved )
  660. {
  661. EnterCriticalSection( &CritSection );
  662. SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes );
  663. SetConsoleMode( hConsole, StartConsoleMode );
  664. // Do not unlock, since we shouldn't allow any more console attribute changes
  665. }
  666. }
  667. void ClearScreen()
  668. {
  669. COORD coordScreen = { 0, 0 };
  670. BOOL bSuccess;
  671. DWORD cCharsWritten;
  672. CONSOLE_SCREEN_BUFFER_INFO csbi;
  673. DWORD dwConSize;
  674. EnterCriticalSection( &CritSection );
  675. if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
  676. goto error;
  677. dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
  678. if (!FillConsoleOutputCharacter(hConsole, (WCHAR) ' ',
  679. dwConSize, coordScreen, &cCharsWritten))
  680. goto error;
  681. if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
  682. goto error;
  683. if (!FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
  684. dwConSize, coordScreen, &cCharsWritten))
  685. goto error;
  686. if (!SetConsoleCursorPosition(hConsole, coordScreen))
  687. goto error;
  688. LeaveCriticalSection( &CritSection );
  689. return;
  690. error:
  691. DWORD dwError = GetLastError();
  692. LeaveCriticalSection( &CritSection );
  693. CheckHR( L"Unable to clear the console window", HRESULT_FROM_WIN32( dwError ) );
  694. throw AbortException( dwError );
  695. }
  696. BITSOUTStream & operator<<( BITSOUTStream & s, AddIntensity )
  697. {
  698. if ( GetFileType( s.GetHandle() ) == FILE_TYPE_CHAR )
  699. {
  700. s.FlushBuffer();
  701. EnterCriticalSection( &CritSection );
  702. SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes | FOREGROUND_INTENSITY );
  703. LeaveCriticalSection( &CritSection );
  704. }
  705. return s;
  706. }
  707. BITSOUTStream & operator<<( BITSOUTStream & s, ResetIntensity )
  708. {
  709. if ( GetFileType( s.GetHandle() ) == FILE_TYPE_CHAR )
  710. {
  711. s.FlushBuffer();
  712. EnterCriticalSection( &CritSection );
  713. SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes );
  714. LeaveCriticalSection( &CritSection );
  715. }
  716. return s;
  717. }