Many changes, bad programmer!
Just copying the history from the source:
recognize the standard handle defines in WriteFile;
minor speed improvement by caching GetConsoleMode;
keep track of three handles (ostensibly stdout, stderr and a file);
test a DOS header exists before writing to e_oemid;
more flexible/robust handling of data directories;
files writing to the console will always succeed;
log: use API file functions and a custom printf;
     add a blank line between processes;
     set function name for MyWriteConsoleA;
scan imports from "kernel32" (without extension);
added dynamic environment variable CLICOLOR;
removed _hwrite (it's the same address as _lwrite);
join multibyte characters split across separate writes;
remove wcstok, avoiding potential interference with the host;
similarly, use a private heap instead of malloc.
			
			
This commit is contained in:
		
							parent
							
								
									2f18f10719
								
							
						
					
					
						commit
						40f59c543c
					
				
							
								
								
									
										25
									
								
								ansicon.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								ansicon.c
									
									
									
									
									
								
							| @ -87,7 +87,7 @@ | |||||||
| 	 add error codes to some message. | 	 add error codes to some message. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #define PDATE L"26 February, 2014" | #define PDATE L"24 December, 2015" | ||||||
| 
 | 
 | ||||||
| #include "ansicon.h" | #include "ansicon.h" | ||||||
| #include "version.h" | #include "version.h" | ||||||
| @ -169,6 +169,7 @@ int my_fputws( const wchar_t* s, FILE* f ) | |||||||
| #define _putws( s ) my_fputws( s L"\n", stdout ) | #define _putws( s ) my_fputws( s L"\n", stdout ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | HANDLE hHeap; | ||||||
| #if defined(_WIN64) | #if defined(_WIN64) | ||||||
| LPTSTR DllNameType; | LPTSTR DllNameType; | ||||||
| #endif | #endif | ||||||
| @ -183,7 +184,7 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app ) | |||||||
| #ifdef _WIN64 | #ifdef _WIN64 | ||||||
|   if (app != NULL) |   if (app != NULL) | ||||||
| #endif | #endif | ||||||
|   DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId ); |   DEBUGSTR( 1, "%S (%u)", app, ppi->dwProcessId ); | ||||||
|   type = ProcessType( ppi, &base, gui ); |   type = ProcessType( ppi, &base, gui ); | ||||||
|   if (type <= 0) |   if (type <= 0) | ||||||
|   { |   { | ||||||
| @ -230,7 +231,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app ) | |||||||
|   int	 type; |   int	 type; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|   DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId ); |   DEBUGSTR( 1, "%S (%u)", app, ppi->dwProcessId ); | ||||||
| 
 | 
 | ||||||
|   // Find the base address of kernel32.dll.
 |   // Find the base address of kernel32.dll.
 | ||||||
|   ticks = GetTickCount(); |   ticks = GetTickCount(); | ||||||
| @ -242,7 +243,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app ) | |||||||
| #ifndef _WIN64 | #ifndef _WIN64 | ||||||
|     if (err == ERROR_PARTIAL_COPY) |     if (err == ERROR_PARTIAL_COPY) | ||||||
|     { |     { | ||||||
|       DEBUGSTR( 1, L"  Ignoring 64-bit process (use x64\\ansicon)" ); |       DEBUGSTR( 1, "  Ignoring 64-bit process (use x64\\ansicon)" ); | ||||||
|       fputws( L"ANSICON: parent is 64-bit (use x64\\ansicon).\n", stderr ); |       fputws( L"ANSICON: parent is 64-bit (use x64\\ansicon).\n", stderr ); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| @ -251,10 +252,10 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app ) | |||||||
|     // two seconds to avoid a potentially infinite loop.
 |     // two seconds to avoid a potentially infinite loop.
 | ||||||
|     if (err == ERROR_BAD_LENGTH && GetTickCount() - ticks < 2000) |     if (err == ERROR_BAD_LENGTH && GetTickCount() - ticks < 2000) | ||||||
|     { |     { | ||||||
|       Sleep( 0 ); |       Sleep( 1 ); | ||||||
|       continue; |       continue; | ||||||
|     } |     } | ||||||
|     DEBUGSTR( 1, L"  Unable to create snapshot (%lu)", err ); |     DEBUGSTR( 1, "  Unable to create snapshot (%u)", err ); | ||||||
|   no_go: |   no_go: | ||||||
|     fputws( L"ANSICON: unable to inject into parent.\n", stderr ); |     fputws( L"ANSICON: unable to inject into parent.\n", stderr ); | ||||||
|     return; |     return; | ||||||
| @ -272,7 +273,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app ) | |||||||
|   CloseHandle( hSnap ); |   CloseHandle( hSnap ); | ||||||
|   if (LLW == NULL) |   if (LLW == NULL) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"  Unable to locate kernel32.dll (%lu)", GetLastError() ); |     DEBUGSTR( 1, "  Unable to locate kernel32.dll" ); | ||||||
|     goto no_go; |     goto no_go; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -292,7 +293,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app ) | |||||||
|   mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE ); |   mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE ); | ||||||
|   if (mem == NULL) |   if (mem == NULL) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"  Unable to allocate virtual memory (%lu)", GetLastError() ); |     DEBUGSTR(1, "  Failed to allocate virtual memory (%u)", GetLastError()); | ||||||
|     goto no_go; |     goto no_go; | ||||||
|   } |   } | ||||||
|   WriteProcMem( mem, DllName, TSIZE(len + 11) ); |   WriteProcMem( mem, DllName, TSIZE(len + 11) ); | ||||||
| @ -357,6 +358,8 @@ int main( void ) | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   hHeap = HeapCreate( 0, 0, 65 * 1024 ); | ||||||
|  | 
 | ||||||
|   prog = get_program_name( NULL ); |   prog = get_program_name( NULL ); | ||||||
|   *buf = '\0'; |   *buf = '\0'; | ||||||
|   GetEnvironmentVariable( L"ANSICON_LOG", buf, lenof(buf) ); |   GetEnvironmentVariable( L"ANSICON_LOG", buf, lenof(buf) ); | ||||||
| @ -369,7 +372,7 @@ int main( void ) | |||||||
|     pi.hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId ); |     pi.hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId ); | ||||||
|     if (pi.hProcess == NULL) |     if (pi.hProcess == NULL) | ||||||
|     { |     { | ||||||
|       DEBUGSTR( 1, L"  Unable to open process %lu (%lu)", |       DEBUGSTR( 1, "  Unable to open process %u (%u)", | ||||||
| 		   pi.dwProcessId, GetLastError() ); | 		   pi.dwProcessId, GetLastError() ); | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
| @ -738,7 +741,7 @@ BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name ) | |||||||
|   hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); |   hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); | ||||||
|   if (hSnap == INVALID_HANDLE_VALUE) |   if (hSnap == INVALID_HANDLE_VALUE) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"Failed to create snapshot (%lu)", GetLastError() ); |     DEBUGSTR( 1, "Failed to create snapshot (%u)", GetLastError() ); | ||||||
|     return FALSE; |     return FALSE; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -747,7 +750,7 @@ BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name ) | |||||||
|   CloseHandle( hSnap ); |   CloseHandle( hSnap ); | ||||||
|   if (!fOk) |   if (!fOk) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"Failed to locate parent" ); |     DEBUGSTR( 1, "Failed to locate parent" ); | ||||||
|     return FALSE; |     return FALSE; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -35,6 +35,7 @@ | |||||||
| // Macro for adding pointers/DWORDs together without C arithmetic interfering
 | // Macro for adding pointers/DWORDs together without C arithmetic interfering
 | ||||||
| #define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset)) | #define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset)) | ||||||
| 
 | 
 | ||||||
|  | #define DATADIRS  OptionalHeader.NumberOfRvaAndSizes | ||||||
| #define EXPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] | #define EXPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] | ||||||
| #define IMPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] | #define IMPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] | ||||||
| #define BOUNDDIR  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] | #define BOUNDDIR  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] | ||||||
| @ -61,6 +62,7 @@ DWORD  GetProcRVA( LPCTSTR, LPCSTR, int ); | |||||||
| DWORD  GetProcRVA( LPCTSTR, LPCSTR ); | DWORD  GetProcRVA( LPCTSTR, LPCSTR ); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | extern HANDLE hHeap; | ||||||
| 
 | 
 | ||||||
| extern TCHAR  prog_path[MAX_PATH]; | extern TCHAR  prog_path[MAX_PATH]; | ||||||
| extern LPTSTR prog; | extern LPTSTR prog; | ||||||
| @ -74,6 +76,6 @@ extern char*  ansi_bits; | |||||||
| void   set_ansi_dll( void ); | void   set_ansi_dll( void ); | ||||||
| 
 | 
 | ||||||
