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
942 lines
24 KiB
/************************************************************************
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
utils.cpp
|
|
|
|
Abstract :
|
|
|
|
Utility functions for BITSADMIN
|
|
|
|
Author :
|
|
|
|
Mike Zoran mzoran May 2002.
|
|
|
|
Revision History :
|
|
|
|
Notes:
|
|
|
|
***********************************************************************/
|
|
|
|
#include "bitsadmin.h"
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
bool g_Shutdown = false;
|
|
HANDLE g_MainThreadHandle = NULL;
|
|
|
|
WCHAR* pComputerName;
|
|
SmartManagerPointer g_Manager;
|
|
bool bRawReturn = false;
|
|
bool bWrap = true;
|
|
bool bExplicitWrap = false;
|
|
|
|
bool bConsoleInfoRetrieved = false;
|
|
HANDLE hConsole;
|
|
CRITICAL_SECTION CritSection;
|
|
CONSOLE_SCREEN_BUFFER_INFO StartConsoleInfo;
|
|
DWORD StartConsoleMode;
|
|
|
|
BITSOUTStream bcout( STD_OUTPUT_HANDLE );
|
|
BITSOUTStream bcerr( STD_ERROR_HANDLE );
|
|
|
|
|
|
void BITSADMINSetThreadUILanguage()
|
|
{
|
|
|
|
LANGID LangId;
|
|
|
|
switch (GetConsoleOutputCP())
|
|
{
|
|
case 932:
|
|
LangId = MAKELANGID( LANG_JAPANESE, SUBLANG_DEFAULT );
|
|
break;
|
|
case 949:
|
|
LangId = MAKELANGID( LANG_KOREAN, SUBLANG_KOREAN );
|
|
break;
|
|
case 936:
|
|
LangId = MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED );
|
|
break;
|
|
case 950:
|
|
LangId = MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL );
|
|
break;
|
|
default:
|
|
LangId = PRIMARYLANGID(LANGIDFROMLCID( GetUserDefaultLCID() ));
|
|
if (LangId == LANG_JAPANESE ||
|
|
LangId == LANG_KOREAN ||
|
|
LangId == LANG_CHINESE )
|
|
{
|
|
LangId = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
|
|
}
|
|
else
|
|
{
|
|
LangId = MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT );
|
|
}
|
|
break;
|
|
}
|
|
|
|
SetThreadLocale( MAKELCID(LangId, SORT_DEFAULT) );
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
BITSOUTStream::OutputString( const WCHAR *RawString )
|
|
{
|
|
SIZE_T CurrentPos = 0;
|
|
|
|
PollShutdown();
|
|
|
|
if ( !RawString )
|
|
RawString = L"NULL";
|
|
|
|
while( RawString[ CurrentPos ] != '\0' )
|
|
{
|
|
|
|
if ( L'\n' == RawString[ CurrentPos ] )
|
|
{
|
|
Buffer[ BufferUsed++ ] = L'\x000D';
|
|
Buffer[ BufferUsed++ ] = L'\x000A';
|
|
CurrentPos++;
|
|
FlushBuffer( true );
|
|
}
|
|
|
|
else if ( L'\t' == RawString[ CurrentPos ] )
|
|
{
|
|
// Tabs complicate things, flush them
|
|
FlushBuffer();
|
|
Buffer[ BufferUsed++ ] = RawString[ CurrentPos++ ];
|
|
FlushBuffer();
|
|
}
|
|
|
|
else
|
|
{
|
|
Buffer[ BufferUsed++ ] = RawString[ CurrentPos++ ];
|
|
|
|
if ( BufferUsed >= ( 4096 - 10 ) ) // keep a pad of 10 chars
|
|
FlushBuffer();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
BITSOUTStream::FlushBuffer( bool HasNewLine )
|
|
{
|
|
|
|
if (!BufferUsed)
|
|
return;
|
|
|
|
if( GetFileType(Handle) == FILE_TYPE_CHAR )
|
|
{
|
|
DWORD CharsWritten;
|
|
if ( bWrap )
|
|
WriteConsoleW( Handle, Buffer, BufferUsed, &CharsWritten, 0);
|
|
else
|
|
{
|
|
|
|
// The console code has what appears to be a bug in that it doesn't
|
|
// handle the case were line wrapping is disabled and WriteConsoleW
|
|
// is called. Need to manually handle the truncation.
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
|
|
GetConsoleScreenBufferInfo( Handle, &ConsoleScreenBufferInfo );
|
|
|
|
SHORT Columns = ( ConsoleScreenBufferInfo.dwSize.X - 1 ) -
|
|
( ConsoleScreenBufferInfo.dwCursorPosition.X );
|
|
|
|
DWORD ActualChars = HasNewLine ? ( BufferUsed - 2 ) : BufferUsed;
|
|
|
|
if ( Columns >= (INT32)ActualChars )
|
|
WriteConsoleW( Handle, Buffer, BufferUsed, &CharsWritten, 0 );
|
|
else
|
|
{
|
|
WriteConsoleW( Handle, Buffer, Columns, &CharsWritten, 0 );
|
|
if ( HasNewLine )
|
|
WriteConsoleW( Handle, Buffer + ActualChars, 2, &CharsWritten, 0 );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int ByteCount = WideCharToMultiByte( GetConsoleOutputCP(), 0, Buffer, BufferUsed, MBBuffer, sizeof(MBBuffer), 0, 0); // SEC-REVIEWED: 2002-03-21
|
|
if ( ByteCount )
|
|
{
|
|
|
|
if ( MBBuffer[ByteCount-1] == '\0' )
|
|
ByteCount--;
|
|
|
|
DWORD BytesWritten;
|
|
while( ByteCount )
|
|
{
|
|
|
|
if ( !WriteFile(Handle, MBBuffer, ByteCount, &BytesWritten, 0) ) // SEC-REVIEWED: 2002-03-21
|
|
CheckHR( L"Unable to write to the output file",
|
|
HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
ByteCount -= BytesWritten;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
BufferUsed = 0;
|
|
|
|
}
|
|
|
|
BITSOUTStream& operator<< (BITSOUTStream &s, const WCHAR * String )
|
|
{
|
|
s.OutputString( String );
|
|
return s;
|
|
}
|
|
|
|
BITSOUTStream& operator<< (BITSOUTStream &s, UINT64 Number )
|
|
{
|
|
static WCHAR Buffer[256];
|
|
if ( FAILED( StringCbPrintf( Buffer, sizeof(Buffer), L"%I64u", Number ) ) )
|
|
return s;
|
|
return ( s << Buffer );
|
|
}
|
|
|
|
WCHAR * HRESULTToString( HRESULT Hr )
|
|
{
|
|
static WCHAR ErrorCode[12];
|
|
if ( FAILED( StringCbPrintf( ErrorCode, sizeof(ErrorCode), L"0x%8.8x", Hr ) ) )
|
|
{
|
|
ErrorCode[0] = '\0';
|
|
}
|
|
|
|
return ErrorCode;
|
|
}
|
|
|
|
BITSOUTStream& operator<< ( BITSOUTStream &s, AutoStringPointer & String )
|
|
{
|
|
return ( s << String.Get() );
|
|
}
|
|
|
|
|
|
BITSOUTStream& operator<< ( BITSOUTStream &s, GUID & guid )
|
|
{
|
|
WCHAR GUIDSTR[40];
|
|
if (!StringFromGUID2( guid, GUIDSTR, 40 ))
|
|
{
|
|
bcout << L"Internal error converting guid to string.\n";
|
|
throw AbortException(1);
|
|
}
|
|
return ( s << GUIDSTR );
|
|
}
|
|
|
|
BITSOUTStream& operator<< ( BITSOUTStream &s, FILETIME & filetime )
|
|
{
|
|
|
|
// Convert the time and date into a localized string.
|
|
// If an error occures, ignore it and print ERROR instead
|
|
|
|
if ( !filetime.dwLowDateTime && !filetime.dwHighDateTime )
|
|
return ( s << L"UNKNOWN" );
|
|
|
|
FILETIME localtime;
|
|
FileTimeToLocalFileTime( &filetime, &localtime );
|
|
|
|
SYSTEMTIME systemtime;
|
|
FileTimeToSystemTime( &localtime, &systemtime );
|
|
|
|
// Get the required date size
|
|
int RequiredDateSize =
|
|
GetDateFormatW(
|
|
LOCALE_USER_DEFAULT,
|
|
0,
|
|
&systemtime,
|
|
NULL,
|
|
NULL,
|
|
0 );
|
|
|
|
if (!RequiredDateSize)
|
|
return ( s << L"ERROR" );
|
|
|
|
CAutoString DateBuffer( new WCHAR[ RequiredDateSize + 1 ]);
|
|
|
|
// Actually retrieve the date
|
|
|
|
int DateSize =
|
|
GetDateFormatW( LOCALE_USER_DEFAULT,
|
|
0,
|
|
&systemtime,
|
|
NULL,
|
|
DateBuffer.get(),
|
|
RequiredDateSize );
|
|
|
|
if (!DateSize)
|
|
return ( s << L"ERROR" );
|
|
|
|
// Get the required time size
|
|
int RequiredTimeSize =
|
|
GetTimeFormatW( LOCALE_USER_DEFAULT,
|
|
0,
|
|
&systemtime,
|
|
NULL,
|
|
NULL,
|
|
0 );
|
|
|
|
if (!RequiredTimeSize)
|
|
return ( s << L"ERROR" );
|
|
|
|
CAutoString TimeBuffer( new WCHAR[ RequiredTimeSize + 1 ]);
|
|
|
|
int TimeSize =
|
|
GetTimeFormatW( LOCALE_USER_DEFAULT,
|
|
0,
|
|
&systemtime,
|
|
NULL,
|
|
TimeBuffer.get(),
|
|
RequiredTimeSize );
|
|
|
|
if (!TimeSize)
|
|
return ( s << L"ERROR" );
|
|
|
|
return ( s << DateBuffer.get() << L" " << TimeBuffer.get() );
|
|
}
|
|
|
|
BITSOUTStream& operator<< ( BITSOUTStream &s, BG_JOB_PROXY_USAGE ProxyUsage )
|
|
{
|
|
switch( ProxyUsage )
|
|
{
|
|
case BG_JOB_PROXY_USAGE_PRECONFIG:
|
|
return (s << L"PRECONFIG");
|
|
case BG_JOB_PROXY_USAGE_NO_PROXY:
|
|
return (s << L"NO_PROXY");
|
|
case BG_JOB_PROXY_USAGE_OVERRIDE:
|
|
return (s << L"OVERRIDE");
|
|
default:
|
|
return (s << L"UNKNOWN");
|
|
}
|
|
}
|
|
|
|
ULONG InputULONG( WCHAR *pText )
|
|
{
|
|
ULONG number;
|
|
if ( 1 != swscanf( pText, L"%u", &number ) )
|
|
{
|
|
bcout << L"Invalid number.\n";
|
|
throw AbortException(1);
|
|
}
|
|
return number;
|
|
}
|
|
|
|
BOOL
|
|
LocalConvertStringSidToSid (
|
|
IN PWSTR StringSid,
|
|
OUT PSID *Sid,
|
|
OUT PWSTR *End
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will convert a string representation of a SID back into
|
|
a sid. The expected format of the string is:
|
|
"S-1-5-32-549"
|
|
If a string in a different format or an incorrect or incomplete string
|
|
is given, the operation is failed.
|
|
|
|
The returned sid must be free via a call to LocalFree
|
|
|
|
|
|
Arguments:
|
|
|
|
StringSid - The string to be converted
|
|
|
|
Sid - Where the created SID is to be returned
|
|
|
|
End - Where in the string we stopped processing
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success.
|
|
|
|
FALSE - Failure. Additional information returned from GetLastError(). Errors set are:
|
|
|
|
ERROR_SUCCESS indicates success
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput sid
|
|
failed
|
|
ERROR_INVALID_SID indicates that the given string did not represent a sid
|
|
|
|
--*/
|
|
{
|
|
DWORD Err = ERROR_SUCCESS;
|
|
UCHAR Revision, Subs;
|
|
SID_IDENTIFIER_AUTHORITY IDAuth;
|
|
PULONG SubAuth = NULL;
|
|
PWSTR CurrEnd, Curr, Next;
|
|
WCHAR Stub, *StubPtr = NULL;
|
|
ULONG Index;
|
|
INT gBase=10;
|
|
INT lBase=10;
|
|
ULONG Auto;
|
|
|
|
if ( NULL == StringSid || NULL == Sid || NULL == End ) {
|
|
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
//
|
|
// no need to check length because StringSid is NULL
|
|
// and if the first char is NULL, it won't access the second char
|
|
//
|
|
if ( (*StringSid != L'S' && *StringSid != L's') ||
|
|
*( StringSid + 1 ) != L'-' ) {
|
|
//
|
|
// string sid should always start with S-
|
|
//
|
|
SetLastError( ERROR_INVALID_SID );
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
Curr = StringSid + 2;
|
|
|
|
if ( (*Curr == L'0') &&
|
|
( *(Curr+1) == L'x' ||
|
|
*(Curr+1) == L'X' ) ) {
|
|
|
|
gBase = 16;
|
|
}
|
|
|
|
Revision = ( UCHAR )wcstol( Curr, &CurrEnd, gBase );
|
|
|
|
if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
|
|
//
|
|
// no revision is provided, or invalid delimeter
|
|
//
|
|
SetLastError( ERROR_INVALID_SID );
|
|
return( FALSE );
|
|
}
|
|
|
|
Curr = CurrEnd + 1;
|
|
|
|
//
|
|
// Count the number of characters in the indentifer authority...
|
|
//
|
|
Next = wcschr( Curr, L'-' );
|
|
|
|
if ( (*Curr == L'0') &&
|
|
( *(Curr+1) == L'x' ||
|
|
*(Curr+1) == L'X' ) ) {
|
|
|
|
lBase = 16;
|
|
} else {
|
|
lBase = gBase;
|
|
}
|
|
|
|
Auto = wcstoul( Curr, &CurrEnd, lBase );
|
|
|
|
if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
|
|
//
|
|
// no revision is provided, or invalid delimeter
|
|
//
|
|
SetLastError( ERROR_INVALID_SID );
|
|
return( FALSE );
|
|
}
|
|
|
|
IDAuth.Value[0] = IDAuth.Value[1] = 0;
|
|
IDAuth.Value[5] = ( UCHAR )Auto & 0xFF;
|
|
IDAuth.Value[4] = ( UCHAR )(( Auto >> 8 ) & 0xFF );
|
|
IDAuth.Value[3] = ( UCHAR )(( Auto >> 16 ) & 0xFF );
|
|
IDAuth.Value[2] = ( UCHAR )(( Auto >> 24 ) & 0xFF );
|
|
Curr = CurrEnd;
|
|
|
|
//
|
|
// Now, count the number of sub auths, at least one sub auth is required
|
|
//
|
|
Subs = 0;
|
|
Next = Curr;
|
|
|
|
//
|
|
// We'll have to count our sub authoritys one character at a time,
|
|
// since there are several deliminators that we can have...
|
|
//
|
|
|
|
while ( Next ) {
|
|
|
|
if ( *Next == L'-' && *(Next-1) != L'-') {
|
|
|
|
//
|
|
// do not allow two continuous '-'s
|
|
// We've found one!
|
|
//
|
|
Subs++;
|
|
|
|
if ( (*(Next+1) == L'0') &&
|
|
( *(Next+2) == L'x' ||
|
|
*(Next+2) == L'X' ) ) {
|
|
//
|
|
// this is hex indicator
|
|
//
|
|
Next += 2;
|
|
|
|
}
|
|
|
|
} else if ( *Next == SDDL_SEPERATORC || *Next == L'\0' ||
|
|
*Next == SDDL_ACE_ENDC || *Next == L' ' ||
|
|
( *(Next+1) == SDDL_DELIMINATORC &&
|
|
(*Next == L'G' || *Next == L'O' || *Next == L'S')) ) {
|
|
//
|
|
// space is a terminator too
|
|
//
|
|
if ( *( Next - 1 ) == L'-' ) {
|
|
//
|
|
// shouldn't allow a SID terminated with '-'
|
|
//
|
|
Err = ERROR_INVALID_SID;
|
|
Next--;
|
|
|
|
} else {
|
|
Subs++;
|
|
}
|
|
|
|
*End = Next;
|
|
break;
|
|
|
|
} else if ( !iswxdigit( *Next ) ) {
|
|
|
|
Err = ERROR_INVALID_SID;
|
|
*End = Next;
|
|
break;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Note: SID is also used as a owner or group
|
|
//
|
|
// Some of the tags (namely 'D' for Dacl) fall under the category of iswxdigit, so
|
|
// if the current character is a character we care about and the next one is a
|
|
// delminiator, we'll quit
|
|
//
|
|
if ( *Next == L'D' && *( Next + 1 ) == SDDL_DELIMINATORC ) {
|
|
|
|
//
|
|
// We'll also need to temporarily truncate the string to this length so
|
|
// we don't accidentally include the character in one of the conversions
|
|
//
|
|
Stub = *Next;
|
|
StubPtr = Next;
|
|
*StubPtr = UNICODE_NULL;
|
|
*End = Next;
|
|
Subs++;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
Next++;
|
|
|
|
}
|
|
|
|
if ( Err == ERROR_SUCCESS ) {
|
|
|
|
if ( Subs != 0 ) Subs--;
|
|
|
|
if ( Subs != 0 ) {
|
|
|
|
Curr++;
|
|
|
|
SubAuth = ( PULONG )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Subs * sizeof( ULONG ) );
|
|
|
|
if ( SubAuth == NULL ) {
|
|
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
for ( Index = 0; Index < Subs; Index++ ) {
|
|
|
|
if ( (*Curr == L'0') &&
|
|
( *(Curr+1) == L'x' ||
|
|
*(Curr+1) == L'X' ) ) {
|
|
|
|
lBase = 16;
|
|
} else {
|
|
lBase = gBase;
|
|
}
|
|
|
|
SubAuth[Index] = wcstoul( Curr, &CurrEnd, lBase );
|
|
Curr = CurrEnd + 1;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
Err = ERROR_INVALID_SID;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, create the SID
|
|
//
|
|
if ( Err == ERROR_SUCCESS ) {
|
|
|
|
*Sid = ( PSID )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof( SID ) + Subs * sizeof( ULONG ) );
|
|
|
|
if ( *Sid == NULL ) {
|
|
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
PISID ISid = ( PISID )*Sid;
|
|
ISid->Revision = Revision;
|
|
ISid->SubAuthorityCount = Subs;
|
|
ISid->IdentifierAuthority = IDAuth;
|
|
RtlCopyMemory( ISid->SubAuthority, SubAuth, Subs * sizeof( ULONG ) ); // SEC-REVIEWED: 2002-03-21
|
|
}
|
|
}
|
|
|
|
LocalFree( SubAuth );
|
|
|
|
//
|
|
// Restore any character we may have stubbed out
|
|
//
|
|
if ( StubPtr ) {
|
|
|
|
*StubPtr = Stub;
|
|
}
|
|
|
|
SetLastError( Err );
|
|
|
|
return( Err == ERROR_SUCCESS );
|
|
}
|
|
|
|
BOOL
|
|
AltConvertStringSidToSid(
|
|
IN LPCWSTR StringSid,
|
|
OUT PSID *Sid
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a stringized SID into a valid, functional SID
|
|
|
|
Arguments:
|
|
|
|
StringSid - SID to be converted.
|
|
|
|
Sid - Where the converted SID is returned. Buffer is allocated via LocalAlloc and should
|
|
be free via LocalFree.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure
|
|
|
|
Extended error status is available using GetLastError.
|
|
|
|
ERROR_INVALID_PARAMETER - A NULL name was given
|
|
|
|
ERROR_INVALID_SID - The format of the given sid was incorrect
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR End = NULL;
|
|
BOOL ReturnValue = FALSE;
|
|
PSID pSASid=NULL;
|
|
ULONG Len=0;
|
|
DWORD SaveCode=0;
|
|
DWORD Err=0;
|
|
|
|
if ( StringSid == NULL || Sid == NULL )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return ReturnValue;
|
|
}
|
|
|
|
ReturnValue = LocalConvertStringSidToSid( ( PWSTR )StringSid, Sid, &End );
|
|
|
|
if ( !ReturnValue )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return ReturnValue;
|
|
}
|
|
|
|
if ( ( ULONG )( End - StringSid ) != wcslen( StringSid ) ) {
|
|
|
|
SetLastError( ERROR_INVALID_SID );
|
|
LocalFree( *Sid );
|
|
*Sid = FALSE;
|
|
ReturnValue = FALSE;
|
|
|
|
} else {
|
|
SetLastError(ERROR_SUCCESS);
|
|
}
|
|
|
|
return ReturnValue;
|
|
|
|
}
|
|
|
|
BITSOUTStream& operator<< ( BITSOUTStream &s, PrintSidString SidString )
|
|
{
|
|
|
|
// Convert the SID string into the user name
|
|
// in domain\account format.
|
|
// If an error occures, just return the SID string
|
|
|
|
PSID pSid = NULL;
|
|
BOOL bResult =
|
|
AltConvertStringSidToSid(
|
|
SidString.m_SidString,
|
|
&pSid );
|
|
|
|
if ( !bResult )
|
|
{
|
|
return ( s << SidString.m_SidString );
|
|
}
|
|
|
|
SID_NAME_USE NameUse;
|
|
DWORD dwNameSize = 0;
|
|
DWORD dwDomainSize = 0;
|
|
bResult = LookupAccountSid(
|
|
NULL,
|
|
pSid,
|
|
NULL,
|
|
&dwNameSize,
|
|
NULL,
|
|
&dwDomainSize,
|
|
&NameUse);
|
|
|
|
if ( bResult ||
|
|
( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) )
|
|
{
|
|
LocalFree( pSid );
|
|
return ( s << SidString.m_SidString );
|
|
}
|
|
|
|
CAutoString pName( new WCHAR[ dwNameSize ] );
|
|
CAutoString pDomain( new WCHAR[ dwDomainSize ] );
|
|
|
|
bResult = LookupAccountSid(
|
|
NULL,
|
|
pSid,
|
|
pName.get(),
|
|
&dwNameSize,
|
|
pDomain.get(),
|
|
&dwDomainSize,
|
|
&NameUse);
|
|
|
|
if (!bResult)
|
|
{
|
|
LocalFree( pSid );
|
|
return ( s << SidString.m_SidString );
|
|
}
|
|
|
|
LocalFree( pSid );
|
|
return ( s << pDomain.get() << L"\\" << pName.get() );
|
|
|
|
}
|
|
|
|
void * _cdecl operator new( size_t Size )
|
|
{
|
|
void *Memory = CoTaskMemAlloc( Size );
|
|
|
|
if ( !Memory )
|
|
{
|
|
bcout << L"Out of memory while allocating " << Size << L" bytes.\n";
|
|
throw AbortException( (int)E_OUTOFMEMORY );
|
|
}
|
|
|
|
return Memory;
|
|
}
|
|
|
|
void _cdecl operator delete( void *Mem )
|
|
{
|
|
CoTaskMemFree( Mem );
|
|
}
|
|
|
|
void PollShutdown()
|
|
{
|
|
if ( g_Shutdown )
|
|
throw AbortException( (DWORD)CONTROL_C_EXIT );
|
|
}
|
|
|
|
|
|
void ShutdownAPC( ULONG_PTR )
|
|
{
|
|
return;
|
|
}
|
|
|
|
void SignalShutdown( DWORD MilliTimeout )
|
|
{
|
|
g_Shutdown = true;
|
|
|
|
// Queue a shutdown APC
|
|
|
|
if ( g_MainThreadHandle )
|
|
{
|
|
QueueUserAPC( ShutdownAPC, g_MainThreadHandle, NULL );
|
|
}
|
|
|
|
Sleep( MilliTimeout );
|
|
RestoreConsole();
|
|
TerminateProcess( GetCurrentProcess(), (DWORD)CONTROL_C_EXIT );
|
|
}
|
|
|
|
|
|
|
|
void CheckHR( const WCHAR *pFailTxt, HRESULT Hr )
|
|
{
|
|
|
|
// Check error code for success, and exit
|
|
// with a failure message if unsuccessfull.
|
|
|
|
if ( !SUCCEEDED(Hr) ) {
|
|
WCHAR ErrorCode[12];
|
|
|
|
if ( SUCCEEDED( StringCbPrintf( ErrorCode, sizeof(ErrorCode), L"0x%8.8x", Hr ) ) )
|
|
{
|
|
|
|
bcout << pFailTxt << L" - " << ErrorCode << L"\n";
|
|
|
|
WCHAR *pMessage = NULL;
|
|
|
|
if ( FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
(DWORD)Hr,
|
|
GetThreadLocale(),
|
|
(WCHAR*)&pMessage,
|
|
0,
|
|
NULL ) )
|
|
{
|
|
bcout << pMessage << L"\n";
|
|
LocalFree( pMessage );
|
|
}
|
|
|
|
}
|
|
|
|
throw AbortException( Hr );
|
|
}
|
|
}
|
|
|
|
void SetupConsole()
|
|
{
|
|
if (!( GetFileType( bcout.GetHandle() ) == FILE_TYPE_CHAR ) )
|
|
return;
|
|
|
|
hConsole = bcout.GetHandle();
|
|
if ( INVALID_HANDLE_VALUE == hConsole )
|
|
CheckHR( L"Unable to get console handle", HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
if (!GetConsoleScreenBufferInfo( hConsole, &StartConsoleInfo ) )
|
|
CheckHR( L"Unable get setup console information", HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
if (!GetConsoleMode( hConsole, &StartConsoleMode ) )
|
|
CheckHR( L"Unable get setup console information", HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
InitializeCriticalSection( &CritSection );
|
|
bConsoleInfoRetrieved = true;
|
|
|
|
EnterCriticalSection( &CritSection );
|
|
|
|
DWORD NewConsoleMode = ( bWrap ) ?
|
|
( StartConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT ) :
|
|
( StartConsoleMode & ~ENABLE_WRAP_AT_EOL_OUTPUT );
|
|
|
|
if (!SetConsoleMode( hConsole, NewConsoleMode ) )
|
|
CheckHR( L"Unable set console mode", HRESULT_FROM_WIN32( GetLastError() ) );
|
|
LeaveCriticalSection( &CritSection );
|
|
}
|
|
|
|
void ChangeConsoleMode()
|
|
{
|
|
|
|
EnterCriticalSection( &CritSection );
|
|
|
|
DWORD NewConsoleMode = ( bWrap ) ?
|
|
( StartConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT ) :
|
|
( StartConsoleMode & ~ENABLE_WRAP_AT_EOL_OUTPUT );
|
|
|
|
if (!SetConsoleMode( hConsole, NewConsoleMode ) )
|
|
CheckHR( L"Unable set console mode", HRESULT_FROM_WIN32( GetLastError() ) );
|
|
LeaveCriticalSection( &CritSection );
|
|
|
|
}
|
|
|
|
void RestoreConsole()
|
|
{
|
|
if ( bConsoleInfoRetrieved )
|
|
{
|
|
EnterCriticalSection( &CritSection );
|
|
SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes );
|
|
SetConsoleMode( hConsole, StartConsoleMode );
|
|
// Do not unlock, since we shouldn't allow any more console attribute changes
|
|
}
|
|
}
|
|
|
|
void ClearScreen()
|
|
{
|
|
COORD coordScreen = { 0, 0 };
|
|
BOOL bSuccess;
|
|
DWORD cCharsWritten;
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
DWORD dwConSize;
|
|
|
|
EnterCriticalSection( &CritSection );
|
|
if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
|
|
goto error;
|
|
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
|
|
if (!FillConsoleOutputCharacter(hConsole, (WCHAR) ' ',
|
|
dwConSize, coordScreen, &cCharsWritten))
|
|
goto error;
|
|
if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
|
|
goto error;
|
|
if (!FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
|
|
dwConSize, coordScreen, &cCharsWritten))
|
|
goto error;
|
|
if (!SetConsoleCursorPosition(hConsole, coordScreen))
|
|
goto error;
|
|
LeaveCriticalSection( &CritSection );
|
|
return;
|
|
|
|
error:
|
|
|
|
DWORD dwError = GetLastError();
|
|
LeaveCriticalSection( &CritSection );
|
|
CheckHR( L"Unable to clear the console window", HRESULT_FROM_WIN32( dwError ) );
|
|
throw AbortException( dwError );
|
|
}
|
|
|
|
|
|
BITSOUTStream & operator<<( BITSOUTStream & s, AddIntensity )
|
|
{
|
|
if ( GetFileType( s.GetHandle() ) == FILE_TYPE_CHAR )
|
|
{
|
|
s.FlushBuffer();
|
|
EnterCriticalSection( &CritSection );
|
|
SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes | FOREGROUND_INTENSITY );
|
|
LeaveCriticalSection( &CritSection );
|
|
}
|
|
return s;
|
|
}
|
|
|
|
BITSOUTStream & operator<<( BITSOUTStream & s, ResetIntensity )
|
|
{
|
|
if ( GetFileType( s.GetHandle() ) == FILE_TYPE_CHAR )
|
|
{
|
|
s.FlushBuffer();
|
|
EnterCriticalSection( &CritSection );
|
|
SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes );
|
|
LeaveCriticalSection( &CritSection );
|
|
}
|
|
return s;
|
|
}
|