Attributes and saved position are local to each console window.
This commit is contained in:
parent
453db81af5
commit
6da33b2af0
272
ANSI.c
272
ANSI.c
@ -118,7 +118,8 @@
|
||||
ntdll's LdrLoadDll via CreateRemoteThread;
|
||||
restore original attributes on detach (for LoadLibrary/FreeLibrary usage);
|
||||
log: remove the quotes around the CreateProcess command line string and
|
||||
distinguish NULL and "" args.
|
||||
distinguish NULL and "" args;
|
||||
attributes (and saved position) are local to each console window.
|
||||
*/
|
||||
|
||||
#include "ansicon.h"
|
||||
@ -127,15 +128,6 @@
|
||||
|
||||
#define is_digit(c) ('0' <= (c) && (c) <= '9')
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SHARED __attribute__((shared, section(".shared")))
|
||||
#else
|
||||
#pragma data_seg(".shared", "read,write,shared")
|
||||
#pragma data_seg()
|
||||
#define SHARED __declspec(allocate(".shared"))
|
||||
#endif
|
||||
|
||||
|
||||
// ========== Global variables and constants
|
||||
|
||||
HANDLE hConOut; // handle to CONOUT$
|
||||
@ -246,36 +238,111 @@ const BYTE attr2ansi[8] = // map console attribute to ANSI number
|
||||
7 // white
|
||||
};
|
||||
|
||||
GRM grm;
|
||||
|
||||
// saved cursor position
|
||||
COORD SavePos;
|
||||
|
||||
// Variables to enable copying attributes between processes.
|
||||
SHARED DWORD s_pid;
|
||||
SHARED GRM s_grm;
|
||||
SHARED DWORD s_flag;
|
||||
#define GRM_INIT 1
|
||||
#define GRM_EXIT 2
|
||||
|
||||
|
||||
// Wait for the child process to finish, then update our GRM to the child's.
|
||||
DWORD WINAPI UpdateGRM( LPVOID child_pi )
|
||||
typedef struct
|
||||
{
|
||||
DWORD pid = ((LPPROCESS_INFORMATION)child_pi)->dwProcessId;
|
||||
HANDLE proc = ((LPPROCESS_INFORMATION)child_pi)->hProcess;
|
||||
free( child_pi );
|
||||
BYTE foreground; // ANSI base color (0 to 7; add 30)
|
||||
BYTE background; // ANSI base color (0 to 7; add 40)
|
||||
BYTE bold; // console FOREGROUND_INTENSITY bit
|
||||
BYTE underline; // console BACKGROUND_INTENSITY bit
|
||||
BYTE rvideo; // swap foreground/bold & background/underline
|
||||
BYTE concealed; // set foreground/bold to background/underline
|
||||
BYTE reverse; // swap console foreground & background attributes
|
||||
COORD SavePos; // saved cursor position
|
||||
} STATE, *PSTATE;
|
||||
|
||||
WaitForSingleObject( proc, INFINITE );
|
||||
CloseHandle( proc );
|
||||
PSTATE pState;
|
||||
HANDLE hMap;
|
||||
|
||||
if (s_flag == GRM_EXIT && s_pid == pid)
|
||||
void set_ansicon( PCONSOLE_SCREEN_BUFFER_INFO );
|
||||
|
||||
|
||||
void get_state( void )
|
||||
{
|
||||
TCHAR buf[64];
|
||||
HWND hwnd;
|
||||
BOOL init;
|
||||
HANDLE hConOut;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
static STATE state; // on the odd chance file mapping fails
|
||||
|
||||
if (pState != NULL)
|
||||
return;
|
||||
|
||||
hwnd = GetConsoleWindow();
|
||||
if (hwnd == NULL)
|
||||
return;
|
||||
|
||||
wsprintf( buf, L"ANSICON_State_%X", PtrToUint( hwnd ) );
|
||||
hMap = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
|
||||
0, sizeof(STATE), buf );
|
||||
if (hMap == NULL)
|
||||
{
|
||||
s_flag = 0;
|
||||
grm = s_grm;
|
||||
no_go:
|
||||
DEBUGSTR( 1, L"File mapping failed (%lu) - using default state",
|
||||
GetLastError() );
|
||||
pState = &state;
|
||||
goto do_init;
|
||||
}
|
||||
init = (GetLastError() != ERROR_ALREADY_EXISTS);
|
||||
|
||||
pState = MapViewOfFile( hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
|
||||
if (pState == NULL)
|
||||
{
|
||||
CloseHandle( hMap );
|
||||
goto no_go;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (init)
|
||||
{
|
||||
do_init:
|
||||
hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, 0 );
|
||||
if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))
|
||||
{
|
||||
DEBUGSTR(1, L"Failed to get screen buffer info (%lu) - assuming defaults",
|
||||
GetLastError() );
|
||||
csbi.wAttributes = 7;
|
||||
csbi.dwSize.X = 80;
|
||||
csbi.dwSize.Y = 300;
|
||||
csbi.srWindow.Left = 0;
|
||||
csbi.srWindow.Right = 79;
|
||||
csbi.srWindow.Top = 0;
|
||||
csbi.srWindow.Bottom = 24;
|
||||
}
|
||||
if (GetEnvironmentVariable( L"ANSICON_REVERSE", NULL, 0 ))
|
||||
{
|
||||
SetEnvironmentVariable( L"ANSICON_REVERSE", NULL );
|
||||
pState->reverse = TRUE;
|
||||
pState->foreground = attr2ansi[(csbi.wAttributes >> 4) & 7];
|
||||
pState->background = attr2ansi[csbi.wAttributes & 7];
|
||||
pState->bold = (csbi.wAttributes & BACKGROUND_INTENSITY) >> 4;
|
||||
pState->underline = (csbi.wAttributes & FOREGROUND_INTENSITY) << 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
pState->foreground = attr2ansi[csbi.wAttributes & 7];
|
||||
pState->background = attr2ansi[(csbi.wAttributes >> 4) & 7];
|
||||
pState->bold = csbi.wAttributes & FOREGROUND_INTENSITY;
|
||||
pState->underline = csbi.wAttributes & BACKGROUND_INTENSITY;
|
||||
}
|
||||
if (!GetEnvironmentVariable( L"ANSICON_DEF", NULL, 0 ))
|
||||
{
|
||||
TCHAR def[4];
|
||||
LPTSTR a = def;
|
||||
if (pState->reverse)
|
||||
{
|
||||
*a++ = '-';
|
||||
csbi.wAttributes = ((csbi.wAttributes >> 4) & 15)
|
||||
| ((csbi.wAttributes & 15) << 4);
|
||||
}
|
||||
wsprintf( a, L"%X", csbi.wAttributes & 255 );
|
||||
SetEnvironmentVariable( L"ANSICON_DEF", def );
|
||||
}
|
||||
set_ansicon( &csbi );
|
||||
CloseHandle( hConOut );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -418,13 +485,14 @@ void InterpretEscSeq( void )
|
||||
switch (suffix)
|
||||
{
|
||||
case 'm':
|
||||
get_state();
|
||||
if (es_argc == 0) es_argv[es_argc++] = 0;
|
||||
for (i = 0; i < es_argc; i++)
|
||||
{
|
||||
if (30 <= es_argv[i] && es_argv[i] <= 37)
|
||||
grm.foreground = es_argv[i] - 30;
|
||||
pState->foreground = es_argv[i] - 30;
|
||||
else if (40 <= es_argv[i] && es_argv[i] <= 47)
|
||||
grm.background = es_argv[i] - 40;
|
||||
pState->background = es_argv[i] - 40;
|
||||
else switch (es_argv[i])
|
||||
{
|
||||
case 0:
|
||||
@ -436,78 +504,78 @@ void InterpretEscSeq( void )
|
||||
*def = '7'; def[1] = '\0';
|
||||
GetEnvironmentVariable( L"ANSICON_DEF", def, lenof(def) );
|
||||
a = wcstol( def, NULL, 16 );
|
||||
grm.reverse = FALSE;
|
||||
pState->reverse = FALSE;
|
||||
if (a < 0)
|
||||
{
|
||||
grm.reverse = TRUE;
|
||||
pState->reverse = TRUE;
|
||||
a = -a;
|
||||
}
|
||||
if (es_argv[i] != 49)
|
||||
grm.foreground = attr2ansi[a & 7];
|
||||
pState->foreground = attr2ansi[a & 7];
|
||||
if (es_argv[i] != 39)
|
||||
grm.background = attr2ansi[(a >> 4) & 7];
|
||||
pState->background = attr2ansi[(a >> 4) & 7];
|
||||
if (es_argv[i] == 0)
|
||||
{
|
||||
if (es_argc == 1)
|
||||
{
|
||||
grm.bold = a & FOREGROUND_INTENSITY;
|
||||
grm.underline = a & BACKGROUND_INTENSITY;
|
||||
pState->bold = a & FOREGROUND_INTENSITY;
|
||||
pState->underline = a & BACKGROUND_INTENSITY;
|
||||
}
|
||||
else
|
||||
{
|
||||
grm.bold = 0;
|
||||
grm.underline = 0;
|
||||
pState->bold = 0;
|
||||
pState->underline = 0;
|
||||
}
|
||||
grm.rvideo = 0;
|
||||
grm.concealed = 0;
|
||||
pState->rvideo = 0;
|
||||
pState->concealed = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: grm.bold = FOREGROUND_INTENSITY; break;
|
||||
case 1: pState->bold = FOREGROUND_INTENSITY; break;
|
||||
case 5: // blink
|
||||
case 4: grm.underline = BACKGROUND_INTENSITY; break;
|
||||
case 7: grm.rvideo = 1; break;
|
||||
case 8: grm.concealed = 1; break;
|
||||
case 4: pState->underline = BACKGROUND_INTENSITY; break;
|
||||
case 7: pState->rvideo = 1; break;
|
||||
case 8: pState->concealed = 1; break;
|
||||
case 21: // oops, this actually turns on double underline
|
||||
// but xterm turns off bold too, so that's alright
|
||||
case 22: grm.bold = 0; break;
|
||||
case 22: pState->bold = 0; break;
|
||||
case 25:
|
||||
case 24: grm.underline = 0; break;
|
||||
case 27: grm.rvideo = 0; break;
|
||||
case 28: grm.concealed = 0; break;
|
||||
case 24: pState->underline = 0; break;
|
||||
case 27: pState->rvideo = 0; break;
|
||||
case 28: pState->concealed = 0; break;
|
||||
}
|
||||
}
|
||||
if (grm.concealed)
|
||||
if (pState->concealed)
|
||||
{
|
||||
if (grm.rvideo)
|
||||
if (pState->rvideo)
|
||||
{
|
||||
attribut = foregroundcolor[grm.foreground]
|
||||
| backgroundcolor[grm.foreground];
|
||||
if (grm.bold)
|
||||
attribut = foregroundcolor[pState->foreground]
|
||||
| backgroundcolor[pState->foreground];
|
||||
if (pState->bold)
|
||||
attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
|
||||
}
|
||||
else
|
||||
{
|
||||
attribut = foregroundcolor[grm.background]
|
||||
| backgroundcolor[grm.background];
|
||||
if (grm.underline)
|
||||
attribut = foregroundcolor[pState->background]
|
||||
| backgroundcolor[pState->background];
|
||||
if (pState->underline)
|
||||
attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
|
||||
}
|
||||
}
|
||||
else if (grm.rvideo)
|
||||
else if (pState->rvideo)
|
||||
{
|
||||
attribut = foregroundcolor[grm.background]
|
||||
| backgroundcolor[grm.foreground];
|
||||
if (grm.bold)
|
||||
attribut = foregroundcolor[pState->background]
|
||||
| backgroundcolor[pState->foreground];
|
||||
if (pState->bold)
|
||||
attribut |= BACKGROUND_INTENSITY;
|
||||
if (grm.underline)
|
||||
if (pState->underline)
|
||||
attribut |= FOREGROUND_INTENSITY;
|
||||
}
|
||||
else
|
||||
attribut = foregroundcolor[grm.foreground] | grm.bold
|
||||
| backgroundcolor[grm.background] | grm.underline;
|
||||
if (grm.reverse)
|
||||
attribut = foregroundcolor[pState->foreground] | pState->bold
|
||||
| backgroundcolor[pState->background] | pState->underline;
|
||||
if (pState->reverse)
|
||||
attribut = ((attribut >> 4) & 15) | ((attribut & 15) << 4);
|
||||
SetConsoleTextAttribute( hConOut, attribut );
|
||||
return;
|
||||
@ -762,12 +830,14 @@ void InterpretEscSeq( void )
|
||||
|
||||
case 's': // ESC[s Saves cursor position for recall later
|
||||
if (es_argc != 0) return;
|
||||
SavePos = Info.dwCursorPosition;
|
||||
get_state();
|
||||
pState->SavePos = Info.dwCursorPosition;
|
||||
return;
|
||||
|
||||
case 'u': // ESC[u Return to saved cursor position
|
||||
if (es_argc != 0) return;
|
||||
SetConsoleCursorPosition( hConOut, SavePos );
|
||||
get_state();
|
||||
SetConsoleCursorPosition( hConOut, pState->SavePos );
|
||||
return;
|
||||
|
||||
case 'n': // ESC[#n Device status report
|
||||
@ -1309,19 +1379,6 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
||||
#endif
|
||||
InjectDLL( child_pi, base );
|
||||
#endif
|
||||
if (!gui && !(dwCreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
|
||||
{
|
||||
LPPROCESS_INFORMATION cpi;
|
||||
s_pid = child_pi->dwProcessId;
|
||||
s_grm = grm;
|
||||
s_flag = GRM_INIT;
|
||||
cpi = malloc( sizeof(*cpi) );
|
||||
cpi->dwProcessId = child_pi->dwProcessId;
|
||||
DuplicateHandle( GetCurrentProcess(), child_pi->hProcess,
|
||||
GetCurrentProcess(), &cpi->hProcess, 0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS );
|
||||
CloseHandle( CreateThread( NULL, 4096, UpdateGRM, cpi, 0, NULL ) );
|
||||
}
|
||||
}
|
||||
|
||||
if (!(dwCreationFlags & CREATE_SUSPENDED))
|
||||
@ -1359,6 +1416,8 @@ BOOL WINAPI MyCreateProcessA( LPCSTR lpApplicationName,
|
||||
(lpCommandLine == NULL) ? "<null>" :
|
||||
(*lpCommandLine == '\0') ? "<empty>" : lpCommandLine );
|
||||
|
||||
// May need to initialise the state, to propagate environment variables.
|
||||
get_state();
|
||||
if (!CreateProcessA( lpApplicationName,
|
||||
lpCommandLine,
|
||||
lpThreadAttributes,
|
||||
@ -1401,6 +1460,7 @@ BOOL WINAPI MyCreateProcessW( LPCWSTR lpApplicationName,
|
||||
(lpCommandLine == NULL) ? L"<null>" :
|
||||
(*lpCommandLine == '\0') ? L"<empty>" : lpCommandLine );
|
||||
|
||||
get_state();
|
||||
if (!CreateProcessW( lpApplicationName,
|
||||
lpCommandLine,
|
||||
lpThreadAttributes,
|
||||
@ -1801,44 +1861,7 @@ void OriginalAttr( PVOID lpReserved )
|
||||
break;
|
||||
}
|
||||
|
||||
if (s_flag == GRM_INIT && s_pid == GetCurrentProcessId())
|
||||
{
|
||||
s_flag = 0;
|
||||
grm = s_grm;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetEnvironmentVariable( L"ANSICON_REVERSE", NULL, 0 ))
|
||||
{
|
||||
SetEnvironmentVariable( L"ANSICON_REVERSE", NULL );
|
||||
grm.reverse = TRUE;
|
||||
grm.foreground = attr2ansi[(csbi.wAttributes >> 4) & 7];
|
||||
grm.background = attr2ansi[csbi.wAttributes & 7];
|
||||
grm.bold = (csbi.wAttributes & BACKGROUND_INTENSITY) >> 4;
|
||||
grm.underline = (csbi.wAttributes & FOREGROUND_INTENSITY) << 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
grm.foreground = attr2ansi[csbi.wAttributes & 7];
|
||||
grm.background = attr2ansi[(csbi.wAttributes >> 4) & 7];
|
||||
grm.bold = csbi.wAttributes & FOREGROUND_INTENSITY;
|
||||
grm.underline = csbi.wAttributes & BACKGROUND_INTENSITY;
|
||||
}
|
||||
}
|
||||
if (!GetEnvironmentVariable( L"ANSICON_DEF", NULL, 0 ))
|
||||
{
|
||||
TCHAR def[4];
|
||||
LPTSTR a = def;
|
||||
if (grm.reverse)
|
||||
{
|
||||
*a++ = '-';
|
||||
csbi.wAttributes = ((csbi.wAttributes >> 4) & 15)
|
||||
| ((csbi.wAttributes & 15) << 4);
|
||||
}
|
||||
wsprintf( a, L"%X", csbi.wAttributes & 255 );
|
||||
SetEnvironmentVariable( L"ANSICON_DEF", def );
|
||||
}
|
||||
set_ansicon( &csbi );
|
||||
get_state();
|
||||
}
|
||||
|
||||
|
||||
@ -1896,9 +1919,6 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
||||
else
|
||||
{
|
||||
DEBUGSTR( 1, L"Terminating" );
|
||||
s_pid = GetCurrentProcessId();
|
||||
s_grm = grm;
|
||||
s_flag = GRM_EXIT;
|
||||
}
|
||||
if (orgattr != 0)
|
||||
{
|
||||
@ -1908,6 +1928,8 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
||||
SetConsoleTextAttribute( hConOut, orgattr );
|
||||
CloseHandle( hConOut );
|
||||
}
|
||||
CloseHandle( pState );
|
||||
CloseHandle( hMap );
|
||||
}
|
||||
|
||||
return bResult;
|
||||
|
16
ansicon.h
16
ansicon.h
@ -13,9 +13,9 @@
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifdef _WIN64
|
||||
#define _WIN32_WINNT 0x0600 // MinGW-w64 wants this defined for Wow64 stuff
|
||||
#define _WIN32_WINNT 0x0501 // at least XP required
|
||||
#else
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#define _WIN32_WINNT 0x0500 // at least Windows 2000 required
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
@ -49,18 +49,6 @@
|
||||
#define VirtProtVar(a, b) VirtualProtectEx( ppi->hProcess, a, sizeof(*(a)), b, &pr )
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE foreground; // ANSI base color (0 to 7; add 30)
|
||||
BYTE background; // ANSI base color (0 to 7; add 40)
|
||||
BYTE bold; // console FOREGROUND_INTENSITY bit
|
||||
BYTE underline; // console BACKGROUND_INTENSITY bit
|
||||
BYTE rvideo; // swap foreground/bold & background/underline
|
||||
BYTE concealed; // set foreground/bold to background/underline
|
||||
BYTE reverse; // swap console foreground & background attributes
|
||||
} GRM, *PGRM; // Graphic Rendition Mode
|
||||
|
||||
|
||||
int ProcessType( LPPROCESS_INFORMATION, PBYTE*, BOOL* );
|
||||
BOOL Wow64Process( HANDLE );
|
||||
|
||||
|
@ -102,7 +102,7 @@ x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\procrva.obj x86\ansicon.res
|
||||
|
||||
x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res
|
||||
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \
|
||||
/base:0xAC0000 /section:.shared,s /filealign:512
|
||||
/base:0xAC0000 /filealign:512
|
||||
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
||||
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2
|
||||
@del $@.manifest
|
||||
@ -116,11 +116,11 @@ x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res
|
||||
|
||||
x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res
|
||||
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \
|
||||
/base:0xAC000000 /section:.shared,s
|
||||
/base:0xAC000000
|
||||
|
||||
x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll.obj x86\util.obj x86\ansi.res
|
||||
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \
|
||||
/base:0xAC0000 /section:.shared,s /filealign:512 /largeaddressaware
|
||||
/base:0xAC0000 /filealign:512 /largeaddressaware
|
||||
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
||||
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2
|
||||
@del $@.manifest
|
||||
|
@ -273,14 +273,15 @@ Version History
|
||||
|
||||
Legend: + added, - bug-fixed, * changed.
|
||||
|
||||
1.70 - 4 February, 2014:
|
||||
1.70 - 8 February, 2014:
|
||||
- don't hook again if using LoadLibrary or LoadLibraryEx;
|
||||
- update the LoadLibraryEx flags that shouldn't hook;
|
||||
- restore original attributes on detach (for LoadLibrary/FreeLibrary usage);
|
||||
- ansicon.exe will start with ANSICON_DEF (if defined and -m not used);
|
||||
- an installed ansicon.exe will restore current (not default) attributes;
|
||||
- attributes and saved position are local to each console window;
|
||||
* inject into a created process by modifying the import descriptor table
|
||||
(use CreateRemoteThread for -p);
|
||||
(-p will use CreateRemoteThread);
|
||||
* log: remove the quotes around the CreateProcess command line;
|
||||
add an underscore in 64-bit addresses to distinguish 8-digit groups.
|
||||
|
||||
@ -470,4 +471,4 @@ Distribution
|
||||
|
||||
|
||||
=============================
|
||||
Jason Hood, 4 February, 2014.
|
||||
Jason Hood, 8 February, 2014.
|
||||
|
Loading…
x
Reference in New Issue
Block a user