| extern int log_level; | extern int log_level; | ||||||
| void   DEBUGSTR( int level, LPTSTR szFormat, ... ); | void   DEBUGSTR( int level, LPCSTR szFormat, ... ); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
							
								
								
									
										110
									
								
								injdll.c
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								injdll.c
									
									
									
									
									
								
							| @ -38,11 +38,35 @@ static PVOID FindMem( HANDLE hProcess, PBYTE base, DWORD len ) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | // Count the imports directly (including the terminator), since the size of the
 | ||||||
|  | // import directory is not necessarily correct (Windows doesn't use it at all).
 | ||||||
|  | static DWORD sizeof_imports( LPPROCESS_INFORMATION ppi, | ||||||
|  | 			     PBYTE pBase, DWORD rImports ) | ||||||
|  | { | ||||||
|  |   IMAGE_IMPORT_DESCRIPTOR  import; | ||||||
|  |   PIMAGE_IMPORT_DESCRIPTOR pImports; | ||||||
|  |   DWORD cnt; | ||||||
|  | 
 | ||||||
|  |   if (rImports == 0) | ||||||
|  |     return 0; | ||||||
|  | 
 | ||||||
|  |   pImports = (PIMAGE_IMPORT_DESCRIPTOR)(pBase + rImports); | ||||||
|  |   cnt = 0; | ||||||
|  |   do | ||||||
|  |   { | ||||||
|  |     ++cnt; | ||||||
|  |     ReadProcVar( pImports++, &import ); | ||||||
|  |   } while (import.Name != 0); | ||||||
|  | 
 | ||||||
|  |   return cnt * sizeof(import); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | ||||||
| { | { | ||||||
|   DWORD rva; |   DWORD rva; | ||||||
|   PVOID pMem; |   PVOID pMem; | ||||||
|   DWORD len; |   DWORD len, import_size; | ||||||
|   DWORD pr; |   DWORD pr; | ||||||
|   IMAGE_DOS_HEADER	   DosHeader; |   IMAGE_DOS_HEADER	   DosHeader; | ||||||
|   IMAGE_NT_HEADERS	   NTHeader, *pNTHeader; |   IMAGE_NT_HEADERS	   NTHeader, *pNTHeader; | ||||||
| @ -59,18 +83,19 @@ void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | |||||||
|   pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew); |   pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew); | ||||||
|   ReadProcVar( pNTHeader, &NTHeader ); |   ReadProcVar( pNTHeader, &NTHeader ); | ||||||
| 
 | 
 | ||||||
|   len = 4 * PTRSZ + ansi_len + sizeof(*pImports) + NTHeader.IMPORTDIR.Size; |   import_size = sizeof_imports( ppi, pBase, NTHeader.IMPORTDIR.VirtualAddress ); | ||||||
|   pImports = malloc( len ); |   len = 2 * PTRSZ + ansi_len + sizeof(*pImports) + import_size; | ||||||
|  |   pImports = HeapAlloc( hHeap, 0, len ); | ||||||
|   if (pImports == NULL) |   if (pImports == NULL) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"  Failed to allocate memory." ); |     DEBUGSTR( 1, "  Failed to allocate memory" ); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   pMem = FindMem( ppi->hProcess, pBase, len ); |   pMem = FindMem( ppi->hProcess, pBase, len ); | ||||||
|   if (pMem == NULL) |   if (pMem == NULL) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"  Failed to allocate virtual memory." ); |     DEBUGSTR( 1, "  Failed to allocate virtual memory (%u)", GetLastError() ); | ||||||
|     free( pImports ); |     HeapFree( hHeap, 0, pImports ); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   rva = (DWORD)((PBYTE)pMem - pBase); |   rva = (DWORD)((PBYTE)pMem - pBase); | ||||||
| @ -78,37 +103,39 @@ void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | |||||||
|   ip.pL = (PLONG_PTR)pImports; |   ip.pL = (PLONG_PTR)pImports; | ||||||
|   *ip.pL++ = IMAGE_ORDINAL_FLAG + 1; |   *ip.pL++ = IMAGE_ORDINAL_FLAG + 1; | ||||||
|   *ip.pL++ = 0; |   *ip.pL++ = 0; | ||||||
|   *ip.pL++ = IMAGE_ORDINAL_FLAG + 1; |  | ||||||
|   *ip.pL++ = 0; |  | ||||||
|   memcpy( ip.pB, ansi_dll, ansi_len ); |   memcpy( ip.pB, ansi_dll, ansi_len ); | ||||||
|   ip.pB += ansi_len; |   ip.pB += ansi_len; | ||||||
|   ip.pI->OriginalFirstThunk = rva + 2 * PTRSZ; |   ip.pI->OriginalFirstThunk = 0; | ||||||
|   ip.pI->TimeDateStamp = 0; |   ip.pI->TimeDateStamp = 0; | ||||||
|   ip.pI->ForwarderChain = 0; |   ip.pI->ForwarderChain = 0; | ||||||
|   ip.pI->Name = rva + 4 * PTRSZ; |   ip.pI->Name = rva + 2 * PTRSZ; | ||||||
|   ip.pI->FirstThunk = rva; |   ip.pI->FirstThunk = rva; | ||||||
|   ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress, |   ReadProcMem( pBase+NTHeader.IMPORTDIR.VirtualAddress, ip.pI+1, import_size ); | ||||||
| 	       ip.pI + 1, NTHeader.IMPORTDIR.Size ); |  | ||||||
|   WriteProcMem( pMem, pImports, len ); |   WriteProcMem( pMem, pImports, len ); | ||||||
|   free( pImports ); |   HeapFree( hHeap, 0, pImports ); | ||||||
| 
 | 
 | ||||||
|   // If there's no IAT, copy the original IDT (to allow writable ".idata").
 |   // If there's no IAT, copy the original IDT (to allow writable ".idata").
 | ||||||
|   if (NTHeader.IATDIR.VirtualAddress == 0) |   if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_IAT && | ||||||
|  |       NTHeader.IATDIR.VirtualAddress == 0) | ||||||
|     NTHeader.IATDIR = NTHeader.IMPORTDIR; |     NTHeader.IATDIR = NTHeader.IMPORTDIR; | ||||||
| 
 | 
 | ||||||
|   NTHeader.IMPORTDIR.VirtualAddress = rva + 4 * PTRSZ + ansi_len; |   NTHeader.IMPORTDIR.VirtualAddress = rva + 2 * PTRSZ + ansi_len; | ||||||
|   NTHeader.IMPORTDIR.Size += sizeof(*pImports); |   //NTHeader.IMPORTDIR.Size += sizeof(*pImports);
 | ||||||
| 
 | 
 | ||||||
|   // Remove bound imports, so the updated import table is used.
 |   // Remove bound imports, so the updated import table is used.
 | ||||||
|   NTHeader.BOUNDDIR.VirtualAddress = 0; |   if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT) | ||||||
|   NTHeader.BOUNDDIR.Size = 0; |   { | ||||||
|  |     NTHeader.BOUNDDIR.VirtualAddress = 0; | ||||||
|  |     //NTHeader.BOUNDDIR.Size = 0;
 | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   VirtProtVar( pNTHeader, PAGE_READWRITE ); |   VirtProtVar( pNTHeader, PAGE_READWRITE ); | ||||||
|   WriteProcVar( pNTHeader, &NTHeader ); |   WriteProcVar( pNTHeader, &NTHeader ); | ||||||
|   VirtProtVar( pNTHeader, pr ); |   VirtProtVar( pNTHeader, pr ); | ||||||
| 
 | 
 | ||||||
|   // Remove the IL-only flag on a managed process.
 |   // Remove the IL-only flag on a managed process.
 | ||||||
|   if (NTHeader.COMDIR.VirtualAddress != 0 && NTHeader.COMDIR.Size != 0) |   if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR && | ||||||
|  |       NTHeader.COMDIR.VirtualAddress != 0) | ||||||
|   { |   { | ||||||
|     pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress); |     pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress); | ||||||
|     ReadProcVar( pComHeader, &ComHeader ); |     ReadProcVar( pComHeader, &ComHeader ); | ||||||
| @ -128,7 +155,7 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | |||||||
| { | { | ||||||
|   DWORD rva; |   DWORD rva; | ||||||
|   PVOID pMem; |   PVOID pMem; | ||||||
|   DWORD len; |   DWORD len, import_size; | ||||||
|   DWORD pr; |   DWORD pr; | ||||||
|   IMAGE_DOS_HEADER	   DosHeader; |   IMAGE_DOS_HEADER	   DosHeader; | ||||||
|   IMAGE_NT_HEADERS32	   NTHeader, *pNTHeader; |   IMAGE_NT_HEADERS32	   NTHeader, *pNTHeader; | ||||||
| @ -145,18 +172,19 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | |||||||
|   pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew); |   pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew); | ||||||
|   ReadProcVar( pNTHeader, &NTHeader ); |   ReadProcVar( pNTHeader, &NTHeader ); | ||||||
| 
 | 
 | ||||||
