Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

323 lines
9.5 KiB

/*++
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);
}