plugins/consoles/win32cons/src/win32cons.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // win32cons.cpp
       
     2 // 
       
     3 // Copyright (c) 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 // os_version.h must be included before the windows headers
       
    14 // to ensure that _WIN32_WINNT has the right value
       
    15 #include "os_version.h"
       
    16 #include <stdio.h>
       
    17 #include <windows.h>
       
    18 #include <fcntl.h>
       
    19 #include <io.h>
       
    20 #include <emulator.h>
       
    21 #include "win32cons.h"
       
    22 #include "keymappings.h"
       
    23 
       
    24 //#define DEBUG_CONSOLE
       
    25 
       
    26 #ifdef DEBUG_CONSOLE
       
    27 #define CONS_DEBUG(x) x
       
    28 #else
       
    29 #define CONS_DEBUG(x)
       
    30 #endif
       
    31 
       
    32 inline int Min(int a, int b) {return a<b ? a : b;}
       
    33 inline int Max(int a, int b) {return a<b ? b : a;}
       
    34 
       
    35 #define WIN32_START() Emulator::Lock()
       
    36 #define WIN32_END() Emulator::Unlock()
       
    37 
       
    38 #define WIN32_CALL(x) { WIN32_START(); x; WIN32_END(); }
       
    39 
       
    40 int TWin32Console::AttachOrAllocConsole()
       
    41 	{
       
    42 	// NB The AttachConsole method is only available on WinXP and later
       
    43 	WIN32_START();
       
    44 #if _WIN32_WINNT >= 0x0501
       
    45 	if (!::AttachConsole(-1)) 
       
    46 		{
       
    47 		// no luck
       
    48 		int err = GetLastError();
       
    49 		if (err == ERROR_ACCESS_DENIED)
       
    50 			{
       
    51 			WIN32_END();
       
    52 			// we're already attached to a console (?) - continue.
       
    53 			}
       
    54 		else if (err == ERROR_INVALID_HANDLE)
       
    55 			{
       
    56 #endif
       
    57 			if (!AllocConsole())
       
    58 				{
       
    59 				WIN32_END();
       
    60 				return 0; //failed
       
    61 				}
       
    62 			WIN32_END();
       
    63 			CONS_DEBUG(DebugMsg("Allocated console"));
       
    64 #if _WIN32_WINNT >= 0x0501
       
    65 			}
       
    66 		else
       
    67 			{
       
    68 			WIN32_END();
       
    69 			CONS_DEBUG(DebugMsg("Failed to attach to console, error %d", err));
       
    70 			return 0;
       
    71 			}
       
    72 		}
       
    73 	else
       
    74 		{
       
    75 		int err = GetLastError();
       
    76 		WIN32_END();
       
    77 		CONS_DEBUG(DebugMsg("Attached console err %d", err));
       
    78 		}
       
    79 #endif
       
    80 	
       
    81 	iHaveConsole = true;
       
    82 	return 1;
       
    83 	}
       
    84 	
       
    85 bool TestHandle(void* aHandle, int* aError = NULL)
       
    86 	{
       
    87 	WIN32_START();
       
    88 	DWORD written;
       
    89 	bool r = WriteFile(aHandle, "", 0, &written, NULL);
       
    90 	if (aError) *aError = GetLastError();
       
    91 	WIN32_END();
       
    92 	return r;
       
    93 	}
       
    94 
       
    95 int TWin32Console::AttachConsole()
       
    96 	{
       
    97 	iHaveConsole = false;
       
    98 	// first, test the existing STDOUT and STDERR handles; if out output is being redirected to 
       
    99 	// a file, these will be valid as they stand.
       
   100 	WIN32_START();
       
   101 	iStdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
       
   102 	iStdErrHandle = GetStdHandle(STD_ERROR_HANDLE);
       
   103 	
       
   104 	// try writing to stdout to see if it's valid
       
   105 	int err;
       
   106 	bool ok = TestHandle(iStdOutHandle, &err);
       
   107 	WIN32_END();
       
   108 	
       
   109 	if (!ok && err == ERROR_INVALID_HANDLE)
       
   110 		{
       
   111 		// no redirection, so existing handle doesn't work. Attach to an existing console (if it exists)
       
   112 		// or create a new one (this will happen if we're invoked from the IDE, for example)
       
   113 		CONS_DEBUG(DebugMsg("Failed to write to existing STDOUT"));
       
   114 		err = AttachOrAllocConsole();
       
   115 		if (err==0) return err;
       
   116 		WIN32_CALL(iStdOutHandle =  GetStdHandle(STD_OUTPUT_HANDLE));
       
   117 		}
       
   118 	else if (!ok)
       
   119 		{
       
   120 		// some other error occurred, fail.
       
   121 		CONS_DEBUG(DebugMsg("Failed to write to existing STDOUT; error %d", err));
       
   122 		return 0;
       
   123 		}
       
   124 	else
       
   125 		{
       
   126 		CONS_DEBUG(DebugMsg("Using existing STDOUT"));
       
   127 		}
       
   128 		
       
   129 	// try writing to stderr to see if it's valid
       
   130 	ok = TestHandle(iStdErrHandle, &err);
       
   131 	if (!ok && err == ERROR_INVALID_HANDLE)
       
   132 		{
       
   133 		CONS_DEBUG(DebugMsg("Failed to write to existing STDERR"));
       
   134 		if (!iHaveConsole)
       
   135 			{
       
   136 			err = AttachOrAllocConsole();
       
   137 			if (err==0) return err;
       
   138 			}
       
   139 		else
       
   140 			{
       
   141 			CONS_DEBUG(DebugMsg("Already attached/alloc'd console"));
       
   142 			}
       
   143 		WIN32_CALL(iStdErrHandle = GetStdHandle(STD_ERROR_HANDLE));
       
   144 		CONS_DEBUG(DebugMsg("GetStdHandle(Stderr)=%d err=%d", iStdErrHandle, GetLastError()));
       
   145 		}
       
   146 	else if (!ok)
       
   147 		{
       
   148 		CONS_DEBUG(DebugMsg("Failed to write to existing STDERR; error %d", err));
       
   149 		return 0;
       
   150 		}
       
   151 	else
       
   152 		{
       
   153 		CONS_DEBUG(DebugMsg("Using existing STDERR"));
       
   154 		}
       
   155 		
       
   156 	// in some cases (such as when we're invoked by GNU make) the handle returned by GetStdHandle
       
   157 	// after attaching to a console doesn't work. In this case, open a new handle to the console
       
   158 	// using CreateFile
       
   159 	TInt lastError;
       
   160 	if (!TestHandle(iStdOutHandle, &lastError))
       
   161 		{
       
   162 		CONS_DEBUG(DebugMsg("Still can't write STDOUT; err %d; opening new console handle", lastError));
       
   163 		
       
   164 		WIN32_START();
       
   165 		iHaveConsole = false;
       
   166 		iStdOutHandle = CreateFile(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
       
   167 		int err = GetLastError();
       
   168 		WIN32_END();
       
   169 		CONS_DEBUG(DebugMsg("CreateFile handle = %d, err %d", iStdOutHandle, err));
       
   170 		if (!TestHandle(iStdOutHandle, &err))
       
   171 			{
       
   172 			CONS_DEBUG(DebugMsg("Still can't write STDOUT; err %d; giving up", err));
       
   173 			return 0;
       
   174 			}
       
   175 		}
       
   176 	
       
   177 	if (!TestHandle(iStdErrHandle, &lastError))
       
   178 		{
       
   179 		CONS_DEBUG(DebugMsg("Still can't write STDOUT; err %d; opening new console handle", GetLastError()));
       
   180 		
       
   181 		WIN32_START();
       
   182 		iHaveConsole = false;
       
   183 		iStdErrHandle = CreateFile(L"CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
       
   184 		int err = GetLastError();
       
   185 		WIN32_END();
       
   186 		
       
   187 		CONS_DEBUG(DebugMsg("CreateFile handle = %d, err %d", iStdErrHandle, err));
       
   188 		if (!TestHandle(iStdErrHandle, &err))
       
   189 			{
       
   190 			CONS_DEBUG(DebugMsg("Still can't write STDERR; err %d; giving up", err));
       
   191 			return 0;
       
   192 			}
       
   193 		}
       
   194 		
       
   195 	//iStdinHandle = CreateFile(L"CONIN$", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
       
   196 	WIN32_START();
       
   197 	iConsModeSet=false;
       
   198 	iStdinHandle = GetStdHandle(STD_INPUT_HANDLE);
       
   199 	if (GetConsoleMode(iStdinHandle, &iOldConsMode))
       
   200 		{
       
   201 		DWORD consmode = iOldConsMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
       
   202 		if (SetConsoleMode(iStdinHandle, consmode))
       
   203 			{
       
   204 			iConsModeSet=true;
       
   205 			}
       
   206 		}
       
   207 	iOrigAttributes = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
       
   208 	CONSOLE_SCREEN_BUFFER_INFO info;
       
   209 	if (GetConsoleScreenBufferInfo(iStdOutHandle, &info))
       
   210 		{
       
   211 		iOrigAttributes = info.wAttributes;
       
   212 		}
       
   213 	WIN32_END();
       
   214 		
       
   215 	return 1;
       
   216 	}
       
   217 	
       
   218 void TWin32Console::FreeConsole()
       
   219 	{
       
   220 	WIN32_START();
       
   221 	if (iConsModeSet)
       
   222 		{
       
   223 		SetConsoleMode(iStdinHandle, iOldConsMode);
       
   224 		}
       
   225 	::FreeConsole();
       
   226 	WIN32_END();
       
   227 	}
       
   228 	
       
   229 int TWin32Console::Write(const char* aText, int aLen)
       
   230 	{
       
   231 	DWORD written;
       
   232 	WIN32_START();
       
   233 	bool b = WriteFile(iStdOutHandle, (const void*)aText, aLen, &written, NULL);
       
   234 	int err = GetLastError();
       
   235 	WIN32_END();
       
   236 	//DebugMsg("WriteFile(STDOUT)=%d, err=%d", b, err);
       
   237 	return b ? 0 : (err>0 ? -err  : err);
       
   238 	}
       
   239 
       
   240 int TWin32Console::Write(const WCHAR* aText, int aLen)
       
   241 	{
       
   242 	if (iHaveConsole)
       
   243 		{
       
   244 		DWORD written;
       
   245 		WIN32_START();
       
   246 		bool b = WriteConsole(iStdOutHandle, (void*)aText, aLen, &written, NULL);
       
   247 		int err = GetLastError();
       
   248 		WIN32_END();
       
   249 		//DebugMsg("WriteFile(STDOUT)=%d, err=%d", b, err);
       
   250 		return b ? 0 : (err>0 ? -err  : err);
       
   251 		}
       
   252 	else
       
   253 		{
       
   254 		const int KBufLen = 256;
       
   255 		char outbuf[KBufLen];
       
   256 		int pos = 0;
       
   257 		while (pos < aLen)
       
   258 			{
       
   259 			int len = Min(KBufLen, aLen - pos);
       
   260 			int narrowLen = WideCharToMultiByte(CP_ACP, 0, aText, len, outbuf, KBufLen, NULL, NULL);
       
   261 			if (narrowLen == 0 && aLen != 0) return 0;
       
   262 			int ok = Write(outbuf, narrowLen);
       
   263 			if (!ok) return ok;
       
   264 			}
       
   265 		return 1;
       
   266 		}
       
   267 	}
       
   268 	
       
   269 int TWin32Console::WriteStdErr(const char* aText, int aLen)
       
   270 	{
       
   271 	DWORD written;
       
   272 	WIN32_START();
       
   273 	bool b = WriteFile(iStdErrHandle, (const void*)aText, aLen, &written, NULL);
       
   274 	int err = GetLastError();
       
   275 	WIN32_END();
       
   276 	//DebugMsg("WriteFile(STDERR)=%d, err=%d", b, err);
       
   277 	return b ? 0 : (err>0 ? -err  : err);
       
   278 	}
       
   279 
       
   280 int TWin32Console::WriteStdErr(const WCHAR* aText, int aLen)
       
   281 	{
       
   282 	if (iHaveConsole)
       
   283 		{
       
   284 		DWORD written;
       
   285 		WIN32_START();
       
   286 		bool b = WriteConsole(iStdErrHandle, (void*)aText, aLen, &written, NULL);
       
   287 		int err = GetLastError();
       
   288 		WIN32_END();
       
   289 		//DebugMsg("WriteFile(STDOUT)=%d, err=%d", b, err);
       
   290 		return b ? 0 : (err>0 ? -err  : err);
       
   291 		}
       
   292 	else
       
   293 		{
       
   294 		const int KBufLen = 256;
       
   295 		char outbuf[KBufLen];
       
   296 		int pos = 0;
       
   297 		while (pos < aLen)
       
   298 			{
       
   299 			int len = Min(KBufLen, aLen - pos);
       
   300 			int narrowLen = WideCharToMultiByte(CP_ACP, 0, aText, len, outbuf, KBufLen, NULL, NULL);
       
   301 			if (narrowLen == 0 && aLen != 0) return 0;
       
   302 			int ok = WriteStdErr(outbuf, narrowLen);
       
   303 			if (!ok) return ok;
       
   304 			}
       
   305 		return 1;
       
   306 		}
       
   307 	}
       
   308 	
       
   309 int TWin32Console::Read(void* buf, int len, int& bytesRead)
       
   310 	{
       
   311 	DWORD read;
       
   312 
       
   313 	/*
       
   314 	Read is a blocking call. We don't want to use WIN32_START() (Emulator::Lock()) as this 
       
   315 	will cause all other emulator threads to block until the Read call returns. Instead,
       
   316 	we escape the emulator which removes this thread from the usual emulator thraed 
       
   317 	scheduling until we re-enter the emulator when ReadFile returns. This allows other
       
   318 	emulator threads to run concurrently, even though (from the emulators thread shedulers
       
   319 	point of view) this thread is still running.
       
   320 	*/
       
   321 	Emulator::Escape(); 
       
   322 	bool b = ReadFile(iStdinHandle, buf, len, &read, NULL);
       
   323 	Emulator::Reenter();
       
   324 	
       
   325 	bytesRead = read;
       
   326 	return b ? 0 : -2; // TODO better error code?
       
   327 	}
       
   328 	
       
   329 int TWin32Console::ReadKey(TKeyCode& aCode, TUint& aModifiers)
       
   330 	{
       
   331 	bool ok = true;
       
   332 	if (iCachedKey.wRepeatCount == 0)
       
   333 		{
       
   334 		Emulator::Escape();
       
   335 		// read a recognised key event:
       
   336 		do
       
   337 			{
       
   338 			// read a key down event:
       
   339 			do
       
   340 				{
       
   341 				DWORD read;
       
   342 				INPUT_RECORD inp;
       
   343 				// read a key event:
       
   344 				do 
       
   345 					{
       
   346 					// read a console event:
       
   347 					do 
       
   348 						{
       
   349 						ok = ReadConsoleInput(iStdinHandle, &inp, 1, &read);
       
   350 						} while (ok && (read==0));
       
   351 					} while (ok && (inp.EventType != KEY_EVENT));
       
   352 				
       
   353 				if (ok)
       
   354 					{
       
   355 					iCachedKey = inp.Event.KeyEvent;
       
   356 					}
       
   357 				} while (ok && !iCachedKey.bKeyDown);
       
   358 			aCode = (TKeyCode)iCachedKey.uChar.AsciiChar;
       
   359 			if (aCode==0) aCode = GetSymbianKeyCode(iCachedKey.wVirtualKeyCode);
       
   360 			aModifiers = GetSymbianModifiers(iCachedKey.dwControlKeyState);
       
   361 			
       
   362 			} while (ok && (aCode==0));
       
   363 
       
   364 		Emulator::Reenter();
       
   365 			
       
   366 		}
       
   367 	if (!ok) return -2;
       
   368 	
       
   369 	CONS_DEBUG(char ch = iCachedKey.uChar.AsciiChar;
       
   370 	if (!ch) ch=' ';
       
   371 	DebugMsg("KeyPress %02x ('%c') down:%d keycode:%02x scancode:%02x controlkey:%02x", 
       
   372 		iCachedKey.uChar.AsciiChar, ch, iCachedKey.bKeyDown, iCachedKey.wVirtualKeyCode, iCachedKey.wVirtualScanCode, iCachedKey.dwControlKeyState));
       
   373 		
       
   374 	if (iCachedKey.wRepeatCount>0) --iCachedKey.wRepeatCount;
       
   375 	
       
   376 	return 0;
       
   377 	}
       
   378 
       
   379 	
       
   380 int TWin32Console::GetCursorPos(int& aX, int& aY) const
       
   381 	{
       
   382 	CONSOLE_SCREEN_BUFFER_INFO sbInfo;
       
   383 	int r;
       
   384 	WIN32_CALL(r = GetConsoleScreenBufferInfo(iStdOutHandle, &sbInfo));
       
   385 	if (r)
       
   386 		{
       
   387 		aX = sbInfo.dwCursorPosition.X;
       
   388 		aY = sbInfo.dwCursorPosition.Y;
       
   389 		// make sure it's not off the screen (bottom right)
       
   390 		if (aX > sbInfo.srWindow.Right) aX = sbInfo.srWindow.Left;
       
   391 		if (aY > sbInfo.srWindow.Bottom) aY = sbInfo.srWindow.Bottom;
       
   392 		// make cursor pos relative to display window
       
   393 		aX -= sbInfo.srWindow.Left;
       
   394 		aY -= sbInfo.srWindow.Top;
       
   395 		// make sure it's not off the screen (top left)
       
   396 		if (aX < 0) aX = 0;
       
   397 		if (aY < 0) aY = 0;
       
   398 		}
       
   399 	else
       
   400 		{
       
   401 		aX = aY = 0;
       
   402 		}
       
   403 	return r;
       
   404 	}
       
   405 	
       
   406 int TWin32Console::SetCursorPos(int aX, int aY)
       
   407 	{
       
   408 	CONSOLE_SCREEN_BUFFER_INFO sbInfo;
       
   409 	int r;
       
   410 	WIN32_CALL(r = GetConsoleScreenBufferInfo(iStdOutHandle, &sbInfo));
       
   411 	if (r)
       
   412 		{
       
   413 		// make position relative to display window
       
   414 		aX += sbInfo.srWindow.Left;
       
   415 		aY += sbInfo.srWindow.Top;
       
   416 		// make sure it's within the screen buffer
       
   417 		if (aX > sbInfo.dwSize.X) aX = sbInfo.dwSize.X;
       
   418 		if (aY > sbInfo.dwSize.Y) aY = sbInfo.dwSize.Y;
       
   419 		if (aX < 0) aX = 0;
       
   420 		if (aY < 0) aY = 0;
       
   421 		COORD pos;
       
   422 		pos.X = aX;
       
   423 		pos.Y = aY;
       
   424 		WIN32_CALL(r = SetConsoleCursorPosition(iStdOutHandle, pos));
       
   425 		}
       
   426 	return r;
       
   427 	}
       
   428 	
       
   429 int TWin32Console::SetCursorPosRel(int aX, int aY)
       
   430 	{
       
   431 	CONSOLE_SCREEN_BUFFER_INFO sbInfo;
       
   432 	int r;
       
   433 	WIN32_CALL(r = GetConsoleScreenBufferInfo(iStdOutHandle, &sbInfo));
       
   434 	if (r)
       
   435 		{
       
   436 		sbInfo.dwCursorPosition.X += aX;
       
   437 		sbInfo.dwCursorPosition.Y += aY;
       
   438 		// make sure it's still within screen buffer
       
   439 		sbInfo.dwCursorPosition.X = Max(0, Min(sbInfo.dwCursorPosition.X, sbInfo.dwSize.X));
       
   440 		sbInfo.dwCursorPosition.Y = Max(0, Min(sbInfo.dwCursorPosition.Y, sbInfo.dwSize.Y));
       
   441 		
       
   442 		WIN32_CALL(r = SetConsoleCursorPosition(iStdOutHandle, sbInfo.dwCursorPosition));
       
   443 		}
       
   444 	return r;
       
   445 	}
       
   446 		
       
   447 int TWin32Console::SetCursorHeight(int aPercentage)
       
   448 	{
       
   449 	CONSOLE_CURSOR_INFO info;
       
   450 	info.dwSize = Min(100, Max(1, aPercentage));
       
   451 	info.bVisible = aPercentage>0;
       
   452 	int r;
       
   453 	WIN32_CALL(r = SetConsoleCursorInfo(iStdOutHandle, &info));
       
   454 	return r;
       
   455 	}
       
   456 	
       
   457 int TWin32Console::SetTitle(const char* aTitle)
       
   458 	{
       
   459 	int r;
       
   460 	WIN32_CALL(r = SetConsoleTitleA(aTitle));
       
   461 	return r;
       
   462 	}
       
   463 	
       
   464 int TWin32Console::ClearScreen()
       
   465 	{
       
   466 	CONSOLE_SCREEN_BUFFER_INFO sbInfo;
       
   467 	WIN32_START();
       
   468 	int r = GetConsoleScreenBufferInfo(iStdOutHandle, &sbInfo);
       
   469 	COORD topLeft = {0, 0};
       
   470 	if (r)
       
   471 		{
       
   472 		DWORD bufferSize = sbInfo.dwSize.X * sbInfo.dwSize.Y;
       
   473 		DWORD charsWritten;
       
   474 		r = FillConsoleOutputCharacter(iStdOutHandle, (TCHAR)' ', bufferSize, topLeft, &charsWritten);
       
   475 		// Also reset the attributes
       
   476 		if (r) FillConsoleOutputAttribute(iStdOutHandle, iOrigAttributes, bufferSize, topLeft, &charsWritten);
       
   477 		}
       
   478 	if (r)
       
   479 		{
       
   480 		// move cursor to top left
       
   481 		r = SetConsoleCursorPosition(iStdOutHandle, topLeft);
       
   482 		}
       
   483 	if (r)
       
   484 		{
       
   485 		// move scroll region to top left
       
   486 		sbInfo.srWindow.Left -= sbInfo.srWindow.Right;
       
   487 		sbInfo.srWindow.Right -= sbInfo.srWindow.Right;
       
   488 		sbInfo.srWindow.Bottom -= sbInfo.srWindow.Top;
       
   489 		sbInfo.srWindow.Top -= sbInfo.srWindow.Top;
       
   490 		r = SetConsoleWindowInfo(iStdOutHandle, true, &sbInfo.srWindow);
       
   491 		}
       
   492 	WIN32_END();
       
   493 	return r;
       
   494 	}
       
   495 	
       
   496 int TWin32Console::ClearToEndOfLine()
       
   497 	{
       
   498 	WIN32_START();
       
   499 	CONSOLE_SCREEN_BUFFER_INFO sbInfo;
       
   500 	int r = GetConsoleScreenBufferInfo(iStdOutHandle, &sbInfo);
       
   501 	if (r)
       
   502 		{
       
   503 		SHORT len = sbInfo.dwSize.X - sbInfo.dwCursorPosition.X;
       
   504 		DWORD charsWritten;
       
   505 		r = FillConsoleOutputCharacter(iStdOutHandle, (TCHAR)' ', len, sbInfo.dwCursorPosition, &charsWritten);
       
   506 		// Also reset the attributes
       
   507 		if (r) FillConsoleOutputAttribute(iStdOutHandle, iOrigAttributes, len, sbInfo.dwCursorPosition, &charsWritten);
       
   508 		}
       
   509 	WIN32_END();
       
   510 	return r;	
       
   511 	}
       
   512 	
       
   513 int TWin32Console::GetScreenSize(int& aWidth, int& aHeight) const
       
   514 	{
       
   515 	CONSOLE_SCREEN_BUFFER_INFO sbInfo;
       
   516 	int r;
       
   517 	WIN32_CALL(r = GetConsoleScreenBufferInfo(iStdOutHandle, &sbInfo));
       
   518 	if (r)
       
   519 		{
       
   520 		aWidth  = sbInfo.srWindow.Right - sbInfo.srWindow.Left + 1;
       
   521 		aHeight = sbInfo.srWindow.Bottom - sbInfo.srWindow.Top + 1;
       
   522 		}
       
   523 	else
       
   524 		{
       
   525 		// not much else we can do?
       
   526 		aWidth = 80;
       
   527 		aHeight = 25; // [Shouldn't this be 24? -TomS]
       
   528 		}
       
   529 	return r;
       
   530 	}
       
   531 	
       
   532 int TWin32Console::SetAttributes(unsigned aAttributes, TWin32Console::TColor aForegroundColor, TWin32Console::TColor aBackgroundColor)
       
   533 	{
       
   534 	WORD attrib;
       
   535 	CONSOLE_SCREEN_BUFFER_INFO info;
       
   536 	if (aAttributes & ENone)
       
   537 		{
       
   538 		// None means reset
       
   539 		attrib = iOrigAttributes;
       
   540 		}
       
   541 	else
       
   542 		{
       
   543 		BOOL ok;
       
   544 		WIN32_CALL(ok = GetConsoleScreenBufferInfo(iStdOutHandle, &info));
       
   545 		if (!ok) return ok;
       
   546 		attrib = info.wAttributes;
       
   547 		}
       
   548 	
       
   549 	if (aForegroundColor != EUnchanged) attrib &= ~0x0F; // Clear the fg bits in preparation for the switch below
       
   550 	if (aBackgroundColor != EUnchanged) attrib &= ~0xF0; // Clear the bg bits in preparation for the switch below
       
   551 
       
   552 	switch (aForegroundColor)
       
   553 		{
       
   554 		case EBlack:
       
   555 			break;
       
   556 		case ERed:
       
   557 			attrib |= FOREGROUND_RED; break;
       
   558 		case EGreen:
       
   559 			attrib |= FOREGROUND_GREEN; break;
       
   560 		case EYellow:
       
   561 			attrib |= FOREGROUND_RED | FOREGROUND_GREEN; break;
       
   562 		case EBlue:
       
   563 			attrib |= FOREGROUND_BLUE; break;
       
   564 		case EMagenta:
       
   565 			attrib |= FOREGROUND_RED | FOREGROUND_BLUE; break;
       
   566 		case ECyan:
       
   567 			attrib |= FOREGROUND_BLUE | FOREGROUND_GREEN; break;
       
   568 		case EWhite:
       
   569 			attrib |= FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN; break;
       
   570 		default:
       
   571 			break;
       
   572 		}
       
   573 	switch (aBackgroundColor)
       
   574 		{
       
   575 		case EBlack:
       
   576 			break;
       
   577 		case ERed:
       
   578 			attrib |= BACKGROUND_RED; break;
       
   579 		case EGreen:
       
   580 			attrib |= BACKGROUND_GREEN; break;
       
   581 		case EYellow:
       
   582 			attrib |= BACKGROUND_RED | BACKGROUND_GREEN; break;
       
   583 		case EBlue:
       
   584 			attrib |= BACKGROUND_BLUE; break;
       
   585 		case EMagenta:
       
   586 			attrib |= BACKGROUND_RED | BACKGROUND_BLUE; break;
       
   587 		case ECyan:
       
   588 			attrib |= BACKGROUND_BLUE | BACKGROUND_GREEN; break;
       
   589 		case EWhite:
       
   590 			attrib |= BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN; break;
       
   591 		default:
       
   592 			break;
       
   593 		}
       
   594 	if (aAttributes & EBold) attrib |= FOREGROUND_INTENSITY;
       
   595 	if (aAttributes & EInverse)
       
   596 		{
       
   597 		// COMMON_LVB_REVERSE_VIDEO doesn't seem to be supported, so swap foreground and background manually
       
   598 		attrib = ((attrib & 0xF) << 4) | ((attrib & 0xF0) >> 4);
       
   599 		}
       
   600 	//if (aAttributes & EUnderscore) attrib |= COMMON_LVB_UNDERSCORE;
       
   601 
       
   602 	BOOL ok;
       
   603 	WIN32_CALL(ok = SetConsoleTextAttribute(iStdOutHandle, attrib));
       
   604 	return ok;
       
   605 	}