|   len = 16 + ansi_len + sizeof(*pImports) + NTHeader.IMPORTDIR.Size; |   import_size = sizeof_imports( ppi, pBase, NTHeader.IMPORTDIR.VirtualAddress ); | ||||||
|   pImports = malloc( len ); |   len = 8 + ansi_len + sizeof(*pImports) + import_size; | ||||||
|  |   pImports = HeapAlloc( hHeap, 0, len ); | ||||||
|   if (pImports == NULL) |   if (pImports == NULL) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"  Failed to allocate memory." ); |     DEBUGSTR( 1, "  Failed to allocate memory" ); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   pMem = FindMem( ppi->hProcess, pBase, len ); |   pMem = FindMem( ppi->hProcess, pBase, len ); | ||||||
|   if (pMem == NULL) |   if (pMem == NULL) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"  Failed to allocate virtual memory." ); |     DEBUGSTR( 1, "  Failed to allocate virtual memory" ); | ||||||
|     free( pImports ); |     HeapFree( hHeap, 0, pImports ); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   rva = (DWORD)((PBYTE)pMem - pBase); |   rva = (DWORD)((PBYTE)pMem - pBase); | ||||||
| @ -164,31 +192,33 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | |||||||
|   ip.pL = (PLONG)pImports; |   ip.pL = (PLONG)pImports; | ||||||
|   *ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1; |   *ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1; | ||||||
|   *ip.pL++ = 0; |   *ip.pL++ = 0; | ||||||
|   *ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1; |  | ||||||
|   *ip.pL++ = 0; |  | ||||||
|   memcpy( ip.pB, ansi_dll, ansi_len ); |   memcpy( ip.pB, ansi_dll, ansi_len ); | ||||||
|   ip.pB += ansi_len; |   ip.pB += ansi_len; | ||||||
|   ip.pI->OriginalFirstThunk = rva + 8; |   ip.pI->OriginalFirstThunk = 0; | ||||||
|   ip.pI->TimeDateStamp = 0; |   ip.pI->TimeDateStamp = 0; | ||||||
|   ip.pI->ForwarderChain = 0; |   ip.pI->ForwarderChain = 0; | ||||||
|   ip.pI->Name = rva + 16; |   ip.pI->Name = rva + 8; | ||||||
|   ip.pI->FirstThunk = rva; |   ip.pI->FirstThunk = rva; | ||||||
|   ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress, |   ReadProcMem( pBase+NTHeader.IMPORTDIR.VirtualAddress, ip.pI+1, import_size ); | ||||||
| 	       ip.pI + 1, NTHeader.IMPORTDIR.Size ); |  | ||||||
|   WriteProcMem( pMem, pImports, len ); |   WriteProcMem( pMem, pImports, len ); | ||||||
|   free( pImports ); |   HeapFree( hHeap, 0, pImports ); | ||||||
| 
 | 
 | ||||||
|   if (NTHeader.IATDIR.VirtualAddress == 0) |   if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_IAT && | ||||||
|  |       NTHeader.IATDIR.VirtualAddress == 0) | ||||||
|     NTHeader.IATDIR = NTHeader.IMPORTDIR; |     NTHeader.IATDIR = NTHeader.IMPORTDIR; | ||||||
|   NTHeader.IMPORTDIR.VirtualAddress = rva + 16 + ansi_len; |   NTHeader.IMPORTDIR.VirtualAddress = rva + 8 + ansi_len; | ||||||
|   NTHeader.IMPORTDIR.Size += sizeof(*pImports); |   //NTHeader.IMPORTDIR.Size += sizeof(*pImports);
 | ||||||
|   NTHeader.BOUNDDIR.VirtualAddress = 0; |   if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT) | ||||||
|   NTHeader.BOUNDDIR.Size = 0; |   { | ||||||
|  |     NTHeader.BOUNDDIR.VirtualAddress = 0; | ||||||
|  |     //NTHeader.BOUNDDIR.Size = 0;
 | ||||||
|  |   } | ||||||
|   VirtProtVar( pNTHeader, PAGE_READWRITE ); |   VirtProtVar( pNTHeader, PAGE_READWRITE ); | ||||||
|   WriteProcVar( pNTHeader, &NTHeader ); |   WriteProcVar( pNTHeader, &NTHeader ); | ||||||
|   VirtProtVar( pNTHeader, pr ); |   VirtProtVar( pNTHeader, pr ); | ||||||
| 
 | 
 | ||||||
