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

  1. /*++
  2. Module Name:
  3. forcedos.c
  4. Abstract:
  5. This program forces NT to treat and execute the given program
  6. as a DOS application.
  7. Author:
  8. William Hsieh - williamh 25-Jan-1993
  9. Revision History:
  10. --*/
  11. /*
  12. Some applications have Windows or OS/2 executable format while
  13. run these program under NT, users will get the following message:
  14. Please run this program under DOS. Since NT selects the subsystem
  15. for application based on application executable format. There is
  16. no way for NT to "run this program under DOS". This utility was provided
  17. for this purpose. We create a pif file for the application and then
  18. create a process for the pif. Since pif file always goes to NTVDM
  19. we got the chance to play game on the program. NTVDM will decode
  20. the pif file and dispatch the program to DOS. All the subsequent program
  21. exec from the first program will be forced to execute under DOS.
  22. */
  23. #define UNICODE 1
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #include <windows.h>
  28. #include <winnlsp.h>
  29. #include "forcedos.h"
  30. #if DBG
  31. #include <stdio.h>
  32. #endif
  33. WCHAR * Extention[MAX_EXTENTION];
  34. WCHAR EXEExtention[] = L".EXE";
  35. WCHAR COMExtention[] = L".COM";
  36. WCHAR BATExtention[] = L".BAT";
  37. WCHAR ProgramNameBuffer[MAX_PATH + 1];
  38. WCHAR SearchPathName[MAX_PATH + 1];
  39. WCHAR DefDirectory[MAX_PATH + 1];
  40. char CommandLine[MAX_PATH + 1];
  41. char ProgramName[MAX_PATH + 1];
  42. WCHAR UnicodeMessage[MAX_MSG_LENGTH];
  43. char OemMessage[MAX_MSG_LENGTH * 2];
  44. #if DBG
  45. BOOL fOutputDebugInfo = FALSE;
  46. #endif
  47. void
  48. _cdecl
  49. main(
  50. int argc,
  51. char **argv
  52. )
  53. {
  54. char *SavePtr;
  55. char * pCommandLine;
  56. char * pCurDirectory;
  57. char * pProgramName;
  58. char * p;
  59. BOOL fDisplayUsage;
  60. ULONG i, nChar, Length, CommandLineLength;
  61. PROCESS_INFORMATION ProcessInformation;
  62. DWORD ExitCode, dw;
  63. STARTUPINFO StartupInfo;
  64. PUNICODE_STRING pTebUnicodeString;
  65. NTSTATUS Status;
  66. OEM_STRING OemString, CmdLineString;
  67. UNICODE_STRING UnicodeString;
  68. WCHAR *pwch, *pFilePart;
  69. Extention[0] = COMExtention;
  70. Extention[1] = EXEExtention;
  71. Extention[2] = BATExtention;
  72. // Set language code page to system locale.
  73. SetThreadUILanguage(0);
  74. pCurDirectory = pProgramName = NULL;
  75. pCommandLine = CommandLine;
  76. CommandLineLength = 0;
  77. pTebUnicodeString = &NtCurrentTeb()->StaticUnicodeString;
  78. fDisplayUsage = TRUE;
  79. if ( argc > 1 ) {
  80. fDisplayUsage = FALSE;
  81. while (--argc != 0) {
  82. p = *++argv;
  83. if (pProgramName == NULL) {
  84. if (*p == '/' || *p == '-') {
  85. switch (*++p) {
  86. case '?':
  87. fDisplayUsage = TRUE;
  88. break;
  89. case 'D':
  90. case 'd':
  91. // if the directory follows the /D immediately
  92. // get it
  93. if (*++p != 0) {
  94. pCurDirectory = p;
  95. break;
  96. }
  97. else if (--argc > 1)
  98. // the next argument must be the curdirectory
  99. pCurDirectory = *++argv;
  100. else
  101. fDisplayUsage = TRUE;
  102. break;
  103. default:
  104. fDisplayUsage = TRUE;
  105. break;
  106. }
  107. }
  108. else {
  109. pProgramName = p;
  110. nChar = strlen(p);
  111. if(nChar+1 >= sizeof(CommandLine)) {
  112. YellAndExit(ID_BAD_CMDLINE, 0xFF);
  113. }
  114. strncpy(CommandLine, pProgramName, nChar);
  115. pCommandLine = CommandLine + nChar;
  116. CommandLineLength = nChar + 1;
  117. }
  118. }
  119. else {
  120. // aggregate command line from all subsequent argvs
  121. nChar = strlen(p);
  122. //check if there is enough space to copy
  123. if(CommandLineLength + nChar + sizeof(" ") >= sizeof(CommandLine)) {
  124. YellAndExit(ID_BAD_CMDLINE, 0xFF);
  125. }
  126. if (CommandLineLength != 0) {
  127. strncpy(pCommandLine, " ", 1);
  128. pCommandLine++;
  129. }
  130. strncpy(pCommandLine, p, nChar);
  131. pCommandLine += nChar;
  132. CommandLineLength += nChar + 1;
  133. }
  134. if (fDisplayUsage)
  135. break;
  136. }
  137. if (pProgramName == NULL)
  138. fDisplayUsage = TRUE;
  139. }
  140. if ( fDisplayUsage) {
  141. OemString.Length = 0;
  142. OemString.MaximumLength = MAX_MSG_LENGTH << 1;
  143. OemString.Buffer = OemMessage;
  144. UnicodeString.Length = 0;
  145. UnicodeString.Buffer = UnicodeMessage;
  146. UnicodeString.MaximumLength = MAX_MSG_LENGTH << 1;
  147. for (i = ID_USAGE_BASE; i <= ID_USAGE_MAX; i++) {
  148. nChar = LoadString(NULL,
  149. i,
  150. UnicodeString.Buffer,
  151. sizeof(UnicodeMessage)/sizeof(WCHAR));
  152. UnicodeString.Length = (USHORT)(nChar << 1);
  153. Status = RtlUnicodeStringToOemString(
  154. &OemString,
  155. &UnicodeString,
  156. FALSE
  157. );
  158. if (!NT_SUCCESS(Status))
  159. break;
  160. if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
  161. OemString.Buffer,
  162. OemString.Length,
  163. &Length, NULL) ||
  164. Length != OemString.Length)
  165. break;
  166. }
  167. ExitProcess(0xFF);
  168. }
  169. if (pCurDirectory != NULL) {
  170. #if DBG
  171. if (fOutputDebugInfo)
  172. printf("Default directory = %s\n", pCurDirectory);
  173. #endif
  174. RtlInitString((PSTRING)&OemString, pCurDirectory);
  175. UnicodeString.MaximumLength = (MAX_PATH + 1) * sizeof(WCHAR);
  176. UnicodeString.Buffer = DefDirectory;
  177. UnicodeString.Length = 0;
  178. Status = RtlOemStringToUnicodeString(&UnicodeString, &OemString, FALSE);
  179. if (!NT_SUCCESS(Status))
  180. YellAndExit(ID_BAD_DEFDIR, 0xFF);
  181. dw = GetFileAttributes(DefDirectory);
  182. if (dw == (DWORD)(-1) || !(dw & FILE_ATTRIBUTE_DIRECTORY))
  183. YellAndExit(ID_BAD_DEFDIR, 0xFF);
  184. SetCurrentDirectory(DefDirectory);
  185. }
  186. else
  187. GetCurrentDirectory(MAX_PATH + 1, DefDirectory);
  188. // get a local copy of program name (for code conversion)
  189. strcpy(ProgramName, pProgramName);
  190. pProgramName = ProgramName;
  191. // when we feed SearchPath with an initial path name ".;%path%"
  192. // it will search the executable for use according to our requirement
  193. // Currentdir -> path
  194. SearchPathName[0] = L'.';
  195. SearchPathName[1] = L';';
  196. GetEnvironmentVariable(L"path", &SearchPathName[2], MAX_PATH + 1 - 2);
  197. RtlInitString((PSTRING)&OemString, pProgramName);
  198. Status = RtlOemStringToUnicodeString(pTebUnicodeString, &OemString, FALSE);
  199. if (!NT_SUCCESS(Status))
  200. YellAndExit(ID_BAD_PATH, 0xFF);
  201. i = 0;
  202. nChar = 0;
  203. pwch = wcschr(pTebUnicodeString->Buffer, (WCHAR)'.');
  204. Length = (pwch) ? 1 : MAX_EXTENTION;
  205. while (i < Length &&
  206. (nChar = SearchPath(
  207. SearchPathName,
  208. pTebUnicodeString->Buffer,
  209. Extention[i],
  210. MAX_PATH + 1,
  211. ProgramNameBuffer,
  212. &pFilePart
  213. )) == 0)
  214. i++;
  215. if (nChar == 0)
  216. YellAndExit(ID_NO_FILE, 0xFF);
  217. nChar = GetFileAttributes(ProgramNameBuffer);
  218. if (nChar == (DWORD) (-1) || (nChar & FILE_ATTRIBUTE_DIRECTORY))
  219. YellAndExit(ID_NO_FILE, 0xFF);
  220. if (OemString.Length + CommandLineLength > 128 - 2 - 1)
  221. YellAndExit(ID_BAD_CMDLINE, 0xFF);
  222. #if DBG
  223. if (fOutputDebugInfo)
  224. printf("Program path name is %s\n", ProgramNameBuffer);
  225. #endif
  226. RtlInitString((PSTRING)&CmdLineString, CommandLine);
  227. Status = RtlOemStringToUnicodeString(pTebUnicodeString, &CmdLineString, FALSE);
  228. if (!NT_SUCCESS(Status))
  229. YellAndExit(ID_BAD_CMDLINE, 0xFF);
  230. ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
  231. StartupInfo.cb = sizeof (STARTUPINFO);
  232. if (!CreateProcess(
  233. ProgramNameBuffer, // program name
  234. pTebUnicodeString->Buffer,// command line
  235. NULL, // process attr
  236. NULL, // thread attr
  237. TRUE, // inherithandle
  238. CREATE_FORCEDOS, // create flag
  239. NULL, // environment
  240. DefDirectory, // cur dir
  241. &StartupInfo, // startupinfo
  242. &ProcessInformation
  243. )) {
  244. YellAndExit(ID_BAD_PROCESS, 0xFF);
  245. #if DBG
  246. if(fOutputDebugInfo)
  247. printf("CreateProceess Failed, error code = %ld\n", GetLastError());
  248. #endif
  249. }
  250. // LocalFree( SavePtr );
  251. WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
  252. GetExitCodeProcess(ProcessInformation.hProcess, &ExitCode);
  253. CloseHandle(ProcessInformation.hProcess);
  254. ExitProcess(ExitCode);
  255. }
  256. VOID YellAndExit
  257. (
  258. UINT MsgID, // string table id from resource
  259. WORD ExitCode // exit code to be used
  260. )
  261. {
  262. int MessageSize;
  263. ULONG SizeWritten;
  264. OEM_STRING OemString;
  265. UNICODE_STRING UnicodeString;
  266. MessageSize = LoadString(NULL, MsgID, UnicodeMessage, sizeof(UnicodeMessage)/sizeof(WCHAR));
  267. OemString.Buffer = OemMessage;
  268. OemString.Length = 0;
  269. OemString.MaximumLength = MAX_MSG_LENGTH * 2;
  270. RtlInitUnicodeString(&UnicodeString, UnicodeMessage);
  271. RtlUnicodeStringToOemString(&OemString, &UnicodeString, FALSE);
  272. WriteFile(GetStdHandle(STD_ERROR_HANDLE),
  273. OemString.Buffer,
  274. OemString.Length,
  275. &SizeWritten,
  276. NULL
  277. );
  278. ExitProcess(ExitCode);
  279. }