|
|
/*++
Module Name:
forcedos.c
Abstract: This program forces NT to treat and execute the given program as a DOS application.
Author:
William Hsieh - williamh 25-Jan-1993
Revision History:
--*/
/*
Some applications have Windows or OS/2 executable format while run these program under NT, users will get the following message: Please run this program under DOS. Since NT selects the subsystem for application based on application executable format. There is no way for NT to "run this program under DOS". This utility was provided for this purpose. We create a pif file for the application and then create a process for the pif. Since pif file always goes to NTVDM we got the chance to play game on the program. NTVDM will decode the pif file and dispatch the program to DOS. All the subsequent program exec from the first program will be forced to execute under DOS. */ #define UNICODE 1
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winnlsp.h>
#include "forcedos.h"
#if DBG
#include <stdio.h>
#endif
WCHAR * Extention[MAX_EXTENTION]; WCHAR EXEExtention[] = L".EXE"; WCHAR COMExtention[] = L".COM"; WCHAR BATExtention[] = L".BAT"; WCHAR ProgramNameBuffer[MAX_PATH + 1]; WCHAR SearchPathName[MAX_PATH + 1]; WCHAR DefDirectory[MAX_PATH + 1]; char CommandLine[MAX_PATH + 1]; char ProgramName[MAX_PATH + 1]; WCHAR UnicodeMessage[MAX_MSG_LENGTH]; char OemMessage[MAX_MSG_LENGTH * 2];
#if DBG
BOOL fOutputDebugInfo = FALSE; #endif
void _cdecl main( int argc, char **argv ) { char *SavePtr;
char * pCommandLine; char * pCurDirectory; char * pProgramName; char * p; BOOL fDisplayUsage; ULONG i, nChar, Length, CommandLineLength; PROCESS_INFORMATION ProcessInformation; DWORD ExitCode, dw; STARTUPINFO StartupInfo; PUNICODE_STRING pTebUnicodeString; NTSTATUS Status; OEM_STRING OemString, CmdLineString; UNICODE_STRING UnicodeString; WCHAR *pwch, *pFilePart;
Extention[0] = COMExtention; Extention[1] = EXEExtention; Extention[2] = BATExtention;
// Set language code page to system locale.
SetThreadUILanguage(0);
pCurDirectory = pProgramName = NULL; pCommandLine = CommandLine; CommandLineLength = 0; pTebUnicodeString = &NtCurrentTeb()->StaticUnicodeString; fDisplayUsage = TRUE;
if ( argc > 1 ) { fDisplayUsage = FALSE;
while (--argc != 0) { p = *++argv; if (pProgramName == NULL) { if (*p == '/' || *p == '-') { switch (*++p) { case '?': fDisplayUsage = TRUE; break; case 'D': case 'd': // if the directory follows the /D immediately
// get it
if (*++p != 0) { pCurDirectory = p; break; } else if (--argc > 1) // the next argument must be the curdirectory
pCurDirectory = *++argv; else fDisplayUsage = TRUE; break;
default: fDisplayUsage = TRUE; break; } } else { pProgramName = p; nChar = strlen(p); if(nChar+1 >= sizeof(CommandLine)) { YellAndExit(ID_BAD_CMDLINE, 0xFF); } strncpy(CommandLine, pProgramName, nChar); pCommandLine = CommandLine + nChar; CommandLineLength = nChar + 1; } } else { // aggregate command line from all subsequent argvs
nChar = strlen(p);
//check if there is enough space to copy
if(CommandLineLength + nChar + sizeof(" ") >= sizeof(CommandLine)) { YellAndExit(ID_BAD_CMDLINE, 0xFF); }
if (CommandLineLength != 0) { strncpy(pCommandLine, " ", 1); pCommandLine++; } strncpy(pCommandLine, p, nChar); pCommandLine += nChar; CommandLineLength += nChar + 1; } if (fDisplayUsage) break; } if (pProgramName == NULL) fDisplayUsage = TRUE; }
if ( fDisplayUsage) { OemString.Length = 0; OemString.MaximumLength = MAX_MSG_LENGTH << 1; OemString.Buffer = OemMessage; UnicodeString.Length = 0; UnicodeString.Buffer = UnicodeMessage; UnicodeString.MaximumLength = MAX_MSG_LENGTH << 1; for (i = ID_USAGE_BASE; i <= ID_USAGE_MAX; i++) { nChar = LoadString(NULL, i, UnicodeString.Buffer, sizeof(UnicodeMessage)/sizeof(WCHAR)); UnicodeString.Length = (USHORT)(nChar << 1); Status = RtlUnicodeStringToOemString( &OemString, &UnicodeString, FALSE ); if (!NT_SUCCESS(Status)) break; if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), OemString.Buffer, OemString.Length, &Length, NULL) || Length != OemString.Length) break; } ExitProcess(0xFF); }
if (pCurDirectory != NULL) { #if DBG
if (fOutputDebugInfo) printf("Default directory = %s\n", pCurDirectory); #endif
RtlInitString((PSTRING)&OemString, pCurDirectory); UnicodeString.MaximumLength = (MAX_PATH + 1) * sizeof(WCHAR); UnicodeString.Buffer = DefDirectory; UnicodeString.Length = 0; Status = RtlOemStringToUnicodeString(&UnicodeString, &OemString, FALSE); if (!NT_SUCCESS(Status)) YellAndExit(ID_BAD_DEFDIR, 0xFF); dw = GetFileAttributes(DefDirectory); if (dw == (DWORD)(-1) || !(dw & FILE_ATTRIBUTE_DIRECTORY)) YellAndExit(ID_BAD_DEFDIR, 0xFF); SetCurrentDirectory(DefDirectory); } else GetCurrentDirectory(MAX_PATH + 1, DefDirectory);
// get a local copy of program name (for code conversion)
strcpy(ProgramName, pProgramName); pProgramName = ProgramName; // when we feed SearchPath with an initial path name ".;%path%"
// it will search the executable for use according to our requirement
// Currentdir -> path
SearchPathName[0] = L'.'; SearchPathName[1] = L';'; GetEnvironmentVariable(L"path", &SearchPathName[2], MAX_PATH + 1 - 2); RtlInitString((PSTRING)&OemString, pProgramName); Status = RtlOemStringToUnicodeString(pTebUnicodeString, &OemString, FALSE); if (!NT_SUCCESS(Status)) YellAndExit(ID_BAD_PATH, 0xFF); i = 0; nChar = 0; pwch = wcschr(pTebUnicodeString->Buffer, (WCHAR)'.'); Length = (pwch) ? 1 : MAX_EXTENTION; while (i < Length && (nChar = SearchPath( SearchPathName, pTebUnicodeString->Buffer, Extention[i], MAX_PATH + 1, ProgramNameBuffer, &pFilePart )) == 0) i++; if (nChar == 0) YellAndExit(ID_NO_FILE, 0xFF); nChar = GetFileAttributes(ProgramNameBuffer); if (nChar == (DWORD) (-1) || (nChar & FILE_ATTRIBUTE_DIRECTORY)) YellAndExit(ID_NO_FILE, 0xFF);
if (OemString.Length + CommandLineLength > 128 - 2 - 1) YellAndExit(ID_BAD_CMDLINE, 0xFF); #if DBG
if (fOutputDebugInfo) printf("Program path name is %s\n", ProgramNameBuffer); #endif
RtlInitString((PSTRING)&CmdLineString, CommandLine); Status = RtlOemStringToUnicodeString(pTebUnicodeString, &CmdLineString, FALSE); if (!NT_SUCCESS(Status)) YellAndExit(ID_BAD_CMDLINE, 0xFF);
ZeroMemory(&StartupInfo, sizeof(STARTUPINFO)); StartupInfo.cb = sizeof (STARTUPINFO); if (!CreateProcess( ProgramNameBuffer, // program name
pTebUnicodeString->Buffer,// command line
NULL, // process attr
NULL, // thread attr
TRUE, // inherithandle
CREATE_FORCEDOS, // create flag
NULL, // environment
DefDirectory, // cur dir
&StartupInfo, // startupinfo
&ProcessInformation )) { YellAndExit(ID_BAD_PROCESS, 0xFF); #if DBG
if(fOutputDebugInfo) printf("CreateProceess Failed, error code = %ld\n", GetLastError()); #endif
}
// LocalFree( SavePtr );
WaitForSingleObject(ProcessInformation.hProcess, INFINITE); GetExitCodeProcess(ProcessInformation.hProcess, &ExitCode); CloseHandle(ProcessInformation.hProcess); ExitProcess(ExitCode); }
VOID YellAndExit ( UINT MsgID, // string table id from resource
WORD ExitCode // exit code to be used
) { int MessageSize; ULONG SizeWritten; OEM_STRING OemString; UNICODE_STRING UnicodeString;
MessageSize = LoadString(NULL, MsgID, UnicodeMessage, sizeof(UnicodeMessage)/sizeof(WCHAR)); OemString.Buffer = OemMessage; OemString.Length = 0; OemString.MaximumLength = MAX_MSG_LENGTH * 2; RtlInitUnicodeString(&UnicodeString, UnicodeMessage); RtlUnicodeStringToOemString(&OemString, &UnicodeString, FALSE);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), OemString.Buffer, OemString.Length, &SizeWritten, NULL );
ExitProcess(ExitCode); }
|