|   if (NTHeader.COMDIR.VirtualAddress != 0 && NTHeader.COMDIR.Size != 0) |   if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR && | ||||||
|  |       NTHeader.COMDIR.VirtualAddress != 0) | ||||||
|   { |   { | ||||||
|     pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress); |     pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress); | ||||||
|     ReadProcVar( pComHeader, &ComHeader ); |     ReadProcVar( pComHeader, &ComHeader ); | ||||||
| @ -233,7 +263,7 @@ static PBYTE get_ntdll( LPPROCESS_INFORMATION ppi ) | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   DEBUGSTR( 1, L"  Failed to find ntdll.dll!" ); |   DEBUGSTR( 1, "  Failed to find ntdll.dll!" ); | ||||||
|   return NULL; |   return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -266,7 +296,7 @@ void InjectDLL64( LPPROCESS_INFORMATION ppi ) | |||||||
| 			 PAGE_EXECUTE_READ ); | 			 PAGE_EXECUTE_READ ); | ||||||
|   if (pMem == NULL) |   if (pMem == NULL) | ||||||
|   { |   { | ||||||
|     DEBUGSTR( 1, L"  Failed to allocate virtual memory (%lu)", GetLastError() ); |     DEBUGSTR(1, "  Failed to allocate virtual memory (%u)", GetLastError()); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -43,10 +43,10 @@ DWORD GetProcRVA( LPCTSTR module, LPCSTR func ) | |||||||
|   if (hMod == NULL) |   if (hMod == NULL) | ||||||
|   { |   { | ||||||
| #ifdef _WIN64 | #ifdef _WIN64 | ||||||
|     DEBUGSTR( 1, L"Unable to load %d-bit %s (%lu)!", |     DEBUGSTR( 1, "Unable to load %u-bit %S (%u)!", | ||||||
| 		 bits, module, GetLastError() ); | 		 bits, module, GetLastError() ); | ||||||
| #else | #else | ||||||
|     DEBUGSTR( 1, L"Unable to load %s (%lu)!", module, GetLastError() ); |     DEBUGSTR( 1, "Unable to load %S (%u)!", module, GetLastError() ); | ||||||
| #endif | #endif | ||||||
|     return 0; |     return 0; | ||||||
|   } |   } | ||||||
| @ -70,9 +70,9 @@ DWORD GetProcRVA( LPCTSTR module, LPCSTR func ) | |||||||
|   if (pFunc == NULL) |   if (pFunc == NULL) | ||||||
|   { |   { | ||||||
| #ifdef _WIN64 | #ifdef _WIN64 | ||||||
|     DEBUGSTR( 1, L"Could not find %d-bit %s!", bits, func ); |     DEBUGSTR( 1, "Could not find %u-bit %s!", bits, func ); | ||||||
| #else | #else | ||||||
|     DEBUGSTR( 1, L"Could not find %s!", func ); |     DEBUGSTR( 1, "Could not find %s!", func ); | ||||||
| #endif | #endif | ||||||
|     rva = 0; |     rva = 0; | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										46
									
								
								proctype.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								proctype.c
									
									
									
									
									
								
							| @ -76,8 +76,8 @@ int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui ) | |||||||
| 	if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386) | 	if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386) | ||||||
| 	{ | 	{ | ||||||
| 	  PIMAGE_NT_HEADERS32 pNTHeader = (PIMAGE_NT_HEADERS32)&nt_header; | 	  PIMAGE_NT_HEADERS32 pNTHeader = (PIMAGE_NT_HEADERS32)&nt_header; | ||||||
| 	  if (pNTHeader->COMDIR.VirtualAddress != 0 && | 	  if (pNTHeader->DATADIRS > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR && | ||||||
| 	      pNTHeader->COMDIR.Size != 0) | 	      pNTHeader->COMDIR.VirtualAddress != 0) | ||||||
| 	  { | 	  { | ||||||
| 	    IMAGE_COR20_HEADER ComHeader, *pComHeader; | 	    IMAGE_COR20_HEADER ComHeader, *pComHeader; | ||||||
| 	    pComHeader = (PIMAGE_COR20_HEADER)((PBYTE)minfo.BaseAddress | 	    pComHeader = (PIMAGE_COR20_HEADER)((PBYTE)minfo.BaseAddress | ||||||
| @ -87,57 +87,51 @@ int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui ) | |||||||
| 		!(ComHeader.Flags & COMIMAGE_FLAGS_32BITREQUIRED)) | 		!(ComHeader.Flags & COMIMAGE_FLAGS_32BITREQUIRED)) | ||||||
| 	    { | 	    { | ||||||
| #if defined(_WIN64) || !defined(W32ON64)	// W32ON64 will log due to -P
 | #if defined(_WIN64) || !defined(W32ON64)	// W32ON64 will log due to -P
 | ||||||
| 	      DEBUGSTR( 1, L"  AnyCPU %s (base = %.8X)", | 	      DEBUGSTR( 1, "  AnyCPU %s (base = %q)", | ||||||
| 			(*gui) ? L"GUI" : L"console", | 			   (*gui) ? "GUI" : "console", minfo.BaseAddress ); | ||||||
| 			PtrToUint( minfo.BaseAddress ) ); |  | ||||||
| #endif | #endif | ||||||
| #if defined(_WIN64) || defined(W32ON64) | #if defined(_WIN64) || defined(W32ON64) | ||||||
| 	      return 48; | 	      return 48; | ||||||
| #else | #else | ||||||
| 	      if (ProcessIs64( ppi->hProcess )) | 	      if (ProcessIs64( ppi->hProcess )) | ||||||
| 	      { | 	      { | ||||||
| 		DEBUGSTR( 1, L"  Unsupported (use x64\\ansicon)" ); | 		DEBUGSTR( 1, "  Unsupported (use x64\\ansicon)" ); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	      } | 	      } | ||||||
| 	      return 32; | 	      return 32; | ||||||
| #endif | #endif | ||||||
| 	    } | 	    } | ||||||
| 	  } | 	  } | ||||||
| 	  DEBUGSTR( 1, L"  32-bit %s (base = %.8X)", | 	  DEBUGSTR( 1, "  32-bit %s (base = %q)", | ||||||
| 		    (*gui) ? L"GUI" : L"console", | 		       (*gui) ? "GUI" : "console", minfo.BaseAddress ); | ||||||
| 		    PtrToUint( minfo.BaseAddress ) ); |  | ||||||
| 	  return 32; | 	  return 32; | ||||||
| 	} | 	} | ||||||
| 	if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) | 	if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) | ||||||
| 	{ | 	{ | ||||||
| #ifdef _WIN64 | #ifdef _WIN64 | ||||||
| 	  DEBUGSTR( 1, L"  64-bit %s (base = %.8X_%.8X)", | 	  DEBUGSTR( 1, "  64-bit %s (base = %p)", | ||||||
| 		    (*gui) ? L"GUI" : L"console", | 		       (*gui) ? "GUI" : "console", minfo.BaseAddress ); | ||||||
| 		    (DWORD)((DWORD_PTR)minfo.BaseAddress >> 32), |  | ||||||
| 		    PtrToUint( minfo.BaseAddress ) ); |  | ||||||
| 	  return 64; | 	  return 64; | ||||||
| #elif defined(W32ON64) | #elif defined(W32ON64) | ||||||
| 	  // Console will log due to -P, but GUI may be ignored (if not,
 | 	  // Console will log due to -P, but GUI may be ignored (if not,
 | ||||||
| 	  // this'll show up twice).
 | 	  // this'll show up twice).
 | ||||||
| 	  if (*gui) | 	  if (*gui) | ||||||
| 	    DEBUGSTR( 1, L"  64-bit GUI (base = 00000000_%.8X)", | 	    DEBUGSTR( 1, "  64-bit GUI (base = %P)", minfo.BaseAddress ); | ||||||
| 		      PtrToUint( minfo.BaseAddress ) ); |  | ||||||
| 	  return 64; | 	  return 64; | ||||||
| #else | #else | ||||||
| 	  DEBUGSTR( 1, L"  64-bit %s (base = 00000000_%.8X)", | 	  DEBUGSTR( 1, "  64-bit %s (base = %P)", | ||||||
| 		    (*gui) ? L"GUI" : L"console", | 		       (*gui) ? "GUI" : "console", minfo.BaseAddress ); | ||||||
| 		    PtrToUint( minfo.BaseAddress ) ); | 	  DEBUGSTR( 1, "  Unsupported (use x64\\ansicon)" ); | ||||||
| 	  DEBUGSTR( 1, L"  Unsupported (use x64\\ansicon)" ); |  | ||||||
| 	  return 0; | 	  return 0; | ||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
| 	DEBUGSTR( 1, L"  Ignoring unsupported machine (0x%X)", | 	DEBUGSTR( 1, "  Ignoring unsupported machine (0x%X)", | ||||||
| 		  nt_header.FileHeader.Machine ); | 		     nt_header.FileHeader.Machine ); | ||||||
|       } |       } | ||||||
|       else |       else | ||||||
|       { |       { | ||||||
| 	DEBUGSTR( 1, L"  Ignoring unsupported subsystem (%u)", | 	DEBUGSTR( 1, "  Ignoring unsupported subsystem (%u)", | ||||||
| 		  nt_header.OptionalHeader.Subsystem ); | 		     nt_header.OptionalHeader.Subsystem ); | ||||||
|       } |       } | ||||||
|       return 0; |       return 0; | ||||||
|     } |     } | ||||||
| @ -147,16 +141,16 @@ int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui ) | |||||||
|     if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) >= 0x100000) |     if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) >= 0x100000) | ||||||
|     { |     { | ||||||
| #ifdef W32ON64 | #ifdef W32ON64 | ||||||
|       DEBUGSTR( 1, L"  Pointer overflow: assuming 64-bit" ); |       DEBUGSTR( 1, "  Pointer overflow: assuming 64-bit" ); | ||||||
|       return 64; |       return 64; | ||||||
| #else | #else | ||||||
|       DEBUGSTR( 1, L"  Ignoring apparent 64-bit process (use x64\\ansicon)" ); |       DEBUGSTR( 1, "  Ignoring apparent 64-bit process (use x64\\ansicon)" ); | ||||||
|       return 0; |       return 0; | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   DEBUGSTR( 1, L"  Ignoring non-Windows process" ); |   DEBUGSTR( 1, "  Ignoring non-Windows process" ); | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										110
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								readme.md
									
									
									
									
									
								
							| @ -5,8 +5,8 @@ provides much the same functionality as `ANSI.SYS` does for MS-DOS. | |||||||
| 
 | 
 | ||||||
| ## Requirements | ## Requirements | ||||||
| 
 | 
 | ||||||
| * 32-bit: Windows 2000 Professional or later (it won't work with NT or 9X). | * 32-bit: Windows 2000 Professional and later (it won't work with NT or 9X). | ||||||
| * 64-bit: Vista or later (it won't work with XP64). | * 64-bit: AMD64 (it won't work with IA64). | ||||||
| 
 | 
 | ||||||
| ## Installation | ## Installation | ||||||
| 
 | 
 | ||||||
| @ -111,15 +111,17 @@ Using `ansicon` after install will always start with the default attributes, | |||||||
| restoring the originals on exit; all other programs will use the current | restoring the originals on exit; all other programs will use the current | ||||||
| attributes.  The shift state is always reset for a new process. | attributes.  The shift state is always reset for a new process. | ||||||
| 
 | 
 | ||||||
| The Windows API `WriteFile` and `WriteConsoleA` functions will set the number of | My version of `WriteConsoleA` will always set the number of characters written, | ||||||
| characters written, not the number of bytes.  When using a multibyte character | not the number of bytes.  This means writing a double-byte character as two | ||||||
| set, this results in a smaller number (since multiple bytes are used to | bytes will set 0 the first write (nothing was written) and 1 the second (when | ||||||
| represent a single character).  Some programs recognise this as a reduced write | the character was actually written); Windows normally sets 1 for both writes. | ||||||
| and will inadvertently repeat previous characters.  If you discover such a | Similarly, writing the individual bytes of a multibyte character will set 0 for | ||||||
| program, use the `ANSICON_API` environment variable to record it and override | all but the last byte, then 1 on the last; Windows normally sets 1 for each | ||||||
| the API, returning the original byte count.  Ruby (prior to 1.9.3) is an example | byte, writing the undefined character.  However, my `WriteFile` (and | ||||||
| of such a program, so use `set ANSICON_API=ruby` to avoid the repitition.  The | `_lwrite`/`_hwrite`) will always set what was received; Windows, using a | ||||||
| full syntax is: | multibyte character set (but not DBCS), would set the characters.  You can have | ||||||
|  | `WriteConsoleA` return the original byte count by using the `ANSICON_API` | ||||||
|  | environment variable: | ||||||
| 
 | 
 | ||||||
|     ANSICON_API=[!]program;program;program... |     ANSICON_API=[!]program;program;program... | ||||||
| 
 | 
 | ||||||
| @ -127,14 +129,16 @@ PROGRAM is the name of the program, with no path and extension.  The leading | |||||||
| exclamation inverts the usage, meaning the API will always be overridden, unless | exclamation inverts the usage, meaning the API will always be overridden, unless | ||||||
| the program is in the list.  The variable can be made permanent by going to | the program is in the list.  The variable can be made permanent by going to | ||||||
| _System Properties_, selecting the _Advanced_ tab (with Vista onwards, this can | _System Properties_, selecting the _Advanced_ tab (with Vista onwards, this can | ||||||
| be done by running _"SystemPropertiesAdvanced"_) and clicking _Environment | be done by running `SystemPropertiesAdvanced`) and clicking _Environment | ||||||
| Variables_. | Variables_. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ## Limitations | ## Limitations | ||||||
| 
 | 
 | ||||||
| - The entire console buffer is used, not just the visible window. | - Line sequences use the window; column sequences use the buffer. | ||||||
| - There's a conflict with NVIDIA's drivers, requiring the setting of the | - An application using multiple screen buffers will not have separate | ||||||
|  |   attributes in each buffer. | ||||||
|  | - There may be a conflict with NVIDIA's drivers, requiring the setting of the | ||||||
|   Environment Variable: |   Environment Variable: | ||||||
| 
 | 
 | ||||||
|         ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll |         ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll | ||||||
| @ -146,38 +150,46 @@ Variables_. | |||||||
| 
 | 
 | ||||||
| The following escape sequences are recognised. | The following escape sequences are recognised. | ||||||
| 
 | 
 | ||||||
|     \e]0;titleBEL   Set (xterm) window's title (and icon) |     \e]0;titleBEL           xterm: Set window's title (and icon, ignored) | ||||||
|     \e[21t          Report (xterm) window's title |     \e]2;titleBEL           xterm: Set window's title | ||||||
|     \e[s            Save Cursor |     \e[21t                  xterm: Report window's title | ||||||
|     \e[u            Restore Cursor |     \e[s                    ANSI.SYS: Save Cursor Position | ||||||
|     \e[#G           CHA Cursor Character Absolute |     \e[u                    ANSI.SYS: Restore Cursor Position | ||||||
|     \e[#E           CNL Cursor Next Line |     \e[#Z           CBT     Cursor Backward Tabulation | ||||||
|     \e[#F           CPL Cursor Preceding Line |     \e[#G           CHA     Cursor Character Absolute | ||||||
|     \e[#D           CUB Cursor Left |     \e[#I           CHT     Cursor Forward Tabulation | ||||||
|     \e[#B           CUD Cursor Down |     \e[#E           CNL     Cursor Next Line | ||||||
|     \e[#C           CUF Cursor Right |     \e[#F           CPL     Cursor Preceding Line | ||||||
|     \e[#;#H         CUP Cursor Position |     \e[3h           CRM     Control Representation Mode (display controls) | ||||||
|     \e[#A           CUU Cursor Up |     \e[3l           CRM     Control Representation Mode (perform controls) | ||||||
|     \e[#P           DCH Delete Character |     \e[#D           CUB     Cursor Left | ||||||
|  |     \e[#B           CUD     Cursor Down | ||||||
|  |     \e[#C           CUF     Cursor Right | ||||||
|  |     \e[#;#H         CUP     Cursor Position | ||||||
|  |     \e[#A           CUU     Cursor Up | ||||||
|  |     \e[#P           DCH     Delete Character | ||||||
|  |     \e[?7h          DECAWM  DEC Autowrap Mode (autowrap) | ||||||
|  |     \e[?7l          DECAWM  DEC Autowrap Mode (no autowrap) | ||||||
|     \e[?25h         DECTCEM DEC Text Cursor Enable Mode (show cursor) |     \e[?25h         DECTCEM DEC Text Cursor Enable Mode (show cursor) | ||||||
|     \e[?25l         DECTCEM DEC Text Cursor Enable Mode (hide cursor) |     \e[?25l         DECTCEM DEC Text Cursor Enable Mode (hide cursor) | ||||||
|     \e[#M           DL  Delete Line |     \e[#M           DL      Delete Line | ||||||
|     \e[#n           DSR Device Status Report |     \e[#n           DSR     Device Status Report | ||||||
|     \e[#X           ECH Erase Character |     \e[#X           ECH     Erase Character | ||||||
|     \e[#J           ED  Erase In Page |     \e[#J           ED      Erase In Page | ||||||
|     \e[#K           EL  Erase In Line |     \e[#K           EL      Erase In Line | ||||||
|     \e[#`           HPA Character Position Absolute |     \e[#`           HPA     Character Position Absolute | ||||||
|     \e[#j           HPB Character Position Backward |     \e[#j           HPB     Character Position Backward | ||||||
|     \e[#a           HPR Character Position Forward |     \e[#a           HPR     Character Position Forward | ||||||
|     \e[#;#f         HVP Character And Line Position |     \e[#;#f         HVP     Character And Line Position | ||||||
|     \e[#@           ICH Insert Character |     \e[#@           ICH     Insert Character | ||||||
|     \e[#L           IL  Insert Line |     \e[#L           IL      Insert Line | ||||||
|     SI              LS0 Locking-shift Zero (see below) |     SI              LS0     Locking-shift Zero (see below) | ||||||
|     SO              LS1 Locking-shift One |     SO              LS1     Locking-shift One | ||||||
|     \e[#;#;#m       SGR Select Graphic Rendition |     \e[#b           REP     Repeat | ||||||
|     \e[#d           VPA Line Position Absolute |     \e[#;#;#m       SGR     Select Graphic Rendition | ||||||
|     \e[#k           VPB Line Position Backward |     \e[#d           VPA     Line Position Absolute | ||||||
|     \e[#e           VPR Line Position Forward |     \e[#k           VPB     Line Position Backward | ||||||
|  |     \e[#e           VPR     Line Position Forward | ||||||
| 
 | 
 | ||||||
| - `\e` represents the escape character (ASCII 27). | - `\e` represents the escape character (ASCII 27). | ||||||
| - `#` represents a decimal number (optional, in most cases defaulting to 1). | - `#` represents a decimal number (optional, in most cases defaulting to 1). | ||||||
| @ -193,6 +205,12 @@ the latter will explicitly reset them.  The environment variable `ANSICON_DEF` | |||||||
| can be used to change the default colors (same value as `-m`; setting the | can be used to change the default colors (same value as `-m`; setting the | ||||||
| variable does not change the current colors). | variable does not change the current colors). | ||||||
| 
 | 
 | ||||||
|  | The first time a program clears the screen (`\e[2J`) will actually scroll in a | ||||||
|  | new window (assuming the buffer is bigger than the window, of course). | ||||||
|  | Subsequent clears will then blank the window.  However, if the window has | ||||||
|  | scrolled, or the cursor is on the last line of the buffer, it will again scroll | ||||||
|  | in a new window. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| ### Ignored Sequences | ### Ignored Sequences | ||||||
| 
 | 
 | ||||||
| @ -214,7 +232,7 @@ http://vt100.net/docs/vt220-rm/table2-4.html. | |||||||
| 
 | 
 | ||||||
|     Char    Unicode Code Point & Name |     Char    Unicode Code Point & Name | ||||||
|     ----    ------------------------- |     ----    ------------------------- | ||||||
|     _       U+0020  Space (blank) |     _       U+00A0  No-Break Space (blank) | ||||||
|     `       U+2666  Black Diamond Suit |     `       U+2666  Black Diamond Suit | ||||||
|     a       U+2592  Medium Shade |     a       U+2592  Medium Shade | ||||||
|     b       U+2409  Symbol For Horizontal Tabulation |     b       U+2409  Symbol For Horizontal Tabulation | ||||||
| @ -299,4 +317,4 @@ In particular, the supplied binaries are freely redistributable. | |||||||
| A formal license (zlib) is available in `LICENSE.txt`. | A formal license (zlib) is available in `LICENSE.txt`. | ||||||
| 
 | 
 | ||||||
| --- | --- | ||||||
| Copyright 2005-2014 Jason Hood | Copyright 2005-2015 Jason Hood | ||||||
|  | |||||||
							
								
								
									
										53
									
								
								readme.txt
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								readme.txt
									
									
									
									
									
								
							| @ -1,9 +1,9 @@ | |||||||
| 
 | 
 | ||||||
| 				    ANSICON | 				    ANSICON | ||||||
| 
 | 
 | ||||||
| 			 Copyright 2005-2014 Jason Hood | 			 Copyright 2005-2015 Jason Hood | ||||||
| 
 | 
 | ||||||
| 			    Version 1.71.  Freeware | 			    Version 1.72.  Freeware | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Description | Description | ||||||
| @ -110,9 +110,10 @@ Usage | |||||||
|     The variable is updated whenever a program reads it directly (i.e. as an |     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 |     individual request, not as part of the entire environment block).  For | ||||||
|     example, 'set an' will not update it, but 'echo %ansicon%' will.  Also |     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 |     created are ANSICON_VER, which contains the version without the point (1.50 | ||||||
|     becomes "150").  This variable does not exist as part of the environment |     becomes "150"), and CLICOLOR (see http://bixense.com/clicolors/), which | ||||||
|     block ('set an' will not show it). |     contains "1".  These variables do not exist as part of the environment | ||||||
|  |     block (e.g. 'set an' will not show ANSICON_VER). | ||||||
| 
 | 
 | ||||||
|     If installed, GUI programs will not be hooked.  Either start the program |     If installed, GUI programs will not be hooked.  Either start the program | ||||||
|     directly with 'ansicon', or add it to the ANSICON_GUI variable (see |     directly with 'ansicon', or add it to the ANSICON_GUI variable (see | ||||||
| @ -122,15 +123,17 @@ Usage | |||||||
|     utes, restoring the originals on exit; all other programs will use the cur- |     utes, restoring the originals on exit; all other programs will use the cur- | ||||||
|     rent attributes.  The shift state is always reset for a new process. |     rent attributes.  The shift state is always reset for a new process. | ||||||
| 
 | 
 | ||||||
|     The Windows API WriteFile and WriteConsoleA functions will set the number |     My version of WriteConsoleA will always set the number of characters writt- | ||||||
|     of characters written, not the number of bytes.  When using a multibyte |     en, not the number of bytes.  This means writing a double-byte character as | ||||||
|     character set, this results in a smaller number (since multiple bytes are |     two bytes will set 0 the first write (nothing was written) and 1 the second | ||||||
|     used to represent a single character).  Some programs recognise this as a |     (when the character was actually written); Windows normally sets 1 for both | ||||||
|     reduced write and will inadvertently repeat previous characters.  If you |     writes.  Similarly, writing the individual bytes of a multibyte character | ||||||
|     discover such a program, use the ANSICON_API environment variable to record |     will set 0 for all but the last byte, then 1 on the last; Windows normally | ||||||
|     it and override the API, returning the original byte count.  Ruby (prior to |     sets 1 for each byte, writing the undefined character.  However, my | ||||||
|     1.9.3) is an example of such a program, so use 'set ANSICON_API=ruby' to |     WriteFile (and _lwrite/_hwrite) will always set what was received; Windows, | ||||||
|     avoid the repitition.  The full syntax is: |     using a multibyte character set (but not DBCS), would set the characters. | ||||||
|  |     You can have WriteConsoleA return the original byte count by using the | ||||||
|  |     ANSICON_API environment variable: | ||||||
| 
 | 
 | ||||||
| 	ANSICON_API=[!]program;program;program... | 	ANSICON_API=[!]program;program;program... | ||||||
| 
 | 
 | ||||||
| @ -277,7 +280,7 @@ Limitations | |||||||
|     Line sequences use the window; column sequences use the buffer. |     Line sequences use the window; column sequences use the buffer. | ||||||
|     Tabs are fixed at eight columns. |     Tabs are fixed at eight columns. | ||||||
| 
 | 
 | ||||||
|     There's a conflict with NVIDIA's drivers, requiring the setting of the |     There may be a conflict with NVIDIA's drivers, requiring the setting of the | ||||||
|     Environment Variable: |     Environment Variable: | ||||||
| 
 | 
 | ||||||
| 	ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll | 	ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll | ||||||
| @ -291,8 +294,24 @@ Version History | |||||||
| 
 | 
 | ||||||
|     Legend: + added, - bug-fixed, * changed. |     Legend: + added, - bug-fixed, * changed. | ||||||
| 
 | 
 | ||||||
|  |     1.72 - 24 December, 2015: | ||||||
|  |     - handle STD_OUTPUT_HANDLE & STD_ERROR_HANDLE in WriteFile; | ||||||
|  |     - better handling of unusual PE files; | ||||||
|  |     * cache GetConsoleMode for an improvement in speed; | ||||||
|  |     * files writing to the console always succeed (should mostly remove the | ||||||
|  |        need for ANSICON_API); | ||||||
|  |     * log: add a blank line between processes; | ||||||
|  | 	   remove the separate line for WriteFile & _lwrite; | ||||||
|  | 	   write byte strings as-is, wide strings using the current code page; | ||||||
|  | 	   use caret notation for control characters, with hexadecimal "^xNN" | ||||||
|  | 	    and "^uNNNN" for characters not in the code page (custom printf); | ||||||
|  |     * join multibyte characters split across separate writes; | ||||||
|  |     * remove wcstok, avoiding potential interference with the host program; | ||||||
|  |     * similarly, remove malloc & friends, using a private heap; | ||||||
|  |     + add CLICOLOR dynamic environment variable. | ||||||
|  | 
 | ||||||
|     1.71 - 23 October, 2015: |     1.71 - 23 October, 2015: | ||||||
|     + add _CRT_NON_CONFORMING_WCSTOK define |     + add _CRT_NON_CONFORMING_WCSTOK define for VS2015. | ||||||
| 
 | 
 | ||||||
|     1.70 - 26 February, 2014: |     1.70 - 26 February, 2014: | ||||||
|     - don't hook again if using LoadLibrary or LoadLibraryEx; |     - don't hook again if using LoadLibrary or LoadLibraryEx; | ||||||
| @ -501,4 +520,4 @@ Distribution | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ============================== | ============================== | ||||||
| Jason Hood, 26 February, 2014. | Jason Hood, 24 December, 2015. | ||||||
|  | |||||||
							
								
								
									
										365
									
								
								util.c
									
									
									
									
									
								
							
							
						
						
									
										365
									
								
								util.c
									
									
									
									
									
								
							| @ -74,99 +74,316 @@ void set_ansi_dll( void ) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void DEBUGSTR( int level, LPTSTR szFormat, ... ) | static LPSTR buf; | ||||||
|  | static DWORD buf_len; | ||||||
|  | static BOOL  quote, alt; | ||||||
|  | 
 | ||||||
|  | static DWORD str_format( DWORD pos, BOOL wide, DWORD_PTR str, DWORD len ) | ||||||
| { | { | ||||||
|   static char  tempfile[MAX_PATH]; |   static UINT  cp; | ||||||
|   static DWORD pid; |   static DWORD flags; | ||||||
| 
 |   static BOOL  def, *pDef, start_trail; | ||||||
|   TCHAR   szBuffer[1024], szEscape[1024]; |   union | ||||||
|   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" ) ); |     LPSTR  a; | ||||||
|     pid = GetCurrentProcessId(); |     LPWSTR w; | ||||||
|  |   } src; | ||||||
|  |   int  ch; | ||||||
|  |   BOOL trail; | ||||||
|  | 
 | ||||||
|  |   src.a = (LPSTR)str; | ||||||
|  |   if (len == 0 && str != 0) | ||||||
|  |     len = (DWORD)(wide ? wcslen( src.w ) : strlen( src.a )); | ||||||
|  | 
 | ||||||
|  |   if (pos + len * 6 + 8 >= buf_len) | ||||||
|  |   { | ||||||
|  |     LPVOID tmp = HeapReAlloc( hHeap, 0, buf, buf_len + len * 6 + 8 ); | ||||||
|  |     if (tmp == NULL) | ||||||
|  |       return 0; | ||||||
|  |     buf = tmp; | ||||||
|  |     buf_len = (DWORD)HeapSize( hHeap, 0, buf ); | ||||||
|   } |   } | ||||||
|   if (szFormat == NULL) | 
 | ||||||
|  |   if (len == 0) | ||||||
|   { |   { | ||||||
|     // Explicitly use 't', as _fmode might be binary.
 |     if (str == 0) | ||||||
|     file = fopen( tempfile, (log_level & 8) ? "at" : "wt" ); |       pos += wsprintfA( buf + pos, "<null>" ); | ||||||
|     if (file != NULL) |     else if (quote) | ||||||
|     { |     { | ||||||
|       SYSTEMTIME now; |       buf[pos++] = '"'; | ||||||
|       GetLocalTime( &now ); |       buf[pos++] = '"'; | ||||||
|       fseek( file, 0, SEEK_END ); |  | ||||||
|       if (ftell( file ) != 0) |  | ||||||
| 	putc( '\n', file ); |  | ||||||
|       fprintf( file, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d) started " |  | ||||||
| 		      "%d-%.2d-%.2d %d:%.2d:%.2d\n", |  | ||||||
| 		     log_level, |  | ||||||
| 		     now.wYear, now.wMonth, now.wDay, |  | ||||||
| 		     now.wHour, now.wMinute, now.wSecond ); |  | ||||||
|       fclose( file ); |  | ||||||
|     } |     } | ||||||
|     return; |     else if (alt) | ||||||
|  |       pos += wsprintfA( buf + pos, "<empty>" ); | ||||||
|  |     return pos; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   va_start( pArgList, szFormat ); |   if (cp != GetConsoleOutputCP()) | ||||||
|   _vsnwprintf( szBuffer, lenof(szBuffer), szFormat, pArgList ); |  | ||||||
|   va_end( pArgList ); |  | ||||||
| 
 |  | ||||||
|   szFormat = szBuffer; |  | ||||||
|   if (*szFormat == '\33') |  | ||||||
|   { |   { | ||||||
|     BOOL first = TRUE; |     cp = GetConsoleOutputCP(); | ||||||
|     LPTSTR pos = szEscape; |     if (wide) | ||||||
|     while (*++szFormat != '\0' && pos < szEscape + lenof(szEscape) - 4) |  | ||||||
|     { |     { | ||||||
|       if (*szFormat < 32) |       wchar_t und = L'\xFFFF'; | ||||||
|  |       flags = WC_NO_BEST_FIT_CHARS; | ||||||
|  |       pDef = &def; | ||||||
|  |       // Some code pages don't support the default character.
 | ||||||
|  |       if (!WideCharToMultiByte( cp, flags, &und, 1, buf + pos, 12, NULL, pDef )) | ||||||
|       { |       { | ||||||
| 	*pos++ = '\\'; | 	flags = 0; | ||||||
| 	switch (*szFormat) | 	pDef = NULL; | ||||||
|  | 	def = FALSE; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (quote) | ||||||
|  |     buf[pos++] = '"'; | ||||||
|  | 
 | ||||||
|  |   trail = FALSE; | ||||||
|  |   while (len-- != 0) | ||||||
|  |   { | ||||||
|  |     if (wide) | ||||||
|  |       ch = *src.w++; | ||||||
|  |     else | ||||||
|  |       ch = (BYTE)*src.a++; | ||||||
|  | 
 | ||||||
|  |     if (ch < 32 || (quote && start_trail)) | ||||||
|  |     { | ||||||
|  |       start_trail = FALSE; | ||||||
|  |       if (quote) | ||||||
|  |       { | ||||||
|  | 	buf[pos++] = '\\'; | ||||||
|  | 	switch (ch) | ||||||
| 	{ | 	{ | ||||||
| 	  case '\a': *pos++ = 'a'; break; | 	  case '\0': buf[pos++] = '0'; break; | ||||||
| 	  case '\b': *pos++ = 'b'; break; | 	  case '\a': buf[pos++] = 'a'; break; | ||||||
| 	  case '\t': *pos++ = 't'; break; | 	  case '\b': buf[pos++] = 'b'; break; | ||||||
| 	  case '\r': *pos++ = 'r'; break; | 	  case '\t': buf[pos++] = 't'; break; | ||||||
| 	  case '\n': *pos++ = 'n'; break; | 	  case '\n': buf[pos++] = 'n'; break; | ||||||
| 	  case	27 : *pos++ = 'e'; break; | 	  case '\v': buf[pos++] = 'v'; break; | ||||||
|  | 	  case '\f': buf[pos++] = 'f'; break; | ||||||
|  | 	  case '\r': buf[pos++] = 'r'; break; | ||||||
|  | 	  case	27 : buf[pos++] = 'e'; break; | ||||||
| 	  default: | 	  default: | ||||||
| 	    pos += _snwprintf( pos, 32, L"%.*o", | 	    pos += wsprintfA( buf + pos, "x%.2X", ch ); | ||||||
| 			     (szFormat[1] >= '0' && szFormat[1] <= '7') ? 3 : 1, |  | ||||||
| 			     *szFormat ); |  | ||||||
| 	} | 	} | ||||||
|       } |       } | ||||||
|       else |       else | ||||||
|       { |       { | ||||||
| 	if (*szFormat == '"') | 	buf[pos++] = '^'; | ||||||
| 	{ | 	buf[pos++] = ch + '@'; | ||||||
| 	  if (first) |  | ||||||
| 	    first = FALSE; |  | ||||||
| 	  else if (szFormat[1] != '\0') |  | ||||||
| 	    *pos++ = '\\'; |  | ||||||
| 	} |  | ||||||
| 	*pos++ = *szFormat; |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     *pos = '\0'; |     else if (quote && ch == '"') | ||||||
|     szFormat = szEscape; |     { | ||||||
|  |       buf[pos++] = '\\'; | ||||||
|  |       buf[pos++] = ch; | ||||||
|  |     } | ||||||
|  |     else if (!wide) | ||||||
|  |     { | ||||||
|  |       if (quote && (cp == 932 || cp == 936 || cp == 949 || cp == 950)) | ||||||
|  |       { | ||||||
|  | 	if (trail) | ||||||
|  | 	  trail = FALSE; | ||||||
|  | 	else if (IsDBCSLeadByteEx( cp, (char)ch )) | ||||||
|  | 	{ | ||||||
|  | 	  if (len == 0) | ||||||
|  | 	    start_trail = TRUE; | ||||||
|  | 	  else | ||||||
|  | 	    trail = TRUE; | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |       if (quote && start_trail) | ||||||
|  | 	pos += wsprintfA( buf + pos, "\\x%.2X", ch ); | ||||||
|  |       else | ||||||
|  | 	buf[pos++] = ch; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       int mb = WideCharToMultiByte( cp, flags, src.w - 1, 1, buf + pos, 12, | ||||||
|  | 				    NULL, pDef ); | ||||||
|  |       if (def) | ||||||
|  | 	mb = wsprintfA( buf + pos, ch < 0x100 ? "%cx%.2X" : "%cu%.4X", | ||||||
|  | 			(quote) ? '\\' : '^', ch ); | ||||||
|  |       pos += mb; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" ); |   if (quote) | ||||||
|   wait	= WaitForSingleObject( mutex, 500 ); |     buf[pos++] = '"'; | ||||||
|   file	= fopen( tempfile, "at" ); | 
 | ||||||
|   if (file != NULL) |   return pos; | ||||||
|   { | } | ||||||
|     fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat ); | 
 | ||||||
|     fclose( file ); | void DEBUGSTR( int level, LPCSTR szFormat, ... ) | ||||||
|   } | { | ||||||
|   if (wait == WAIT_OBJECT_0) |   static int	prefix_len; | ||||||
|     ReleaseMutex( mutex ); |   static HANDLE mutex; | ||||||
|   CloseHandle( mutex ); |   static DWORD	size; | ||||||
|  | 
 | ||||||
|  |   WCHAR     temp[MAX_PATH]; | ||||||
|  |   HANDLE    file; | ||||||
|  |   va_list   pArgList; | ||||||
|  |   DWORD     len, slen, written; | ||||||
|  |   DWORD_PTR num; | ||||||
|  | 
 | ||||||
|  |   if ((log_level & 3) < level && !(level & 4 & log_level)) | ||||||
|  |     return; | ||||||
|  | 
 | ||||||
|  |   if (mutex == NULL) | ||||||
|  |   { | ||||||
|  |     mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" ); | ||||||
|  |     if (mutex == NULL) | ||||||
|  |     { | ||||||
|  |       file = INVALID_HANDLE_VALUE; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     buf = HeapAlloc( hHeap, 0, 2048 ); | ||||||
|  |     buf_len = (DWORD)HeapSize( hHeap, 0, buf ); | ||||||
|  |     prefix_len = wsprintfA( buf, "%S (%lu): ", prog, GetCurrentProcessId() ); | ||||||
|  |   } | ||||||
|  |   if (WaitForSingleObject( mutex, 500 ) == WAIT_TIMEOUT) | ||||||
|  |     return; | ||||||
|  | 
 | ||||||
|  |   ExpandEnvironmentStrings( L"%TEMP%\\ansicon.log", temp, lenof(temp) ); | ||||||
|  |   file = CreateFile( temp, GENERIC_WRITE, FILE_SHARE_READ, NULL, | ||||||
|  | 		     (szFormat != NULL || (log_level & 8)) ? OPEN_ALWAYS | ||||||
|  | 							   : CREATE_ALWAYS, | ||||||
|  | 		     0, NULL ); | ||||||
|  |   if (file == INVALID_HANDLE_VALUE) | ||||||
|  |   { | ||||||
|  |     ReleaseMutex( mutex ); | ||||||
|  |     CloseHandle( mutex ); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   len = SetFilePointer( file, 0, NULL, FILE_END ); | ||||||
|  |   if (len == 0 || szFormat == NULL) | ||||||
|  |   { | ||||||
|  |     char buf[128]; | ||||||
|  |     SYSTEMTIME now; | ||||||
|  | 
 | ||||||
|  |     size = 0; | ||||||
|  | 
 | ||||||
|  |     if (len != 0) | ||||||
|  |     { | ||||||
|  |       memset( buf + 2, '=', 72 ); | ||||||
|  |       buf[0] = buf[74] = buf[76] = '\r'; | ||||||
|  |       buf[1] = buf[75] = buf[77] = '\n'; | ||||||
|  |       WriteFile( file, buf, 78, &written, NULL ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     GetLocalTime( &now ); | ||||||
|  |     len = wsprintfA( buf, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d)" | ||||||
|  | 			  " started %d-%.2d-%.2d %d:%.2d:%.2d\r\n", | ||||||
|  | 			  log_level, | ||||||
|  | 			  now.wYear, now.wMonth, now.wDay, | ||||||
|  | 			  now.wHour, now.wMinute, now.wSecond ); | ||||||
|  |     WriteFile( file, buf, len, &written, NULL ); | ||||||
|  |     if (szFormat == NULL) | ||||||
|  |     { | ||||||
|  |       CloseHandle( file ); | ||||||
|  |       ReleaseMutex( mutex ); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (len != size) | ||||||
|  |     WriteFile( file, "\r\n", 2, &written, NULL ); | ||||||
|  | 
 | ||||||
|  |   va_start( pArgList, szFormat ); | ||||||
|  | 
 | ||||||
|  |   // Customized printf, mainly to handle wide-character strings the way I want.
 | ||||||
|  |   // It only supports:
 | ||||||
|  |   //   %u   unsigned 32-bit decimal
 | ||||||
|  |   //   %X   unsigned 32-bit upper case hexadecimal
 | ||||||
|  |   //   %p   native pointer
 | ||||||
|  |   //   %q   native pointer, display as 32 bits
 | ||||||
|  |   //   %P   32-bit pointer, display as 64 bits
 | ||||||
|  |   //   %s   null-terminated byte characters
 | ||||||
|  |   //   %S   null-terminated wide characters
 | ||||||
|  |   //
 | ||||||
|  |   // s & S may be prefixed with (in this order):
 | ||||||
|  |   //   "    quote the string, using C-style escapes and <null> for NULL
 | ||||||
|  |   //   #    use <null> for NULL and <empty> for ""
 | ||||||
|  |   //   <    length of the string is the previous %u
 | ||||||
|  |   //   *    length of the string is the parameter before the string
 | ||||||
|  |   //
 | ||||||
|  |   // Wide strings are converted according to the current code page; if a
 | ||||||
|  |   // character could not be translated, hex is used.
 | ||||||
|  |   //
 | ||||||
|  |   // C-style escapes are the standard backslash sequences, plus '\e' for ESC,
 | ||||||
|  |   // with '\x' used for two hex digits and '\u' for four.  Otherwise, caret
 | ||||||
|  |   // notation is used to represent controls, with '^x'/'^u' for hex.
 | ||||||
|  | 
 | ||||||
|  |   num = 0; | ||||||
|  |   len = prefix_len; | ||||||
|  |   while (*szFormat != '\0') | ||||||
|  |   { | ||||||
|  |     if (*szFormat != '%') | ||||||
|  |       buf[len++] = *szFormat++; | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       quote = alt = FALSE; | ||||||
|  |       ++szFormat; | ||||||
|  |       if (*szFormat == '"') | ||||||
|  |       { | ||||||
|  | 	quote = TRUE; | ||||||
|  | 	++szFormat; | ||||||
|  |       } | ||||||
|  |       if (*szFormat == '#') | ||||||
|  |       { | ||||||
|  | 	alt = TRUE; | ||||||
|  | 	++szFormat; | ||||||
|  |       } | ||||||
|  |       slen = 0; | ||||||
|  |       if (*szFormat == '<') | ||||||
|  |       { | ||||||
|  | 	slen = (DWORD)num; | ||||||
|  | 	++szFormat; | ||||||
|  |       } | ||||||
|  |       if (*szFormat == '*') | ||||||
|  |       { | ||||||
|  | 	slen = va_arg( pArgList, DWORD ); | ||||||
|  | 	++szFormat; | ||||||
|  |       } | ||||||
|  |       num = va_arg( pArgList, DWORD_PTR ); | ||||||
|  |       switch (*szFormat++) | ||||||
|  |       { | ||||||
|  | 	case 'u': len += wsprintfA( buf + len, "%u", (DWORD)num ); break; | ||||||
|  | 	case 'X': len += wsprintfA( buf + len, "%X", (DWORD)num ); break; | ||||||
|  | 	case 'p': | ||||||
|  | #ifdef _WIN64 | ||||||
|  | 	  len += wsprintfA( buf + len, "%.8X_%.8X", | ||||||
|  | 				       (DWORD)(num >> 32), (DWORD)num ); | ||||||
|  | 	  break; | ||||||
|  | #endif | ||||||
|  | 	case 'q': len += wsprintfA( buf + len, "%.8X", (DWORD)num ); break; | ||||||
|  | 	case 'P': len += wsprintfA( buf + len, "00000000_%.8X", (DWORD)num ); break; | ||||||
|  | 	case 's': len = str_format( len, FALSE, num, slen ); break; | ||||||
|  | 	case 'S': len = str_format( len, TRUE, num, slen ); break; | ||||||
|  | 	default: | ||||||
|  | 	  buf[len++] = '%'; | ||||||
|  | 	  if (szFormat[-1] == '\0') | ||||||
|  | 	    --szFormat; | ||||||
|  | 	  else | ||||||
|  | 	    buf[len++] = szFormat[-1]; | ||||||
|  |       } | ||||||
|  |       if (len >= buf_len - 20) | ||||||
|  |       { | ||||||
|  | 	LPVOID tmp = HeapReAlloc( hHeap, 0, buf, buf_len + 128 ); | ||||||
|  | 	if (tmp == NULL) | ||||||
|  | 	  break; | ||||||
|  | 	buf = tmp; | ||||||
|  | 	buf_len = (DWORD)HeapSize( hHeap, 0, buf ); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   buf[len++] = '\r'; | ||||||
|  |   buf[len++] = '\n'; | ||||||
|  | 
 | ||||||
|  |   WriteFile( file, buf, len, &written, NULL ); | ||||||
|  | 
 | ||||||
|  |   size = GetFileSize( file, NULL ); | ||||||
|  |   CloseHandle( file ); | ||||||
|  |   ReleaseMutex( mutex ); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								version.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								version.h
									
									
									
									
									
								
							| @ -2,11 +2,11 @@ | |||||||
|   version.h - Version defines. |   version.h - Version defines. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #define PVERS	L"1.71"         // wide string
 | #define PVERS	L"1.72"         // wide string
 | ||||||
| #define PVERSA	 "1.71"         // ANSI string (windres 2.16.91 didn't like L)
 | #define PVERSA	 "1.72"         // ANSI string (windres 2.16.91 didn't like L)
 | ||||||
| #define PVERE	L"171"          // wide environment string
 | #define PVERE	L"172"          // wide environment string
 | ||||||
| #define PVEREA	 "171"          // ANSI environment string
 | #define PVEREA	 "172"          // ANSI environment string
 | ||||||
| #define PVERB	1,7,1,0 	// binary (resource)
 | #define PVERB	1,7,2,0 	// binary (resource)
 | ||||||
| 
 | 
 | ||||||
| #ifdef _WIN64 | #ifdef _WIN64 | ||||||
| # define BITS L"64" | # define BITS L"64" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jason Hood
						Jason Hood