Exclude modules from being hooked; hook only selected GUI programs.
Added environment variable ANSICON_EXC to specify modules that should not be hooked. This should work around the nvd3d9wrap.dll issue. Since it helps to know what the modules are, logging is now always available, controlled by -l or ANSICON_LOG. A side-effect caused debugstr.c to move to util.c. GUI programs are once again not hooked, unless run by "ansicon" directly or in the ANSICON_GUI environment variable. Since not hooking still leaves ANSICON in the environment, created ANSICON_VER as a dynamic-only variable, which can also serve as a version check. Due to an email requesting a reverse video option, realised I always take the current attributes as default. This means if you turned on reverse and ran a program, it would take the reverse as its default. Created ANSICON_DEF variable to explicitly set the default attribute, using the current if it doesn't exist. The reverse video option is done via a "negative" attribute (e.g. "-m-f0" is reversed black on white, meaning you'll get white on black, with foreground sequences changing the background). (The difference from "\e[7m" is that it won't be reset on "\e[m".) A child program will inherit the parent's modes (but not shift); the parent will read the child's modes on exit (but not unload). The exception is "ansicon", which will always start with the default modes and leave the parent unchanged. Improved the AutoRun entry, only running "ansicon" if ANSICON_VER doesn't exist. The "ansicon" command is always first. Stopped -u implying -p; return the program's exit code; don't restore the original color when just using -p; output error messages to stderr.
This commit is contained in:
parent
a87891fa6a
commit
790de57763
@ -50,6 +50,57 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
========================================
|
||||
getopt, getopt_long, and getop_long_only
|
||||
========================================
|
||||
|
||||
Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
Sponsored in part by the Defense Advanced Research Projects
|
||||
Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
|
||||
* * * * * * *
|
||||
|
||||
Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
All rights reserved.
|
||||
|
||||
This code is derived from software contributed to The NetBSD Foundation
|
||||
by Dieter Baron and Thomas Klausner.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
===============================================================
|
||||
gdtoa: Converting between IEEE floating point numbers and ASCII
|
||||
@ -167,3 +218,23 @@ permission from the author and then add a license into the Cephes files
|
||||
in MinGW runtime. At least on follow-up it is marked that debian sees the
|
||||
version a-like BSD one. As MinGW.org (where those cephes parts are coming
|
||||
from) distributes them now over 6 years, it should be fine.
|
||||
|
||||
===================================
|
||||
Headers and IDLs imported from Wine
|
||||
===================================
|
||||
|
||||
Some header and IDL files were imported from the Wine project. These files
|
||||
are prominent maked in source. Their copyright belongs to contributors and
|
||||
they are distributed under LGPL license.
|
||||
|
||||
Disclaimer
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
9
ansi.rc
9
ansi.rc
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <winver.h>
|
||||
#include "version.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
# define BITS "64"
|
||||
@ -13,8 +14,8 @@
|
||||
#endif
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 1,4,0,0
|
||||
PRODUCTVERSION 1,4,0,0
|
||||
FILEVERSION PVERB
|
||||
PRODUCTVERSION PVERB
|
||||
FILEOS VOS_NT
|
||||
FILETYPE VFT_DLL
|
||||
{
|
||||
@ -25,12 +26,12 @@ FILETYPE VFT_DLL
|
||||
VALUE "Comments", "http://ansicon.adoxa.cjb.net/"
|
||||
VALUE "CompanyName", "Jason Hood"
|
||||
VALUE "FileDescription", "ANSI Console"
|
||||
VALUE "FileVersion", "1.40"
|
||||
VALUE "FileVersion", PVERSA
|
||||
VALUE "InternalName", "ANSI" BITS
|
||||
VALUE "LegalCopyright", "Freeware"
|
||||
VALUE "OriginalFilename", "ANSI" BITS ".dll"
|
||||
VALUE "ProductName", "ANSICON"
|
||||
VALUE "ProductVersion", "1.40"
|
||||
VALUE "ProductVersion", PVERSA
|
||||
}
|
||||
}
|
||||
|
||||
|
574
ansicon.c
574
ansicon.c
@ -47,18 +47,24 @@
|
||||
make -p more robust;
|
||||
inject into GUI processes;
|
||||
-i implies -p.
|
||||
|
||||
v1.50, 7 to 14 December, 2011:
|
||||
-u does not imply -p;
|
||||
add the PID to the debugging output;
|
||||
use ANSICON_VER to test if already installed;
|
||||
always place first in AutoRun;
|
||||
logging is always available, controlled by ANSICON_LOG environment variable;
|
||||
only restore the original color after program/echo/type;
|
||||
return program's exit code.
|
||||
*/
|
||||
|
||||
#define PVERS L"1.40"
|
||||
#define PDATE L"1 March, 2011"
|
||||
#define PDATE L"14 December, 2011"
|
||||
|
||||
#include "ansicon.h"
|
||||
#include <shellapi.h>
|
||||
#include "version.h"
|
||||
#include <tlhelp32.h>
|
||||
#include <ctype.h>
|
||||
#include <io.h>
|
||||
#include <objbase.h>
|
||||
#include <psapi.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
int _CRT_glob = 0;
|
||||
@ -79,33 +85,33 @@ int _CRT_glob = 0;
|
||||
void help( void );
|
||||
|
||||
void display( LPCTSTR, BOOL );
|
||||
void print_error( LPCTSTR, ... );
|
||||
LPTSTR skip_spaces( LPTSTR );
|
||||
LPTSTR skip_arg( LPTSTR );
|
||||
void get_arg( LPTSTR, LPTSTR*, LPTSTR* );
|
||||
|
||||
void process_autorun( TCHAR );
|
||||
|
||||
BOOL find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe );
|
||||
BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi );
|
||||
BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR );
|
||||
|
||||
|
||||
// Find the name of the DLL and inject it.
|
||||
BOOL Inject( LPPROCESS_INFORMATION ppi )
|
||||
BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
||||
{
|
||||
DWORD len;
|
||||
WCHAR dll[MAX_PATH];
|
||||
int type;
|
||||
|
||||
#if (MYDEBUG > 0)
|
||||
if (GetModuleFileNameEx( ppi->hProcess, NULL, dll, lenof(dll) ))
|
||||
DEBUGSTR( L"%s", dll );
|
||||
#endif
|
||||
type = ProcessType( ppi );
|
||||
DEBUGSTR( 1, L"%s", app );
|
||||
type = ProcessType( ppi, gui );
|
||||
if (type == 0)
|
||||
{
|
||||
fwprintf( stderr, L"ANSICON: %s: unsupported process.\n", app );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
len = GetModuleFileName( NULL, dll, lenof(dll) );
|
||||
while (dll[len-1] != '\\')
|
||||
--len;
|
||||
len = (DWORD)(prog - prog_path);
|
||||
memcpy( dll, prog_path, TSIZE(len) );
|
||||
#ifdef _WIN64
|
||||
wsprintf( dll + len, L"ANSI%d.dll", type );
|
||||
if (type == 32)
|
||||
@ -145,288 +151,302 @@ DWORD CtrlHandler( DWORD event )
|
||||
}
|
||||
|
||||
|
||||
//int _tmain( int argc, TCHAR* argv[] )
|
||||
int main( void )
|
||||
{
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
TCHAR* cmd;
|
||||
BOOL option;
|
||||
BOOL opt_m;
|
||||
LPTSTR argv, arg, cmd;
|
||||
TCHAR logstr[4];
|
||||
BOOL installed;
|
||||
BOOL shell, run, gui;
|
||||
HMODULE ansi;
|
||||
DWORD len;
|
||||
int rc = 0;
|
||||
|
||||
int argc;
|
||||
LPWSTR* argv = CommandLineToArgvW( GetCommandLine(), &argc );
|
||||
argv = GetCommandLine();
|
||||
len = (DWORD)wcslen( argv ) + 1;
|
||||
if (len < MAX_PATH)
|
||||
len = MAX_PATH;
|
||||
arg = malloc( TSIZE(len) );
|
||||
get_arg( arg, &argv, &cmd ); // skip the program name
|
||||
get_arg( arg, &argv, &cmd );
|
||||
|
||||
if (argc > 1)
|
||||
if (*arg)
|
||||
{
|
||||
if (lstrcmp( argv[1], L"--help" ) == 0 ||
|
||||
(argv[1][0] == '-' && (argv[1][1] == '?' || argv[1][1] == 'h')) ||
|
||||
(argv[1][0] == '/' && argv[1][1] == '?'))
|
||||
if (wcscmp( arg, L"/?" ) == 0 ||
|
||||
wcscmp( arg, L"--help" ) == 0)
|
||||
{
|
||||
help();
|
||||
return rc;
|
||||
}
|
||||
if (lstrcmp( argv[1], L"--version" ) == 0)
|
||||
if (wcscmp( arg, L"--version" ) == 0)
|
||||
{
|
||||
_putws( L"ANSICON (" BITS L"-bit) version " PVERS L" (" PDATE L")." );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
#if (MYDEBUG > 1)
|
||||
DEBUGSTR( NULL ); // create a new file
|
||||
#endif
|
||||
prog = get_program_name( NULL );
|
||||
*logstr = '\0';
|
||||
GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );
|
||||
log_level = _wtoi( logstr );
|
||||
if (log_level && !(log_level & 8))
|
||||
DEBUGSTR( 1, NULL ); // create a new file
|
||||
|
||||
option = (argc > 1 && argv[1][0] == '-');
|
||||
if (option && (towlower( argv[1][1] ) == 'i' ||
|
||||
towlower( argv[1][1] ) == 'u'))
|
||||
installed = (GetEnvironmentVariable( L"ANSICON_VER", NULL, 0 ) != 0);
|
||||
// If it's already installed, remove it. This serves two purposes: preserves
|
||||
// the parent's GRM; and unconditionally injects into GUI, without having to
|
||||
// worry about ANSICON_GUI.
|
||||
if (installed)
|
||||
{
|
||||
process_autorun( argv[1][1] );
|
||||
argv[1][1] = 'p';
|
||||
fputws( L"\33[m", stdout );
|
||||
FreeLibrary( GetModuleHandle( L"ANSI" BITS L".dll" ) );
|
||||
}
|
||||
|
||||
shell = run = TRUE;
|
||||
get_original_attr();
|
||||
|
||||
opt_m = FALSE;
|
||||
if (option && argv[1][1] == 'm')
|
||||
while (*arg == '-')
|
||||
{
|
||||
WORD attr = 7;
|
||||
if (iswxdigit( argv[1][2] ))
|
||||
switch (arg[1])
|
||||
{
|
||||
attr = iswdigit( argv[1][2] ) ? argv[1][2] - '0'
|
||||
: (argv[1][2] | 0x20) - 'a' + 10;
|
||||
if (iswxdigit( argv[1][3]))
|
||||
{
|
||||
attr <<= 4;
|
||||
attr |= iswdigit( argv[1][3] ) ? argv[1][3] - '0'
|
||||
: (argv[1][3] | 0x20) - 'a' + 10;
|
||||
}
|
||||
}
|
||||
SetConsoleTextAttribute( hConOut, attr );
|
||||
case 'l':
|
||||
SetEnvironmentVariable( L"ANSICON_LOG", arg + 2 );
|
||||
log_level = _wtoi( arg + 2 );
|
||||
if (!(log_level & 8)) // unless told otherwise
|
||||
DEBUGSTR( 1, NULL ); // create a new file
|
||||
break;
|
||||
|
||||
opt_m = TRUE;
|
||||
++argv;
|
||||
--argc;
|
||||
option = (argc > 1 && argv[1][0] == '-');
|
||||
}
|
||||
case 'i':
|
||||
case 'I':
|
||||
case 'u':
|
||||
case 'U':
|
||||
shell = FALSE;
|
||||
process_autorun( arg[1] );
|
||||
if (arg[1] == 'u' || arg[1] == 'U')
|
||||
break;
|
||||
// else fall through
|
||||
|
||||
installed = (GetEnvironmentVariable( L"ANSICON", NULL, 0 ) != 0);
|
||||
|
||||
if (option && argv[1][1] == 'p')
|
||||
{
|
||||
case 'p':
|
||||
shell = FALSE;
|
||||
// If it's already installed, there's no need to do anything.
|
||||
if (installed)
|
||||
;
|
||||
else if (GetParentProcessInfo( &pi ))
|
||||
{
|
||||
pi.hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId );
|
||||
DEBUGSTR( 1, L"Already installed" );
|
||||
}
|
||||
else if (GetParentProcessInfo( &pi, arg ))
|
||||
{
|
||||
pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
|
||||
pi.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );
|
||||
SuspendThread( pi.hThread );
|
||||
if (!Inject( &pi ))
|
||||
{
|
||||
_putws( L"ANSICON: parent process type is not supported." );
|
||||
if (!Inject( &pi, &gui, arg ))
|
||||
rc = 1;
|
||||
}
|
||||
ResumeThread( pi.hThread );
|
||||
CloseHandle( pi.hThread );
|
||||
CloseHandle( pi.hProcess );
|
||||
}
|
||||
else
|
||||
{
|
||||
_putws( L"ANSICON: could not obtain the parent process." );
|
||||
fputws( L"ANSICON: could not obtain the parent process.\n", stderr );
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
{
|
||||
int a = wcstol( arg + 2, NULL, 16 );
|
||||
if (a == 0)
|
||||
a = (arg[2] == '-') ? -7 : 7;
|
||||
if (a < 0)
|
||||
{
|
||||
SetEnvironmentVariable( L"ANSICON_REVERSE", L"1" );
|
||||
a = -a;
|
||||
a = ((a >> 4) & 15) | ((a & 15) << 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
ansi = 0;
|
||||
if (!installed)
|
||||
{
|
||||
ansi = LoadLibrary( L"ANSI" BITS L".dll" );
|
||||
if (!ansi)
|
||||
{
|
||||
fputws( L"ANSICON: failed to load ANSI" BITS L".dll.\n", stderr );
|
||||
rc = 1;
|
||||
}
|
||||
SetConsoleTextAttribute( hConOut, a );
|
||||
SetEnvironmentVariable( L"ANSICON_DEF", NULL );
|
||||
break;
|
||||
}
|
||||
|
||||
if (option && (argv[1][1] == 't' || argv[1][1] == 'T'))
|
||||
{
|
||||
BOOL title = (argv[1][1] == 'T');
|
||||
if (argc == 2)
|
||||
{
|
||||
argv[2] = L"-";
|
||||
++argc;
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 't':
|
||||
case 'T':
|
||||
run = FALSE;
|
||||
++arg;
|
||||
goto arg_out;
|
||||
}
|
||||
for (; argc > 2; ++argv, --argc)
|
||||
{
|
||||
if (title)
|
||||
wprintf( L"==> %s <==\n", argv[2] );
|
||||
display( argv[2], title );
|
||||
if (title)
|
||||
putwchar( '\n' );
|
||||
get_arg( arg, &argv, &cmd );
|
||||
}
|
||||
}
|
||||
else
|
||||
arg_out:
|
||||
if (run && *cmd == '\0')
|
||||
{
|
||||
// Retrieve the original command line, skipping our name and the option.
|
||||
cmd = skip_spaces( skip_arg( skip_spaces( GetCommandLine() ) ) );
|
||||
if (opt_m)
|
||||
cmd = skip_spaces( skip_arg( cmd ) );
|
||||
if (!_isatty( 0 ))
|
||||
{
|
||||
*arg = 't';
|
||||
run = FALSE;
|
||||
}
|
||||
else if (!shell)
|
||||
run = FALSE;
|
||||
}
|
||||
|
||||
if (cmd[0] == '-' && (cmd[1] == 'e' || cmd[1] == 'E'))
|
||||
{
|
||||
fputws( cmd + 3, stdout );
|
||||
if (cmd[1] == 'e')
|
||||
putwchar( '\n' );
|
||||
}
|
||||
else if (!_isatty( 0 ) && *cmd == '\0')
|
||||
{
|
||||
display( L"-", FALSE );
|
||||
}
|
||||
else
|
||||
if (run)
|
||||
{
|
||||
if (*cmd == '\0')
|
||||
{
|
||||
cmd = _wgetenv( L"ComSpec" );
|
||||
if (cmd == NULL)
|
||||
cmd = L"cmd";
|
||||
arg = cmd;
|
||||
}
|
||||
|
||||
ZeroMemory( &si, sizeof(si) );
|
||||
si.cb = sizeof(si);
|
||||
if (CreateProcess( NULL, cmd, NULL,NULL, TRUE, 0, NULL,NULL, &si, &pi ))
|
||||
if (CreateProcess( NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED,
|
||||
NULL, NULL, &si, &pi ))
|
||||
{
|
||||
BOOL console = FALSE;
|
||||
TCHAR name[MAX_PATH];
|
||||
DWORD rc;
|
||||
CoInitialize( NULL );
|
||||
do
|
||||
{
|
||||
// When I first tried doing this, it took a little while to
|
||||
// succeed. Testing again shows it works immediately - perhaps the
|
||||
// CoInitialize introduces enough of a delay. Still, play it safe
|
||||
// and keep trying. And if you're wondering why I do it at all,
|
||||
// ProcessType may detect GUI, even for a console process. That's
|
||||
// fine after injection (including -p), but not here. We *need* to
|
||||
// suspend our own execution whilst running the child, otherwise
|
||||
// bad things happen (besides which, I want to restore the original
|
||||
// attributes when the child exits).
|
||||
if (GetModuleFileNameEx( pi.hProcess, NULL, name, lenof(name) ))
|
||||
{
|
||||
DWORD_PTR info;
|
||||
info = SHGetFileInfo( name, 0, NULL, 0, SHGFI_EXETYPE );
|
||||
if (info == 0x00004550) // console PE
|
||||
console = TRUE;
|
||||
DEBUGSTR( L"%s", name );
|
||||
DEBUGSTR( L" %s (%p)", (console) ? L"Console" : L"Not console",
|
||||
info );
|
||||
break;
|
||||
}
|
||||
Sleep( 10 );
|
||||
} while (GetExitCodeProcess( pi.hProcess, &rc ) &&
|
||||
rc == STILL_ACTIVE);
|
||||
CoUninitialize();
|
||||
if (console)
|
||||
Inject( &pi, &gui, arg );
|
||||
ResumeThread( pi.hThread );
|
||||
if (!gui)
|
||||
{
|
||||
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)CtrlHandler, TRUE );
|
||||
WaitForSingleObject( pi.hProcess, INFINITE );
|
||||
GetExitCodeProcess( pi.hProcess, (LPDWORD)(LPVOID)&rc );
|
||||
}
|
||||
CloseHandle( pi.hProcess );
|
||||
CloseHandle( pi.hThread );
|
||||
}
|
||||
else
|
||||
{
|
||||
*skip_arg( cmd ) = '\0';
|
||||
wprintf( L"ANSICON: '%s' could not be executed.\n", cmd );
|
||||
print_error( arg, arg );
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
else if (*arg)
|
||||
{
|
||||
ansi = LoadLibrary( L"ANSI" BITS L".dll" );
|
||||
if (ansi == NULL)
|
||||
{
|
||||
print_error( L"ANSI" BITS L".dll" );
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
if (*arg == 'e' || *arg == 'E')
|
||||
{
|
||||
cmd += 2;
|
||||
if (*cmd == ' ' || *cmd == '\t')
|
||||
++cmd;
|
||||
fputws( cmd, stdout );
|
||||
if (*arg == 'e')
|
||||
putwchar( '\n' );
|
||||
}
|
||||
else // (*arg == 't' || *arg == 'T')
|
||||
{
|
||||
BOOL title = (*arg == 'T');
|
||||
get_arg( arg, &argv, &cmd );
|
||||
if (*arg == '\0')
|
||||
wcscpy( arg, L"-" );
|
||||
do
|
||||
{
|
||||
if (title)
|
||||
{
|
||||
wprintf( L"==> %s <==\n", arg );
|
||||
display( arg, title );
|
||||
putwchar( '\n' );
|
||||
}
|
||||
else
|
||||
display( arg, title );
|
||||
get_arg( arg, &argv, &cmd );
|
||||
} while (*arg);
|
||||
}
|
||||
|
||||
if (ansi)
|
||||
FreeLibrary( ansi );
|
||||
}
|
||||
|
||||
if (run || *arg)
|
||||
set_original_attr();
|
||||
else
|
||||
CloseHandle( hConOut );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void print_error( LPCTSTR name, BOOL title )
|
||||
{
|
||||
LPTSTR errmsg;
|
||||
|
||||
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
NULL, GetLastError(), 0, (LPTSTR)(LPVOID)&errmsg, 0, NULL );
|
||||
if (!title)
|
||||
wprintf( L"ANSICON: %s: ", name );
|
||||
fputws( errmsg, stdout );
|
||||
LocalFree( errmsg );
|
||||
}
|
||||
|
||||
|
||||
// Display a file.
|
||||
void display( LPCTSTR name, BOOL title )
|
||||
{
|
||||
HANDLE file;
|
||||
int c;
|
||||
LARGE_INTEGER size, offset;
|
||||
HANDLE in, out;
|
||||
BOOL pipe;
|
||||
char buf[8192];
|
||||
DWORD len;
|
||||
|
||||
// Handle the pipe differently.
|
||||
if (*name == '-' && name[1] == '\0')
|
||||
{
|
||||
if (title)
|
||||
putwchar( '\n' );
|
||||
while ((c = getchar()) != EOF)
|
||||
putchar( c );
|
||||
return;
|
||||
}
|
||||
|
||||
file = CreateFile( name, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, 0, NULL );
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
print_error( name, title );
|
||||
return;
|
||||
}
|
||||
|
||||
GetFileSizeEx( file, &size );
|
||||
if (size.QuadPart != 0)
|
||||
{
|
||||
HANDLE map = CreateFileMapping( file, NULL, PAGE_READONLY, 0, 0, NULL );
|
||||
if (map)
|
||||
{
|
||||
if (title)
|
||||
putwchar( '\n' );
|
||||
offset.QuadPart = 0;
|
||||
do
|
||||
{
|
||||
DWORD len = (size.QuadPart > 65536) ? 65536 : size.LowPart;
|
||||
LPVOID mem = MapViewOfFile( map, FILE_MAP_READ, offset.HighPart,
|
||||
offset.LowPart, len );
|
||||
if (mem)
|
||||
{
|
||||
fwrite( mem, 1, len, stdout );
|
||||
UnmapViewOfFile( mem );
|
||||
pipe = TRUE;
|
||||
in = GetStdHandle( STD_INPUT_HANDLE );
|
||||
}
|
||||
else
|
||||
{
|
||||
print_error( name, title );
|
||||
pipe = FALSE;
|
||||
in = CreateFile( name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL );
|
||||
if (in == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
print_error( name );
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (title)
|
||||
{
|
||||
putwchar( '\n' );
|
||||
// Need to flush, otherwise it's written *after* STD_OUTPUT_HANDLE should
|
||||
// it be redirected.
|
||||
fflush( stdout );
|
||||
}
|
||||
out = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
for (;;)
|
||||
{
|
||||
if (!ReadFile( in, buf, sizeof(buf), &len, NULL ))
|
||||
{
|
||||
if (GetLastError() != ERROR_BROKEN_PIPE)
|
||||
print_error( name );
|
||||
break;
|
||||
}
|
||||
offset.QuadPart += len;
|
||||
size.QuadPart -= len;
|
||||
} while (size.QuadPart);
|
||||
CloseHandle( map );
|
||||
if (len == 0)
|
||||
break;
|
||||
WriteFile( out, buf, len, &len, NULL );
|
||||
}
|
||||
if (!pipe)
|
||||
CloseHandle( in );
|
||||
}
|
||||
|
||||
|
||||
void print_error( LPCTSTR name, ... )
|
||||
{
|
||||
LPTSTR errmsg = NULL;
|
||||
DWORD err = GetLastError();
|
||||
va_list arg;
|
||||
|
||||
if (err == ERROR_BAD_EXE_FORMAT)
|
||||
{
|
||||
// This error requires an argument, which is a duplicate of name.
|
||||
va_start( arg, name );
|
||||
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, &arg );
|
||||
va_end( arg );
|
||||
fwprintf( stderr, L"ANSICON: %s", errmsg );
|
||||
}
|
||||
else
|
||||
print_error( name, title );
|
||||
{
|
||||
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, NULL );
|
||||
// Just in case there are other messages requiring args...
|
||||
if (errmsg == NULL)
|
||||
fwprintf( stderr, L"ANSICON: %s: Error %lu.\n", name, err );
|
||||
else
|
||||
fwprintf( stderr, L"ANSICON: %s: %s", name, errmsg );
|
||||
}
|
||||
CloseHandle( file );
|
||||
LocalFree( errmsg );
|
||||
}
|
||||
|
||||
|
||||
@ -434,16 +454,19 @@ void display( LPCTSTR name, BOOL title )
|
||||
void process_autorun( TCHAR cmd )
|
||||
{
|
||||
HKEY cmdkey;
|
||||
TCHAR ansicon[MAX_PATH+8];
|
||||
TCHAR ansicon[MAX_PATH+80];
|
||||
TCHAR logstr[80];
|
||||
LPTSTR autorun, ansirun;
|
||||
DWORD len, type, exist;
|
||||
BOOL inst;
|
||||
|
||||
len = GetModuleFileName( NULL, ansicon+2, MAX_PATH );
|
||||
ansicon[0] = '&';
|
||||
ansicon[1] = ansicon[2+len] = '"';
|
||||
wcscpy( ansicon + 3+len, L" -p" );
|
||||
len += 6;
|
||||
if (log_level)
|
||||
_snwprintf( logstr, lenof(logstr), L"set ANSICON_LOG=%d&", log_level );
|
||||
else
|
||||
*logstr = '\0';
|
||||
len = TSIZE(_snwprintf( ansicon, lenof(ansicon),
|
||||
L"(if %%ANSICON_VER%%==^%%ANSICON_VER^%% %s\"%s\" -p)",
|
||||
logstr, prog_path ) + 1);
|
||||
|
||||
inst = (towlower( cmd ) == 'i');
|
||||
RegCreateKeyEx( (iswlower( cmd )) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
|
||||
@ -452,48 +475,58 @@ void process_autorun( TCHAR cmd )
|
||||
&cmdkey, &exist );
|
||||
exist = 0;
|
||||
RegQueryValueEx( cmdkey, AUTORUN, NULL, NULL, NULL, &exist );
|
||||
autorun = malloc( exist + len * sizeof(TCHAR) + sizeof(TCHAR) );
|
||||
// Let's assume there's sufficient memory.
|
||||
if (exist > sizeof(TCHAR))
|
||||
if (exist == 0)
|
||||
{
|
||||
exist += sizeof(TCHAR);
|
||||
RegQueryValueEx( cmdkey, AUTORUN, NULL, &type, (PBYTE)autorun, &exist );
|
||||
ansirun = wcsstr( autorun, ansicon+1 );
|
||||
if (inst)
|
||||
{
|
||||
if (!ansirun)
|
||||
{
|
||||
wcscpy( (LPTSTR)((PBYTE)autorun + exist - sizeof(TCHAR)), ansicon );
|
||||
RegSetValueEx( cmdkey, AUTORUN, 0, type, (PBYTE)autorun,
|
||||
exist + len*sizeof(TCHAR) );
|
||||
}
|
||||
RegSetValueEx( cmdkey, AUTORUN, 0, REG_SZ, (PBYTE)ansicon, len );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ansirun)
|
||||
// Let's assume there's sufficient memory.
|
||||
autorun = malloc( exist + len );
|
||||
RegQueryValueEx( cmdkey, AUTORUN, NULL, &type, (PBYTE)autorun, &exist );
|
||||
// Remove the existing command, if present.
|
||||
ansirun = wcsstr( autorun, L"(if %ANSICON_VER%" );
|
||||
if (ansirun != NULL)
|
||||
{
|
||||
if (ansirun == autorun && exist == len*sizeof(TCHAR))
|
||||
RegDeleteValue( cmdkey, AUTORUN );
|
||||
else
|
||||
LPTSTR tmp = wcschr( ansirun, '"' ); // opening quote
|
||||
tmp = wcschr( tmp + 1, '"' ); // closing quote
|
||||
tmp = wcschr( tmp + 1, ')' ); // closing bracket
|
||||
if (*++tmp == '&')
|
||||
++tmp;
|
||||
if (*tmp == '&')
|
||||
++tmp;
|
||||
if (*tmp == '\0')
|
||||
{
|
||||
if (ansirun > autorun && ansirun[-1] == '&')
|
||||
--ansirun;
|
||||
else if (autorun[len-1] != '&')
|
||||
--len;
|
||||
memcpy( ansirun, ansirun + len, exist - len*sizeof(TCHAR) );
|
||||
RegSetValueEx( cmdkey, AUTORUN, 0, type, (PBYTE)autorun,
|
||||
exist - len*sizeof(TCHAR) );
|
||||
if (ansirun > autorun && ansirun[-1] == '&')
|
||||
--ansirun;
|
||||
}
|
||||
wcscpy( ansirun, tmp );
|
||||
exist = TSIZE((DWORD)wcslen( autorun ) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (inst)
|
||||
if (inst)
|
||||
{
|
||||
RegSetValueEx( cmdkey, AUTORUN, 0, REG_SZ, (PBYTE)(ansicon+1),
|
||||
len*sizeof(TCHAR) );
|
||||
if (exist == sizeof(TCHAR))
|
||||
RegSetValueEx( cmdkey, AUTORUN, 0, REG_SZ, (PBYTE)ansicon, len );
|
||||
else
|
||||
{
|
||||
memmove( (PBYTE)autorun + len, autorun, exist );
|
||||
memcpy( autorun, ansicon, len );
|
||||
((PBYTE)autorun)[len-sizeof(TCHAR)] = '&';
|
||||
RegSetValueEx( cmdkey, AUTORUN, 0, type, (PBYTE)autorun, exist+len );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exist == sizeof(TCHAR))
|
||||
RegDeleteValue( cmdkey, AUTORUN );
|
||||
else
|
||||
RegSetValueEx( cmdkey, AUTORUN, 0, type, (PBYTE)autorun, exist );
|
||||
}
|
||||
|
||||
free( autorun );
|
||||
}
|
||||
RegCloseKey( cmdkey );
|
||||
}
|
||||
|
||||
@ -513,20 +546,19 @@ BOOL find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe )
|
||||
|
||||
|
||||
// Obtain the process and thread identifiers of the parent process.
|
||||
BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi )
|
||||
BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name )
|
||||
{
|
||||
HANDLE hSnap;
|
||||
PROCESSENTRY32 pe;
|
||||
THREADENTRY32 te;
|
||||
DWORD id = GetCurrentProcessId();
|
||||
BOOL fOk;
|
||||
|
||||
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD, id );
|
||||
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD, 0 );
|
||||
|
||||
if (hSnap == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
find_proc_id( hSnap, id, &pe );
|
||||
find_proc_id( hSnap, GetCurrentProcessId(), &pe );
|
||||
if (!find_proc_id( hSnap, pe.th32ParentProcessID, &pe ))
|
||||
{
|
||||
CloseHandle( hSnap );
|
||||
@ -542,38 +574,53 @@ BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi )
|
||||
|
||||
ppi->dwProcessId = pe.th32ProcessID;
|
||||
ppi->dwThreadId = te.th32ThreadID;
|
||||
wcscpy( name, pe.szExeFile );
|
||||
|
||||
return fOk;
|
||||
}
|
||||
|
||||
|
||||
// Return the first non-space character from cmd.
|
||||
LPTSTR skip_spaces( LPTSTR cmd )
|
||||
// Return the first non-space character from arg.
|
||||
LPTSTR skip_spaces( LPTSTR arg )
|
||||
{
|
||||
while ((*cmd == ' ' || *cmd == '\t') && *cmd != '\0')
|
||||
++cmd;
|
||||
while (*arg == ' ' || *arg == '\t')
|
||||
++arg;
|
||||
|
||||
return cmd;
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
// Return the end of the argument at cmd.
|
||||
LPTSTR skip_arg( LPTSTR cmd )
|
||||
// Retrieve an argument from the command line. cmd gets the existing argv; argv
|
||||
// is ready for the next argument.
|
||||
void get_arg( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd )
|
||||
{
|
||||
while (*cmd != ' ' && *cmd != '\t' && *cmd != '\0')
|
||||
{
|
||||
if (*cmd == '"')
|
||||
{
|
||||
do
|
||||
++cmd;
|
||||
while (*cmd != '"' && *cmd != '\0');
|
||||
if (*cmd == '\0')
|
||||
--cmd;
|
||||
}
|
||||
++cmd;
|
||||
}
|
||||
LPTSTR line;
|
||||
|
||||
return cmd;
|
||||
line = *cmd = skip_spaces( *argv );
|
||||
while (*line != '\0')
|
||||
{
|
||||
if (*line == ' ' || *line == '\t')
|
||||
{
|
||||
++line;
|
||||
break;
|
||||
}
|
||||
if (*line == '"')
|
||||
{
|
||||
while (*++line != '\0')
|
||||
{
|
||||
if (*line == '"')
|
||||
{
|
||||
++line;
|
||||
break;
|
||||
}
|
||||
*arg++ = *line;
|
||||
}
|
||||
}
|
||||
else
|
||||
*arg++ = *line++;
|
||||
}
|
||||
*arg = '\0';
|
||||
*argv = line;
|
||||
}
|
||||
|
||||
|
||||
@ -590,10 +637,12 @@ L"Process ANSI escape sequences in Windows console programs.\n"
|
||||
L"Process ANSI escape sequences in Win32 console programs.\n"
|
||||
#endif
|
||||
L"\n"
|
||||
L"ansicon -i|I | -u|U\n"
|
||||
L"ansicon [-m[<attr>]] [-p | -e|E string | -t|T [file(s)] | program [args]]\n"
|
||||
L"ansicon [-l<level>] [-i] [-I] [-u] [-U] [-m[<attr>]] [-p]\n"
|
||||
L" [-e|E string | -t|T [file(s)] | program [args]]\n"
|
||||
L"\n"
|
||||
L" -i\t\tinstall - add ANSICON to the AutoRun entry (implies -p)\n"
|
||||
L" -l\t\tset the logging level (1=process, 2=module, 3=function,\n"
|
||||
L" \t\t +4=output, +8=append) for program (-p is unaffected)\n"
|
||||
L" -i\t\tinstall - add ANSICON to the AutoRun entry (also implies -p)\n"
|
||||
L" -u\t\tuninstall - remove ANSICON from the AutoRun entry\n"
|
||||
L" -I -U\t\tuse local machine instead of current user\n"
|
||||
L" -m\t\tuse grey on black (\"monochrome\") or <attr> as default color\n"
|
||||
@ -605,6 +654,7 @@ L" -T\t\tdisplay files, name first, blank line before and after\n"
|
||||
L" program\trun the specified program\n"
|
||||
L" nothing\trun a new command processor, or display stdin if redirected\n"
|
||||
L"\n"
|
||||
L"<attr> is one or two hexadecimal digits; please use \"COLOR /?\" for details."
|
||||
L"<attr> is one or two hexadecimal digits; please use \"COLOR /?\" for details.\n"
|
||||
L"It may start with '-' to reverse foreground and background (but not for -p)."
|
||||
);
|
||||
}
|
||||
|
37
ansicon.h
37
ansicon.h
@ -18,29 +18,30 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#define lenof(array) (sizeof(array)/sizeof(*(array)))
|
||||
#define TSIZE(size) ((size) * sizeof(TCHAR))
|
||||
|
||||
|
||||
int ProcessType( LPPROCESS_INFORMATION );
|
||||
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, BOOL* );
|
||||
void InjectDLL32( LPPROCESS_INFORMATION, LPCTSTR );
|
||||
void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR );
|
||||
|
||||
extern TCHAR prog_path[MAX_PATH];
|
||||
extern LPTSTR prog;
|
||||
LPTSTR get_program_name( LPTSTR );
|
||||
|
||||
// ========== Auxiliary debug function
|
||||
|
||||
#ifndef MYDEBUG
|
||||
# define MYDEBUG 0 // 0 - no debugging
|
||||
// 1 - use OutputDebugString
|
||||
// 2 - use %temp%\ansicon.log
|
||||
#endif
|
||||
|
||||
#if (MYDEBUG > 0)
|
||||
void DEBUGSTR( LPTSTR szFormat, ... );
|
||||
#else
|
||||
# if defined(_MSC_VER) && _MSC_VER <= 1400
|
||||
#define DEBUGSTR (void)
|
||||
# else
|
||||
# define DEBUGSTR(...)
|
||||
# endif
|
||||
#endif
|
||||
extern int log_level;
|
||||
void DEBUGSTR( int level, LPTSTR szFormat, ... );
|
||||
|
||||
#endif
|
||||
|
@ -5,10 +5,11 @@
|
||||
*/
|
||||
|
||||
#include <winver.h>
|
||||
#include "version.h"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 1,4,0,0
|
||||
PRODUCTVERSION 1,4,0,0
|
||||
FILEVERSION PVERB
|
||||
PRODUCTVERSION PVERB
|
||||
FILEOS VOS_NT
|
||||
FILETYPE VFT_APP
|
||||
{
|
||||
@ -19,12 +20,12 @@ FILETYPE VFT_APP
|
||||
VALUE "Comments", "http://ansicon.adoxa.cjb.net/"
|
||||
VALUE "CompanyName", "Jason Hood"
|
||||
VALUE "FileDescription", "ANSI Console"
|
||||
VALUE "FileVersion", "1.40"
|
||||
VALUE "FileVersion", PVERSA
|
||||
VALUE "InternalName", "ansicon"
|
||||
VALUE "LegalCopyright", "Freeware"
|
||||
VALUE "OriginalFilename", "ansicon.exe"
|
||||
VALUE "ProductName", "ANSICON"
|
||||
VALUE "ProductVersion", "1.40"
|
||||
VALUE "ProductVersion", PVERSA
|
||||
}
|
||||
}
|
||||
|
||||
|
102
debugstr.c
102
debugstr.c
@ -1,102 +0,0 @@
|
||||
/*
|
||||
debugstr.c - Auxiliary debug functionality.
|
||||
*/
|
||||
|
||||
#include "ansicon.h"
|
||||
|
||||
#if (MYDEBUG > 1)
|
||||
char tempfile[MAX_PATH];
|
||||
#endif
|
||||
|
||||
#if (MYDEBUG > 0)
|
||||
void DEBUGSTR( LPTSTR szFormat, ... ) // sort of OutputDebugStringf
|
||||
{
|
||||
TCHAR szBuffer[1024], szEscape[1024];
|
||||
va_list pArgList;
|
||||
|
||||
#if (MYDEBUG > 1)
|
||||
if (*tempfile == '\0')
|
||||
_snprintf( tempfile, MAX_PATH, "%s\\ansicon.log", getenv( "TEMP" ) );
|
||||
if (szFormat == NULL)
|
||||
{
|
||||
DeleteFileA( tempfile );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
va_start( pArgList, szFormat );
|
||||
_vsnwprintf( szBuffer, lenof(szBuffer), szFormat, pArgList );
|
||||
va_end( pArgList );
|
||||
|
||||
szFormat = szBuffer;
|
||||
if (*szFormat == '\33')
|
||||
{
|
||||
BOOL first = TRUE;
|
||||
LPTSTR pos = szEscape;
|
||||
while (*++szFormat != '\0' && pos < szEscape + lenof(szEscape) - 4)
|
||||
{
|
||||
if (*szFormat < 32)
|
||||
{
|
||||
*pos++ = '\\';
|
||||
switch (*szFormat)
|
||||
{
|
||||
case '\a': *pos++ = 'a'; break;
|
||||
case '\b': *pos++ = 'b'; break;
|
||||
case '\t': *pos++ = 't'; break;
|
||||
case '\r': *pos++ = 'r'; break;
|
||||
case '\n': *pos++ = 'n'; break;
|
||||
case 27 : *pos++ = 'e'; break;
|
||||
default:
|
||||
pos += _snwprintf( pos, 32, L"%.*o",
|
||||
(szFormat[1] >= '0' && szFormat[1] <= '7') ? 3 : 1,
|
||||
*szFormat );
|
||||
}
|
||||
}
|
||||
else if (*szFormat == '"')
|
||||
{
|
||||
if (first)
|
||||
first = FALSE;
|
||||
else if (szFormat[1] == '\0')
|
||||
;
|
||||
else
|
||||
*pos++ = '\\';
|
||||
*pos++ = '"';
|
||||
}
|
||||
else
|
||||
{
|
||||
*pos++ = *szFormat;
|
||||
}
|
||||
}
|
||||
*pos = '\0';
|
||||
szFormat = szEscape;
|
||||
}
|
||||
#if (MYDEBUG > 1)
|
||||
{
|
||||
HANDLE mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );
|
||||
DWORD wait = WaitForSingleObject( mutex, 500 );
|
||||
FILE* file = fopen( tempfile, "at" ); // _fmode might be binary
|
||||
if (file != NULL)
|
||||
{
|
||||
TCHAR path[MAX_PATH];
|
||||
LPTSTR prog, ext;
|
||||
GetModuleFileName( NULL, path, lenof(path) );
|
||||
prog = wcsrchr( path, '\\' );
|
||||
if (prog != NULL)
|
||||
++prog;
|
||||
else
|
||||
prog = path;
|
||||
ext = wcsrchr( prog, '.' );
|
||||
if (ext != NULL)
|
||||
*ext = '\0';
|
||||
fwprintf( file, L"%s: %s\n", prog, szFormat );
|
||||
fclose( file );
|
||||
}
|
||||
if (wait == WAIT_OBJECT_0)
|
||||
ReleaseMutex( mutex );
|
||||
CloseHandle( mutex );
|
||||
}
|
||||
#else
|
||||
OutputDebugString( szFormat );
|
||||
#endif
|
||||
}
|
||||
#endif
|
15
injdll32.c
15
injdll32.c
@ -43,17 +43,16 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
||||
LPVOID mem;
|
||||
DWORD mem32;
|
||||
#define CODESIZE 20
|
||||
BYTE code[CODESIZE+MAX_PATH*sizeof(TCHAR)];
|
||||
BYTE code[CODESIZE+TSIZE(MAX_PATH)];
|
||||
union
|
||||
{
|
||||
PBYTE pB;
|
||||
PDWORD pL;
|
||||
} ip;
|
||||
|
||||
len = lstrlen( dll ) + 1;
|
||||
if (len > MAX_PATH)
|
||||
len = TSIZE(lstrlen( dll ) + 1);
|
||||
if (len > TSIZE(MAX_PATH))
|
||||
return;
|
||||
len *= sizeof(TCHAR);
|
||||
|
||||
if (LLW == 0)
|
||||
{
|
||||
@ -66,7 +65,7 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
||||
// Assume if one is defined, so is the other.
|
||||
if (Wow64GetThreadContext == 0)
|
||||
{
|
||||
DEBUGSTR( L"Failed to get pointer to Wow64GetThreadContext.\n" );
|
||||
DEBUGSTR( 1, L"Failed to get pointer to Wow64GetThreadContext.\n" );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -76,13 +75,13 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
||||
ZeroMemory( &si, sizeof(si) );
|
||||
si.cb = sizeof(si);
|
||||
// ...ANSI32.dll\0
|
||||
CopyMemory( code, dll, len - 7*sizeof(TCHAR) );
|
||||
CopyMemory( code, dll, len - TSIZE(7) );
|
||||
// ...ANSI-LLW.exe\0
|
||||
CopyMemory( code + len - 7*sizeof(TCHAR), L"-LLW.exe", 9*sizeof(TCHAR) );
|
||||
CopyMemory( code + len - TSIZE(7), L"-LLW.exe", TSIZE(9) );
|
||||
if (!CreateProcess( (LPCTSTR)code, NULL, NULL, NULL, FALSE, 0, NULL, NULL,
|
||||
&si, &pi ))
|
||||
{
|
||||
DEBUGSTR( L"Failed to execute \"%s\".\n", (LPCTSTR)code );
|
||||
DEBUGSTR( 1, L"Failed to execute \"%s\".\n", (LPCTSTR)code );
|
||||
return;
|
||||
}
|
||||
WaitForSingleObject( pi.hProcess, INFINITE );
|
||||
|
@ -29,7 +29,7 @@ void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
||||
PDWORD64 pL;
|
||||
} ip;
|
||||
#define CODESIZE 92
|
||||
static BYTE code[CODESIZE+MAX_PATH*sizeof(TCHAR)] = {
|
||||
static BYTE code[CODESIZE+TSIZE(MAX_PATH)] = {
|
||||
0,0,0,0,0,0,0,0, // original rip
|
||||
0,0,0,0,0,0,0,0, // LoadLibraryW
|
||||
0x9C, // pushfq
|
||||
@ -72,10 +72,9 @@ void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
||||
0, // dword alignment for LLW, fwiw
|
||||
};
|
||||
|
||||
len = lstrlen( dll ) + 1;
|
||||
if (len > MAX_PATH)
|
||||
len = TSIZE(lstrlen( dll ) + 1);
|
||||
if (len > TSIZE(MAX_PATH))
|
||||
return;
|
||||
len *= sizeof(TCHAR);
|
||||
CopyMemory( code + CODESIZE, dll, len );
|
||||
len += CODESIZE;
|
||||
|
||||
|
39
makefile
39
makefile
@ -1,29 +1,32 @@
|
||||
# Makefile for ANSICON.
|
||||
# Jason Hood, 11 March, 2006. Updated 20 June, 2009.
|
||||
|
||||
# I've used TDM64 (gcc 4.5.0), building the 32-bit version in the x86 directory
|
||||
# I've used TDM64 (gcc 4.6.1), building the 32-bit version in the x86 directory
|
||||
# and the 64-bit version in the x64 directory. MinGW32 (gcc 3.4.5) will also
|
||||
# build the 32-bit version, but will of course fail on the 64-bit.
|
||||
# build the 32-bit version.
|
||||
|
||||
# 19 November, 2010:
|
||||
# explicitly use 64-bit flags, in case the compiler isn't.
|
||||
#
|
||||
# 13 December, 2011:
|
||||
# use CMD for file operations, not programs from fileutils.
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -O2 -Wall
|
||||
|
||||
X86OBJS = x86/proctype.o x86/injdll32.o x86/debugstr.o
|
||||
X64OBJS = x64/proctype.o x64/injdll64.o x64/injdll32.o x64/debugstr.o
|
||||
X86OBJS = x86/proctype.o x86/injdll32.o x86/util.o
|
||||
X64OBJS = x64/proctype.o x64/injdll64.o x64/injdll32.o x64/util.o
|
||||
|
||||
x86/%.o: %.c ansicon.h
|
||||
$(CC) -m32 -c $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||
$(CC) -m32 -c $(CFLAGS) $< -o $@
|
||||
|
||||
x86/%v.o: %.rc
|
||||
x86/%v.o: %.rc version.h
|
||||
windres -U _WIN64 -F pe-i386 $< $@
|
||||
|
||||
x64/%.o: %.c ansicon.h
|
||||
$(CC) -m64 -c $(CFLAGS) $(CPPFLAGS) $< -o $@
|
||||
$(CC) -m64 -c $(CFLAGS) $< -o $@
|
||||
|
||||
x64/%v.o: %.rc
|
||||
x64/%v.o: %.rc version.h
|
||||
windres -F pe-x86-64 $< $@
|
||||
|
||||
all: ansicon32 ansicon64
|
||||
@ -33,34 +36,40 @@ ansicon32: x86 x86/ansicon.exe x86/ANSI32.dll
|
||||
ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll x64/ANSI32.dll x64/ANSI-LLW.exe
|
||||
|
||||
x86:
|
||||
mkdir x86
|
||||
cmd /c "mkdir x86"
|
||||
|
||||
x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/ansiconv.o
|
||||
$(CC) -m32 $+ -s -o $@ -lpsapi -lole32
|
||||
$(CC) -m32 $+ -s -o $@
|
||||
|
||||
x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o
|
||||
$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared
|
||||
|
||||
x64:
|
||||
mkdir x64
|
||||
cmd /c "mkdir x64"
|
||||
|
||||
x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/ansiconv.o
|
||||
$(CC) -m64 $+ -s -o $@ -lpsapi -lole32
|
||||
$(CC) -m64 $+ -s -o $@
|
||||
|
||||
x64/ANSI64.dll: x64/ANSI.o $(X64OBJS) x64/ansiv.o
|
||||
$(CC) -m64 $+ -s -o $@ -mdll -Wl,-shared
|
||||
|
||||
x64/ANSI32.dll: x86/ANSI32.dll
|
||||
cp -p x86/ANSI32.dll x64/ANSI32.dll
|
||||
cmd /c "copy/y x86\ANSI32.dll x64\ANSI32.dll >nul"
|
||||
|
||||
x64/ANSI-LLW.exe: ANSI-LLW.c
|
||||
$(CC) -m32 $(CFLAGS) $< -s -o $@
|
||||
|
||||
x86/ansicon.o: version.h
|
||||
x86/ANSI.o: version.h
|
||||
x64/ansicon.o: version.h
|
||||
x64/ANSI.o: version.h
|
||||
x86/ansiconv.o: ansicon.rc
|
||||
x86/ansiv.o: ansi.rc
|
||||
x64/ansiconv.o: ansicon.rc
|
||||
x64/ansiv.o: ansi.rc
|
||||
|
||||
# Need two commands, because if the directory doesn't exist, it won't delete
|
||||
# anything at all.
|
||||
clean:
|
||||
-rm x86/*.o
|
||||
-rm x64/*.o
|
||||
-cmd /c "del x86\*.o 2>nul"
|
||||
-cmd /c "del x64\*.o 2>nul"
|
||||
|
23
makefile.vc
23
makefile.vc
@ -26,10 +26,13 @@ DIR = x64
|
||||
|
||||
CC = cl
|
||||
CFLAGS = /nologo /W3 /Ox /GF /D_CRT_SECURE_NO_WARNINGS
|
||||
LIBS = advapi32.lib shell32.lib user32.lib psapi.lib ole32.lib
|
||||
LIBS = advapi32.lib user32.lib
|
||||
|
||||
X86OBJS = x86\proctype.obj x86\injdll32.obj x86\debugstr.obj
|
||||
X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\debugstr.obj
|
||||
# This is required for the 2003 Platform SDK, but not for Visual Studio 2010.
|
||||
#LIBS64 = bufferoverflowu.lib
|
||||
|
||||
X86OBJS = x86\proctype.obj x86\injdll32.obj x86\util.obj
|
||||
X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\util.obj
|
||||
|
||||
{}.c{$(DIR)}.obj:
|
||||
$(CC) /c $(CFLAGS) /Fo$@ $<
|
||||
@ -58,20 +61,22 @@ x64:
|
||||
mkdir x64
|
||||
|
||||
x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res
|
||||
$(CC) /nologo /Fe$@ $** $(LIBS) bufferoverflowu.lib
|
||||
$(CC) /nologo /Fe$@ $** $(LIBS) $(LIBS64)
|
||||
|
||||
x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res
|
||||
$(CC) /nologo /LD /Fe$@ $** $(LIBS) bufferoverflowu.lib
|
||||
$(CC) /nologo /LD /Fe$@ $** $(LIBS) $(LIBS64)
|
||||
|
||||
x64\ANSI32.dll: x86\ANSI32.dll
|
||||
copy x86\ANSI32.dll x64\ANSI32.dll
|
||||
|
||||
x64\ANSI-LLW.exe: ANSI-LLW.c
|
||||
$(CC) $(CFLAGS) /Fe$@ /Fo$*.obj $? bufferoverflowu.lib
|
||||
$(CC) $(CFLAGS) /Fe$@ /Fo$*.obj $? $(LIBS64)
|
||||
|
||||
ansicon.c: ansicon.h
|
||||
ANSI.c: ansicon.h
|
||||
debugstr.c: ansicon.h
|
||||
ansicon.c: ansicon.h version.h
|
||||
ansicon.rc: version.h
|
||||
ANSI.c: ansicon.h version.h
|
||||
ANSI.rc: version.h
|
||||
util.c: ansicon.h
|
||||
injdll32.c: ansicon.h
|
||||
injdll64.c: ansicon.h
|
||||
proctype.c: ansicon.h
|
||||
|
48
proctype.c
48
proctype.c
@ -8,67 +8,75 @@
|
||||
hardly seems worth it. There's GetModuleInformation, but passing in NULL just
|
||||
returns a base of NULL, so that's no help. Since 64/32 is sufficient, let
|
||||
ansicon.exe handle the difference between console/GUI.
|
||||
|
||||
Update: ignore images characterised as DLL.
|
||||
*/
|
||||
|
||||
#include "ansicon.h"
|
||||
|
||||
|
||||
int ProcessType( LPPROCESS_INFORMATION pinfo )
|
||||
int ProcessType( LPPROCESS_INFORMATION pinfo, BOOL* gui )
|
||||
{
|
||||
char* ptr;
|
||||
MEMORY_BASIC_INFORMATION minfo;
|
||||
char* ptr = 0;
|
||||
|
||||
while (VirtualQueryEx( pinfo->hProcess, ptr, &minfo, sizeof(minfo) ))
|
||||
{
|
||||
IMAGE_DOS_HEADER dos_header;
|
||||
IMAGE_NT_HEADERS nt_header;
|
||||
SIZE_T read;
|
||||
|
||||
*gui = FALSE;
|
||||
for (ptr = NULL;
|
||||
VirtualQueryEx( pinfo->hProcess, ptr, &minfo, sizeof(minfo) );
|
||||
ptr += minfo.RegionSize)
|
||||
{
|
||||
if (minfo.BaseAddress == minfo.AllocationBase &&
|
||||
ReadProcessMemory( pinfo->hProcess, minfo.AllocationBase,
|
||||
&dos_header, sizeof(dos_header), &read ))
|
||||
{
|
||||
if (dos_header.e_magic == IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
IMAGE_NT_HEADERS nt_header;
|
||||
if (ReadProcessMemory( pinfo->hProcess, (char*)minfo.AllocationBase +
|
||||
dos_header.e_lfanew, &nt_header,
|
||||
sizeof(nt_header), &read ))
|
||||
{
|
||||
if (nt_header.Signature == IMAGE_NT_SIGNATURE)
|
||||
if (nt_header.Signature == IMAGE_NT_SIGNATURE &&
|
||||
(nt_header.FileHeader.Characteristics &
|
||||
(IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL))
|
||||
== IMAGE_FILE_EXECUTABLE_IMAGE)
|
||||
{
|
||||
BOOL gui = (nt_header.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI);
|
||||
if (nt_header.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI ||
|
||||
gui )
|
||||
*gui = (nt_header.OptionalHeader.Subsystem
|
||||
== IMAGE_SUBSYSTEM_WINDOWS_GUI);
|
||||
if (nt_header.OptionalHeader.Subsystem ==
|
||||
IMAGE_SUBSYSTEM_WINDOWS_CUI || *gui)
|
||||
{
|
||||
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
||||
{
|
||||
DEBUGSTR( L" %p: 32-bit %s",
|
||||
minfo.AllocationBase, (gui) ? L"GUI" : L"console" );
|
||||
DEBUGSTR( 1, L" 32-bit %s (base = %p)",
|
||||
(*gui) ? L"GUI" : L"console", minfo.AllocationBase );
|
||||
return 32;
|
||||
}
|
||||
#ifdef _WIN64
|
||||
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
||||
{
|
||||
DEBUGSTR( L" %p: 64-bit %s",
|
||||
minfo.AllocationBase, (gui) ? L"GUI" : L"console" );
|
||||
DEBUGSTR( 1, L" 64-bit %s (base = %p)",
|
||||
(*gui) ? L"GUI" : L"console", minfo.AllocationBase );
|
||||
return 64;
|
||||
}
|
||||
#endif
|
||||
DEBUGSTR( L" Ignoring unsupported machine (0x%X)",
|
||||
DEBUGSTR( 1, L" Ignoring unsupported machine (0x%X)",
|
||||
nt_header.FileHeader.Machine );
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGSTR( L" Ignoring non-Windows subsystem (%u)",
|
||||
DEBUGSTR( 1, L" Ignoring unsupported subsystem (%u)",
|
||||
nt_header.OptionalHeader.Subsystem );
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ptr += minfo.RegionSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGSTR( L" Ignoring non-Windows process" );
|
||||
DEBUGSTR( 1, L" Ignoring non-Windows process" );
|
||||
return 0;
|
||||
}
|
||||
|
71
readme.txt
71
readme.txt
@ -3,7 +3,7 @@
|
||||
|
||||
Copyright 2005-2011 Jason Hood
|
||||
|
||||
Version 1.40. Freeware
|
||||
Version 1.50. Freeware
|
||||
|
||||
|
||||
===========
|
||||
@ -30,9 +30,9 @@
|
||||
use option `-i' (or `-I') to install it permanently, by adding an entry
|
||||
to CMD.EXE's AutoRun registry value (current user or local machine,
|
||||
respectively). Uninstall simply involves closing any programs that are
|
||||
currently using it, running with `-u' (and again with `-U') to remove
|
||||
the AutoRun entry/ies, then removing the directory from PATH or deleting
|
||||
the files. No other changes are made.
|
||||
currently using it, running with `-u' (and/or `-U') to remove the Auto-
|
||||
Run entry/ies, then removing the directory from PATH or deleting the
|
||||
files. No other changes are made.
|
||||
|
||||
---------
|
||||
Upgrading
|
||||
@ -40,6 +40,7 @@
|
||||
|
||||
Delete ANSI.dll, it has been replaced with ANSI32.dll.
|
||||
Delete ANSI-LLA.dll, it has been replaced with ANSI-LLW.dll.
|
||||
Uninstall with your current version and install with this version.
|
||||
|
||||
|
||||
=====
|
||||
@ -48,6 +49,8 @@
|
||||
|
||||
Options (case sensitive):
|
||||
|
||||
-l Log to %temp%\ansicon.log.
|
||||
|
||||
-p Enable the parent process (i.e. the command shell used to
|
||||
run ANSICON) to recognise escapes.
|
||||
|
||||
@ -55,7 +58,7 @@
|
||||
("monochrome"), or the attribute following the `m' (please
|
||||
use `COLOR /?' for attribute values).
|
||||
|
||||
-e Echo the command line - the character after the `e' is
|
||||
-e Echo the command line - a space or tab after the `e' is
|
||||
ignored, the remainder is displayed verbatim.
|
||||
|
||||
-E As above, but no newline is added.
|
||||
@ -74,12 +77,46 @@
|
||||
Eg: `ansicon -m30 -t file.ans' will display `file.ans' using black on
|
||||
cyan as the default color.
|
||||
|
||||
The attribute may start with "-" to permanently reverse the foreground
|
||||
and background colors (but not when using `-p'). Eg: `ansicon -m-f0 -t
|
||||
file.log' will use reversed black on white as the default (i.e. white on
|
||||
black, with foreground sequences changing the background).
|
||||
|
||||
If you experience trouble with certain programs, the log may help in
|
||||
finding the cause; it can be found at "%TEMP%\ansicon.log". A number
|
||||
should follow the `l':
|
||||
|
||||
0 No logging
|
||||
1 Log process start and end
|
||||
2 Above, plus log modules used by the process
|
||||
3 Above, plus log functions that are hooked
|
||||
4 Log console output (add to any of the above)
|
||||
8 Append to the existing file (add to any of the above)
|
||||
|
||||
The log option will not work with `-p'; set the environment variable
|
||||
ANSICON_LOG instead. The variable is only read once when a new process
|
||||
is started; changing it won't affect running processes. If you identify
|
||||
a module that causes problems (one known is "nvd3d9wrap.dll") add it to
|
||||
the ANSICON_EXC environment variable (see ANSICON_API below, but the
|
||||
extension is required).
|
||||
|
||||
Once installed, the ANSICON environment variable will be created. This
|
||||
variable is of the form "WxH (wxh)", where W & H are the width and
|
||||
height of the buffer and w & h are the width and height of the window.
|
||||
The variable is updated whenever a program reads it directly (i.e. as
|
||||
an individual request, not as part of the entire environment block).
|
||||
For example, "set an" will not update it, but "echo %ansicon%" will.
|
||||
Also created is ANSICON_VER, which contains the version without the
|
||||
point (1.50 becomes "150"). This variable does not exist as part of the
|
||||
environment block ("set an" will not show it).
|
||||
|
||||
If installed, GUI programs will not be hooked. Either start the program
|
||||
directly with `ansicon', or add it to the ANSICON_GUI variable (see
|
||||
ANSICON_API below).
|
||||
|
||||
Using `ansicon' after install will always start with the default attrib-
|
||||
utes, restoring the originals on exit; all other programs will use the
|
||||
current attributes. The shift state is always reset for a new process.
|
||||
|
||||
The Windows API WriteFile and WriteConsoleA functions will set the num-
|
||||
ber of characters written, not the number of bytes. When using a multi-
|
||||
@ -142,7 +179,10 @@
|
||||
I make a distinction between "\e[m" and "\e[0;...m". Both will restore
|
||||
the original foreground/background colors (and so "0" should be the
|
||||
first parameter); the former will also restore the original bold and
|
||||
underline attributes, whilst the latter will explicitly reset them.
|
||||
underline attributes, whilst the latter will explicitly reset them. The
|
||||
environment variable ANSICON_DEF can be used to change the default col-
|
||||
ors (same value as `-m'; setting the variable does not change the cur-
|
||||
rent colors).
|
||||
|
||||
|
||||
=================
|
||||
@ -217,8 +257,6 @@
|
||||
|
||||
The entire console buffer is used, not just the visible window.
|
||||
|
||||
If running CMD.EXE, its own COLOR will be the initial color.
|
||||
|
||||
The 64-bit version can inject into a 32-bit process, but the 32-bit
|
||||
version will not inject into a 64-bit process.
|
||||
|
||||
@ -231,6 +269,19 @@
|
||||
|
||||
Legend: + added, - bug-fixed, * changed.
|
||||
|
||||
1.50 - 14 December, 2011:
|
||||
- -u does not imply -p;
|
||||
- return the program's exit code;
|
||||
- -p by itself will not restore original color;
|
||||
- output error messages to stderr;
|
||||
* logging is always available, with various levels; include the pid;
|
||||
* don't automatically hook GUI programs, use `ansicon' or ANSICON_GUI;
|
||||
* always place first in AutoRun; don't run if already installed;
|
||||
+ global reverse video capability;
|
||||
+ added ANSICON_VER to provide version/install test;
|
||||
+ added ANSICON_EXC to exclude selected modules;
|
||||
+ added ANSICON_DEF to explicitly set the default SGM.
|
||||
|
||||
1.40 - 1 March, 2011:
|
||||
- hook GetProcAddress (now PowerShell works);
|
||||
+ add SO/SI, using the DEC Special Graphics Character Set for G1;
|
||||
@ -364,5 +415,5 @@
|
||||
in the version text and a source diff is included.
|
||||
|
||||
|
||||
==========================
|
||||
Jason Hood, 3 March, 2011.
|
||||
==============================
|
||||
Jason Hood, 14 December, 2011.
|
||||
|
125
util.c
Normal file
125
util.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
util.c - Utility functions.
|
||||
*/
|
||||
|
||||
#include "ansicon.h"
|
||||
|
||||
|
||||
TCHAR prog_path[MAX_PATH];
|
||||
LPTSTR prog;
|
||||
int log_level;
|
||||
char tempfile[MAX_PATH];
|
||||
DWORD pid;
|
||||
|
||||
|
||||
// Get just the name of the program: "C:\path\program.exe" -> "program".
|
||||
// Returns a pointer within program; it is modified to remove the extension.
|
||||
LPTSTR get_program_name( LPTSTR program )
|
||||
{
|
||||
LPTSTR name, ext;
|
||||
|
||||
if (program == NULL)
|
||||
{
|
||||
GetModuleFileName( NULL, prog_path, lenof(prog_path) );
|
||||
program = prog_path;
|
||||
}
|
||||
name = wcsrchr( program, '\\' );
|
||||
if (name != NULL)
|
||||
++name;
|
||||
else
|
||||
name = program;
|
||||
ext = wcsrchr( name, '.' );
|
||||
if (ext != NULL && ext != name)
|
||||
*ext = '\0';
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void DEBUGSTR( int level, LPTSTR szFormat, ... )
|
||||
{
|
||||
TCHAR szBuffer[1024], szEscape[1024];
|
||||
va_list pArgList;
|
||||
HANDLE mutex;
|
||||
DWORD wait;
|
||||
FILE* file;
|
||||
|
||||
if ((log_level & 3) < level && !(level & 4 & log_level))
|
||||
return;
|
||||
|
||||
if (*tempfile == '\0')
|
||||
{
|
||||
_snprintf( tempfile, MAX_PATH, "%s\\ansicon.log", getenv( "TEMP" ) );
|
||||
pid = GetCurrentProcessId();
|
||||
}
|
||||
if (szFormat == NULL)
|
||||
{
|
||||
file = fopen( tempfile, "wt" );
|
||||
if (file != NULL)
|
||||
{
|
||||
SYSTEMTIME now;
|
||||
GetLocalTime( &now );
|
||||
fprintf( file, "Logging started %d-%.2d-%.2d %d:%.2d:%.2d\n",
|
||||
now.wYear, now.wMonth, now.wDay,
|
||||
now.wHour, now.wMinute, now.wSecond );
|
||||
fclose( file );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
va_start( pArgList, szFormat );
|
||||
_vsnwprintf( szBuffer, lenof(szBuffer), szFormat, pArgList );
|
||||
va_end( pArgList );
|
||||
|
||||
szFormat = szBuffer;
|
||||
if (*szFormat == '\33')
|
||||
{
|
||||
BOOL first = TRUE;
|
||||
LPTSTR pos = szEscape;
|
||||
while (*++szFormat != '\0' && pos < szEscape + lenof(szEscape) - 4)
|
||||
{
|
||||
if (*szFormat < 32)
|
||||
{
|
||||
*pos++ = '\\';
|
||||
switch (*szFormat)
|
||||
{
|
||||
case '\a': *pos++ = 'a'; break;
|
||||
case '\b': *pos++ = 'b'; break;
|
||||
case '\t': *pos++ = 't'; break;
|
||||
case '\r': *pos++ = 'r'; break;
|
||||
case '\n': *pos++ = 'n'; break;
|
||||
case 27 : *pos++ = 'e'; break;
|
||||
default:
|
||||
pos += _snwprintf( pos, 32, L"%.*o",
|
||||
(szFormat[1] >= '0' && szFormat[1] <= '7') ? 3 : 1,
|
||||
*szFormat );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*szFormat == '"')
|
||||
{
|
||||
if (first)
|
||||
first = FALSE;
|
||||
else if (szFormat[1] != '\0')
|
||||
*pos++ = '\\';
|
||||
}
|
||||
*pos++ = *szFormat;
|
||||
}
|
||||
}
|
||||
*pos = '\0';
|
||||
szFormat = szEscape;
|
||||
}
|
||||
|
||||
mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );
|
||||
wait = WaitForSingleObject( mutex, 500 );
|
||||
file = fopen( tempfile, "at" ); // _fmode might be binary
|
||||
if (file != NULL)
|
||||
{
|
||||
fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat );
|
||||
fclose( file );
|
||||
}
|
||||
if (wait == WAIT_OBJECT_0)
|
||||
ReleaseMutex( mutex );
|
||||
CloseHandle( mutex );
|
||||
}
|
9
version.h
Normal file
9
version.h
Normal file
@ -0,0 +1,9 @@
|
||||
/*
|
||||
version.h - Version defines.
|
||||
*/
|
||||
|
||||
#define PVERS L"1.50" // wide string
|
||||
#define PVERSA "1.50" // ANSI string (windres 2.16.91 didn't like L)
|
||||
#define PVERE L"150" // wide environment string
|
||||
#define PVEREA "150" // ANSI environment string
|
||||
#define PVERB 1,5,0,0 // binary (resource)
|
Loading…
x
Reference in New Issue
Block a user