Source code of Windows XP (NT5)
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.

999 lines
30 KiB

  1. /* cmdmisc.c - Misc. SVC routines of Command.lib
  2. *
  3. *
  4. * Modification History:
  5. *
  6. * Sudeepb 17-Sep-1991 Created
  7. */
  8. #include "cmd.h"
  9. #include <cmdsvc.h>
  10. #include <demexp.h>
  11. #include <softpc.h>
  12. #include <mvdm.h>
  13. #include <ctype.h>
  14. #include <memory.h>
  15. #include "oemuni.h"
  16. #include "nt_pif.h"
  17. #include "nt_uis.h" // For resource id
  18. #if defined(NEC_98)
  19. extern UINT saveCP;
  20. extern UINT saveOutputCP;
  21. #endif // NEC_98
  22. VOID GetWowKernelCmdLine(VOID);
  23. extern ULONG fSeparateWow;
  24. #if defined(KOREA)
  25. //To fix HaNa spread sheet IME hot key problem
  26. //09/20/96 bklee. See mvdm\v86\monitor\i386\monitor.c
  27. BOOL bIgnoreExtraKbdDisable = FALSE;
  28. #endif
  29. VOID cmdGetNextCmd (VOID)
  30. {
  31. LPSTR lpszCmd;
  32. PCMDINFO pCMDInfo;
  33. ULONG cb;
  34. PREDIRCOMPLETE_INFO pRdrInfo;
  35. VDMINFO MyVDMInfo;
  36. char *pSrc, *pDst;
  37. char achCurDirectory[MAXIMUM_VDM_CURRENT_DIR + 4];
  38. char CmdLine[MAX_PATH];
  39. //
  40. // This routine is called once for WOW VDMs, to retrieve the
  41. // "krnl386" command line.
  42. // 5
  43. if (VDMForWOW) {
  44. GetWowKernelCmdLine();
  45. #if defined(NEC_98)
  46. cmdInitConsole();
  47. #endif // NEC_98
  48. return;
  49. }
  50. VDMInfo.VDMState = 0;
  51. pCMDInfo = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
  52. VDMInfo.ErrorCode = FETCHWORD(pCMDInfo->ReturnCode);
  53. VDMInfo.CmdSize = sizeof(CmdLine);
  54. VDMInfo.CmdLine = CmdLine;
  55. VDMInfo.AppName = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->ExecPathSeg),
  56. FETCHWORD(pCMDInfo->ExecPathOff));
  57. VDMInfo.AppLen = FETCHWORD(pCMDInfo->ExecPathSize);
  58. VDMInfo.PifLen = 0;
  59. VDMInfo.EnviornmentSize = 0;
  60. VDMInfo.Enviornment = NULL;
  61. VDMInfo.CurDrive = 0;
  62. VDMInfo.TitleLen = 0;
  63. VDMInfo.ReservedLen = 0;
  64. VDMInfo.DesktopLen = 0;
  65. VDMInfo.CurDirectoryLen = MAX_PATH + 1;
  66. VDMInfo.CurDirectory = achCurDirectory;
  67. if(IsFirstCall){
  68. VDMInfo.VDMState = ASKING_FOR_FIRST_COMMAND;
  69. VDMInfo.ErrorCode = 0;
  70. DeleteConfigFiles(); // get rid of the temp boot files
  71. // When COMMAND.COM issues first cmdGetNextCmd, it has
  72. // a completed environment already(cmdGetInitEnvironment),
  73. // Therefore, we don't have to ask environment from BASE
  74. cmdVDMEnvBlk.lpszzEnv = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->EnvSeg),0);
  75. cmdVDMEnvBlk.cchEnv = FETCHWORD(pCMDInfo->EnvSize);
  76. // Check BLASTER environment variable to determine if Sound Blaster
  77. // emulation should be disabled.
  78. if (cmdGetEnvironmentVariable(NULL, "BLASTER", CmdLine, MAX_PATH)) {
  79. SbReinitialize(CmdLine, MAX_PATH);
  80. }
  81. //clear bits that track printer flushing
  82. host_lpt_flush_initialize();
  83. }
  84. else {
  85. // program has terminated. If the termiation was issued from
  86. // second(or later) instance of command.com(cmd.exe), don't
  87. // reset the flag.
  88. if (Exe32ActiveCount == 0)
  89. DontCheckDosBinaryType = FALSE;
  90. // tell the base our new current directories (in ANSI)
  91. // we don't do it on repeat call(the shell out case is handled in
  92. // return exit code
  93. if (!IsRepeatCall) {
  94. cmdUpdateCurrentDirectories((BYTE)pCMDInfo->CurDrive);
  95. }
  96. VDMInfo.VDMState = 0;
  97. if(!IsRepeatCall){
  98. demCloseAllPSPRecords ();
  99. if (!pfdata.CloseOnExit && DosSessionId)
  100. nt_block_event_thread(1);
  101. else
  102. nt_block_event_thread(0);
  103. if (DosSessionId) {
  104. pRdrInfo = (PREDIRCOMPLETE_INFO) FETCHDWORD(pCMDInfo->pRdrInfo);
  105. if (!pfdata.CloseOnExit){
  106. char achTitle[MAX_PATH];
  107. char achInactive[60]; //should be plenty for 'inactive'
  108. strcpy (achTitle, "[");
  109. if (!LoadString(GetModuleHandle(NULL), EXIT_NO_CLOSE,
  110. achInactive, 60))
  111. strcat (achTitle, "Inactive ");
  112. else
  113. strcat(achTitle, achInactive);
  114. cb = strlen(achTitle);
  115. // GetConsoleTitleA and SetConsoleTitleA
  116. // are working on OEM character set.
  117. GetConsoleTitleA(achTitle + cb, MAX_PATH - cb - 1);
  118. cb = strlen(achTitle);
  119. achTitle[cb] = ']';
  120. achTitle[cb + 1] = '\0';
  121. SetConsoleTitleA(achTitle);
  122. // finish touch on redirection stuff
  123. cmdCheckCopyForRedirection (pRdrInfo, FALSE);
  124. Sleep(INFINITE);
  125. }
  126. else {
  127. // finish touch on redirection stuff
  128. // this will wait on the output thread if there
  129. // are any.
  130. cmdCheckCopyForRedirection (pRdrInfo, TRUE);
  131. VdmExitCode = VDMInfo.ErrorCode;
  132. TerminateVDM();
  133. }
  134. }
  135. fBlock = TRUE;
  136. #if defined(NEC_98)
  137. if (!VDMForWOW) { // BugFix: Change IME status by Screen Saver of 16bit
  138. SetConsoleCP(saveCP);
  139. SetConsoleOutputCP(saveOutputCP);
  140. }
  141. #endif // NEC_98
  142. }
  143. }
  144. if(IsRepeatCall) {
  145. VDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
  146. if( VDMInfo.ErrorCode != 0 )
  147. IsRepeatCall = FALSE;
  148. }
  149. VDMInfo.VDMState |= ASKING_FOR_DOS_BINARY;
  150. if (!IsFirstCall && !(VDMInfo.VDMState & ASKING_FOR_SECOND_TIME)) {
  151. pRdrInfo = (PREDIRCOMPLETE_INFO) FETCHDWORD(pCMDInfo->pRdrInfo);
  152. if (!cmdCheckCopyForRedirection (pRdrInfo, FALSE))
  153. VDMInfo.ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  154. }
  155. // Leave the current directory in a safe place, so that other 32bit
  156. // apps etc. can delnode this directory (and other such operations) later.
  157. if ( IsFirstCall == FALSE && IsRepeatCall == FALSE )
  158. SetCurrentDirectory (cmdHomeDirectory);
  159. // TSRExit will be set to 1, only if we are coming from command.com's
  160. // prompt and user typed an exit. We need to kill our parent also, so we
  161. // should write an exit in the console buffer.
  162. if (FETCHWORD(pCMDInfo->fTSRExit)) {
  163. cmdPushExitInConsoleBuffer ();
  164. }
  165. /**
  166. Merging environment is required if
  167. (1). Not the first comamnd &&
  168. (2). NTVDM is running on an existing console ||
  169. NTVDM has been shelled out.
  170. Note that WOW doesn't need enviornment merging.
  171. **/
  172. if (!DosEnvCreated && !IsFirstCall && (!DosSessionId || Exe32ActiveCount)) {
  173. RtlZeroMemory(&MyVDMInfo, sizeof(VDMINFO));
  174. MyVDMInfo.VDMState = ASKING_FOR_ENVIRONMENT | ASKING_FOR_DOS_BINARY;
  175. if (IsRepeatCall) {
  176. MyVDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
  177. MyVDMInfo.ErrorCode = 0;
  178. }
  179. else
  180. MyVDMInfo.ErrorCode = VDMInfo.ErrorCode;
  181. MyVDMInfo.Enviornment = lpszzVDMEnv32;
  182. MyVDMInfo.EnviornmentSize = (USHORT) cchVDMEnv32;
  183. if (!GetNextVDMCommand(&MyVDMInfo) && MyVDMInfo.EnviornmentSize > cchVDMEnv32) {
  184. MyVDMInfo.Enviornment = realloc(lpszzVDMEnv32, MyVDMInfo.EnviornmentSize);
  185. if (MyVDMInfo.Enviornment == NULL) {
  186. RcErrorDialogBox(EG_MALLOC_FAILURE, NULL, NULL);
  187. TerminateVDM();
  188. }
  189. lpszzVDMEnv32 = MyVDMInfo.Enviornment;
  190. cchVDMEnv32 = MyVDMInfo.EnviornmentSize;
  191. MyVDMInfo.VDMState = ASKING_FOR_DOS_BINARY | ASKING_FOR_ENVIRONMENT |
  192. ASKING_FOR_SECOND_TIME;
  193. MyVDMInfo.TitleLen =
  194. MyVDMInfo.DesktopLen =
  195. MyVDMInfo.ReservedLen =
  196. MyVDMInfo.CmdSize =
  197. MyVDMInfo.AppLen =
  198. MyVDMInfo.PifLen =
  199. MyVDMInfo.CurDirectoryLen = 0;
  200. MyVDMInfo.ErrorCode = 0;
  201. if (!GetNextVDMCommand(&MyVDMInfo)) {
  202. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  203. TerminateVDM();
  204. }
  205. }
  206. if (!cmdCreateVDMEnvironment(&cmdVDMEnvBlk)) {
  207. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  208. TerminateVDM();
  209. }
  210. DosEnvCreated = TRUE;
  211. VDMInfo.ErrorCode = 0;
  212. }
  213. if (cmdVDMEnvBlk.cchEnv > FETCHWORD(pCMDInfo->EnvSize)) {
  214. setAX((USHORT)cmdVDMEnvBlk.cchEnv);
  215. setCF(1);
  216. IsFirstCall = FALSE;
  217. IsRepeatCall = TRUE;
  218. #if defined(NEC_98)
  219. cmdInitConsole();
  220. #endif // NEC_98
  221. return;
  222. }
  223. if (DosEnvCreated)
  224. VDMInfo.VDMState |= ASKING_FOR_SECOND_TIME;
  225. if(!GetNextVDMCommand(&VDMInfo)){
  226. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  227. TerminateVDM();
  228. }
  229. IsRepeatCall = FALSE;
  230. IsFirstCall = FALSE;
  231. if(fBlock){
  232. #if defined(NEC_98)
  233. if (!VDMForWOW) { // BugFix: Change IME status by Screen Saver of 16bit
  234. saveCP = GetConsoleCP();
  235. saveOutputCP = GetConsoleOutputCP();
  236. SetConsoleCP(932);
  237. SetConsoleOutputCP(932);
  238. }
  239. #endif // NEC_98
  240. nt_resume_event_thread();
  241. fBlock = FALSE;
  242. }
  243. // Sync VDMs enviornment variables for current directories
  244. cmdSetDirectories (lpszzVDMEnv32, &VDMInfo);
  245. // tell DOS that this is a dos executable and no further checking is
  246. // necessary
  247. *pIsDosBinary = 1;
  248. // Check for PIF files. If a pif file is being executed extract the
  249. // executable name, command line, current directory and title from the pif
  250. // file and place the stuff appropriately in VDMInfo. Note, if pif file
  251. // is invalid, we dont do any thing to vdminfo. In such a case we
  252. // pass the pif as it is to scs to execute which we know will fail and
  253. // will come back to cmdGettNextCmd with proper error code.
  254. cmdCheckForPIF (&VDMInfo);
  255. //
  256. // if forcedos, then don't check binary type on int 21 exec process,
  257. // so that child spawns stay in dos land. Begining with NT 4.0 forcedos.exe
  258. // no longer uses pif files to force execution of a binary as a dos exe.
  259. // It now uses a bit in CreateProcess (dwCreationFlags).
  260. //
  261. DontCheckDosBinaryType = (VDMInfo.dwCreationFlags & CREATE_FORCEDOS) != 0;
  262. // convert exec path name to upper case. This is what command.com expect
  263. if (WOW32_strupr(VDMInfo.AppName) == NULL) {
  264. pSrc = VDMInfo.AppName;
  265. while (*pSrc)
  266. *pSrc++ = (char)toupper((int)*pSrc);
  267. }
  268. // figure out the extention type
  269. // at least one char for the base name plus
  270. // EXTENTION_STRING_LEN for the extention
  271. // plus the NULL char
  272. if (VDMInfo.AppLen > 1 + EXTENTION_STRING_LEN + 1) {
  273. pSrc = (PCHAR)VDMInfo.AppName + VDMInfo.AppLen - 5;
  274. if (!strncmp(pSrc, EXE_EXTENTION_STRING, EXTENTION_STRING_LEN))
  275. STOREWORD(pCMDInfo->ExecExtType, EXE_EXTENTION);
  276. else if (!strncmp(pSrc, COM_EXTENTION_STRING, EXTENTION_STRING_LEN))
  277. STOREWORD(pCMDInfo->ExecExtType, COM_EXTENTION);
  278. else if (!strncmp(pSrc, BAT_EXTENTION_STRING, EXTENTION_STRING_LEN))
  279. STOREWORD(pCMDInfo->ExecExtType, BAT_EXTENTION);
  280. else
  281. STOREWORD(pCMDInfo->ExecExtType, UNKNOWN_EXTENTION);
  282. }
  283. else
  284. STOREWORD(pCMDInfo->ExecExtType, UNKNOWN_EXTENTION);
  285. // tell command.com the length of the app full path name.
  286. STOREWORD(pCMDInfo->ExecPathSize, VDMInfo.AppLen);
  287. //
  288. // Prepare ccom's UCOMBUF
  289. //
  290. lpszCmd = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->CmdLineSeg),
  291. FETCHWORD(pCMDInfo->CmdLineOff));
  292. // Copy filepart of AppName excluding extension to ccom's buffer
  293. pSrc = strrchr(VDMInfo.AppName, '\\');
  294. #if defined(KOREA)
  295. // To fix HaNa spread sheet IME hotkey problem.
  296. {
  297. LPSTR pStrt, pEnd;
  298. char szModName[9];
  299. SHORT len;
  300. pStrt = pSrc;
  301. if (pStrt==NULL)
  302. pStrt = VDMInfo.AppName;
  303. else
  304. pStrt++;
  305. if ( (pEnd = strchr (pStrt, '.')) == NULL)
  306. strncpy (szModName, pStrt, 9);
  307. else {
  308. len = (SHORT) (pEnd - pStrt);
  309. if (len<=8) {
  310. strncpy (szModName, pStrt, len);
  311. szModName[len] = '\0';
  312. }
  313. }
  314. bIgnoreExtraKbdDisable = !(strcmp("HANASP", szModName));
  315. }
  316. #endif
  317. if (!pSrc) {
  318. pSrc = VDMInfo.AppName;
  319. }
  320. else {
  321. pSrc++;
  322. }
  323. pDst = lpszCmd + 2;
  324. while (*pSrc && *pSrc != '.') {
  325. *pDst++ = *pSrc++;
  326. }
  327. cb = strlen(CmdLine);
  328. // cmd line must be terminated with "\0xd\0xa\0". This is either done
  329. // by BASE or cmdCheckForPif function(cmdpif.c).
  330. ASSERT((cb >= 2) && (0xd == CmdLine[cb - 2]) && (0xa == CmdLine[cb - 1]));
  331. // if cmd line is not blank, separate program base name and
  332. // cmd line with a SPACE. If it IS blank, do not insert any white chars
  333. // or we end up passing white chars to the applications as cmd line
  334. // and some applications just can not live with that.
  335. // We do not strip leading white characters in the passed command line
  336. // so the application sees the original data.
  337. if (cb > 2)
  338. *pDst++ = ' ';
  339. // append the command tail(at least, "\0xd\0xa")
  340. strncpy(pDst, CmdLine, cb + 1);
  341. // set the count
  342. // cb has the cmd line length including the terminated 0xd and 0xa
  343. // It does NOT count the terminated NULL char.
  344. ASSERT((cb + pDst - lpszCmd - 2) <= 127);
  345. // minus 2 because the real data in lpszCmd start from lpszCmd[2]
  346. lpszCmd[1] = (CHAR)(cb + pDst - lpszCmd - 2);
  347. if (DosEnvCreated) {
  348. VDMInfo.Enviornment = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->EnvSeg),0);
  349. RtlMoveMemory(VDMInfo.Enviornment,
  350. cmdVDMEnvBlk.lpszzEnv,
  351. cmdVDMEnvBlk.cchEnv
  352. );
  353. STOREWORD(pCMDInfo->EnvSize,cmdVDMEnvBlk.cchEnv);
  354. free(cmdVDMEnvBlk.lpszzEnv);
  355. DosEnvCreated = FALSE;
  356. }
  357. STOREWORD(pCMDInfo->fBatStatus,(USHORT)VDMInfo.fComingFromBat);
  358. STOREWORD(pCMDInfo->CurDrive,VDMInfo.CurDrive);
  359. STOREWORD(pCMDInfo->NumDrives,nDrives);
  360. VDMInfo.CodePage = (ULONG) cmdMapCodePage (VDMInfo.CodePage);
  361. STOREWORD(pCMDInfo->CodePage,(USHORT)VDMInfo.CodePage);
  362. cmdVDMEnvBlk.lpszzEnv = NULL;
  363. cmdVDMEnvBlk.cchEnv = 0;
  364. IsFirstVDM = FALSE;
  365. // Handle Standard IO redirection
  366. pRdrInfo = cmdCheckStandardHandles (&VDMInfo,&pCMDInfo->bStdHandles);
  367. STOREDWORD(pCMDInfo->pRdrInfo,(ULONG)pRdrInfo);
  368. // Tell DOS that it has to invalidate the CDSs
  369. *pSCS_ToSync = (CHAR)0xff;
  370. setCF(0);
  371. #if defined(NEC_98)
  372. cmdInitConsole();
  373. #endif // NEC_98
  374. return;
  375. }
  376. VOID GetWowKernelCmdLine(VOID)
  377. {
  378. CMDINFO UNALIGNED *pCMDInfo;
  379. PCHAR pch, pEnvStrings;
  380. PCHAR pSlash;
  381. int Len;
  382. LPSTR pszCmdLine;
  383. DeleteConfigFiles(); // get rid of the temp boot files
  384. host_lpt_flush_initialize();
  385. //
  386. // Only a few things need be set for WOW.
  387. // 1. NumDrives
  388. // 2. Kernel CmdLine (get from ntvdm command tail)
  389. // 3. Current drive
  390. //
  391. // Command.com has setup correct enviroment block at
  392. // this moment, so don't bother to mess with environment stuff.
  393. pCMDInfo = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
  394. pCMDInfo->NumDrives = nDrives;
  395. //
  396. // Get the command line parameter, which consists of a fully
  397. // qualified short path file name: "-a %SystemRoot%\system32\krnl386.exe".
  398. //
  399. // Note that the first token of cmdline is "%SystemRoot%\system32\ntvdm ",
  400. // and may be a long file name surrounded by quotes.
  401. //
  402. pszCmdLine = GetCommandLine();
  403. if (pszCmdLine) {
  404. // skip leading spaces
  405. while (*pszCmdLine && !isgraph(*pszCmdLine)) {
  406. pszCmdLine++;
  407. }
  408. // skip first token
  409. if (*pszCmdLine == '"') {
  410. pszCmdLine++;
  411. while (*pszCmdLine && *pszCmdLine++ != '"')
  412. ;
  413. }
  414. else {
  415. while (isgraph(*pszCmdLine)) {
  416. pszCmdLine++;
  417. }
  418. }
  419. // mov to beg of WowKernelPathName
  420. pszCmdLine = strstr(pszCmdLine, " -a ");
  421. pszCmdLine += 4;
  422. while (*pszCmdLine && *pszCmdLine == ' ') {
  423. pszCmdLine++;
  424. }
  425. }
  426. if (!pszCmdLine || !*pszCmdLine) {
  427. RcErrorDialogBox(EG_ENVIRONMENT_ERR, NULL, NULL);
  428. TerminateVDM();
  429. }
  430. //
  431. // Copy first token to ExecPath, and find the beg of the file part.
  432. //
  433. Len = FETCHWORD(pCMDInfo->ExecPathSize);
  434. pch = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->ExecPathSeg),
  435. FETCHWORD(pCMDInfo->ExecPathOff));
  436. pSlash = pszCmdLine;
  437. while (--Len && isgraph(*pszCmdLine)) {
  438. if (*pszCmdLine == '\\') {
  439. pSlash = pszCmdLine + 1;
  440. }
  441. *pch++ = *pszCmdLine++;
  442. }
  443. *pch = '\0';
  444. pCMDInfo->ExecPathSize -= (USHORT)Len;
  445. pCMDInfo->ExecExtType = EXE_EXTENTION; // for WOW, use EXE extention
  446. pszCmdLine = pSlash; // filepart begins here
  447. //
  448. // Copy filepart of first token and rest to CmdLine buffer
  449. //
  450. Len = FETCHWORD(pCMDInfo->CmdLineSize);
  451. pch = (PVOID)GetVDMAddr(FETCHWORD(pCMDInfo->CmdLineSeg),
  452. FETCHWORD(pCMDInfo->CmdLineOff));
  453. while (--Len && *pszCmdLine) {
  454. *pch++ = *pszCmdLine++;
  455. }
  456. strcpy(pch, "\x0d\x0a");
  457. *pIsDosBinary = 1;
  458. IsRepeatCall = FALSE;
  459. IsFirstCall = FALSE;
  460. // Tell DOS that it has to invalidate the CDSs
  461. *pSCS_ToSync = (CHAR)0xff;
  462. setCF(0);
  463. return;
  464. }
  465. /* cmdGetCurrentDir - Return the current directory for a drive.
  466. *
  467. *
  468. * Entry - Client (DS:SI) - buffer to return the directory
  469. * Client (AL) - drive being queried (0 = A)
  470. *
  471. * EXIT - SUCCESS Client (CY) clear
  472. * FAILURE Client (CY) set
  473. * (AX) = 0 (Directory was bigger than 64)
  474. * (AX) = 1 (the drive is not valid)
  475. *
  476. */
  477. VOID cmdGetCurrentDir (VOID)
  478. {
  479. PCHAR lpszCurDir;
  480. UCHAR chDrive;
  481. CHAR EnvVar[] = "=?:";
  482. CHAR RootName[] = "?:\\";
  483. DWORD EnvVarLen;
  484. UINT DriveType;
  485. lpszCurDir = (PCHAR) GetVDMAddr ((USHORT)getDS(),(USHORT)getSI());
  486. chDrive = getAL();
  487. EnvVar[1] = chDrive + 'A';
  488. RootName[0] = chDrive + 'A';
  489. // if the drive doesn't exist, blindly clear the environment var
  490. // and return error
  491. DriveType = demGetPhysicalDriveType(chDrive);
  492. if (DriveType == DRIVE_UNKNOWN) {
  493. DriveType = GetDriveTypeOem(RootName);
  494. }
  495. if (DriveType == DRIVE_UNKNOWN || DriveType == DRIVE_NO_ROOT_DIR){
  496. SetEnvironmentVariableOem(EnvVar, NULL);
  497. setCF(1);
  498. setAX(0);
  499. return;
  500. }
  501. if((EnvVarLen = GetEnvironmentVariableOem (EnvVar,lpszCurDir,
  502. MAXIMUM_VDM_CURRENT_DIR+3)) == 0){
  503. // if its not in env then and drive exist then we have'nt
  504. // yet touched it.
  505. strcpy(lpszCurDir, RootName);
  506. SetEnvironmentVariableOem (EnvVar,RootName);
  507. setCF(0);
  508. return;
  509. }
  510. if (EnvVarLen > MAXIMUM_VDM_CURRENT_DIR+3) {
  511. setCF(1);
  512. setAX(0);
  513. }
  514. else {
  515. setCF(0);
  516. }
  517. return;
  518. }
  519. /* cmdSetInfo - Set the address of SCS_ToSync variable in DOSDATA.
  520. * This variable is set whenever SCS dispatches a new
  521. * command to command.com. Setting of this variable
  522. * indicates to dos to validate all the CDS structures
  523. * for local drives.
  524. *
  525. *
  526. * Entry - Client (DS:DX) - pointer to SCSINFO.
  527. *
  528. * EXIT - None
  529. */
  530. VOID cmdSetInfo (VOID)
  531. {
  532. pSCSInfo = (PSCSINFO) GetVDMAddr (getDS(),getDX());
  533. pSCS_ToSync = (PCHAR) &pSCSInfo->SCS_ToSync;
  534. pIsDosBinary = (BYTE *) GetVDMAddr(getDS(), getBX());
  535. pFDAccess = (WORD *) GetVDMAddr(getDS(), getCX());
  536. return;
  537. }
  538. VOID cmdSetDirectories (PCHAR lpszzEnv, VDMINFO * pVdmInfo)
  539. {
  540. LPSTR lpszVal;
  541. CHAR ch, chDrive, achEnvDrive[] = "=?:";
  542. ch = pVdmInfo->CurDrive + 'A';
  543. if (pVdmInfo->CurDirectoryLen != 0){
  544. SetCurrentDirectory(pVdmInfo->CurDirectory);
  545. achEnvDrive[1] = ch;
  546. SetEnvironmentVariable(achEnvDrive, pVdmInfo->CurDirectory);
  547. }
  548. if (lpszzEnv) {
  549. while(*lpszzEnv) {
  550. if(*lpszzEnv == '=' &&
  551. (chDrive = (CHAR)toupper(*(lpszzEnv+1))) >= 'A' &&
  552. chDrive <= 'Z' &&
  553. (*(PCHAR)((ULONG)lpszzEnv+2) == ':') &&
  554. chDrive != ch) {
  555. lpszVal = (PCHAR)((ULONG)lpszzEnv + 4);
  556. achEnvDrive[1] = chDrive;
  557. SetEnvironmentVariable (achEnvDrive,lpszVal);
  558. }
  559. lpszzEnv = strchr(lpszzEnv,'\0');
  560. lpszzEnv++;
  561. }
  562. }
  563. }
  564. static BOOL fConOutput = FALSE;
  565. VOID cmdComSpec (VOID)
  566. {
  567. LPSTR lpszCS;
  568. if(IsFirstCall == FALSE)
  569. return;
  570. lpszCS = (LPVOID) GetVDMAddr ((USHORT)getDS(),(USHORT)getDX());
  571. strcpy(lpszComSpec,"COMSPEC=");
  572. strcpy(lpszComSpec+8,lpszCS);
  573. cbComSpec = strlen(lpszComSpec) +1;
  574. setAL((BYTE)(!fConOutput || VDMForWOW));
  575. return;
  576. }
  577. VOID cmdSaveWorld (VOID)
  578. {
  579. #ifdef CHECK_IT_LATER
  580. SAVEWORLD VDMState;
  581. HANDLE hFile;
  582. PCHAR pVDM;
  583. DWORD dwBytesWritten;
  584. if(IsFirstVDMInSystem) {
  585. IsFirstVDMInSystem = FALSE;
  586. if ((hFile = CreateFile("c:\\nt\\bin86\\savevdm.wld",
  587. GENERIC_WRITE,
  588. 0,
  589. NULL,
  590. OPEN_ALWAYS,
  591. 0,
  592. NULL)) == (HANDLE)-1){
  593. SaveWorldCreated = FALSE;
  594. return;
  595. }
  596. VDMState.ax = getAX();
  597. VDMState.bx = getBX();
  598. VDMState.cx = getCX();
  599. VDMState.dx = getDX();
  600. VDMState.cs = getCS();
  601. VDMState.ss = getSS();
  602. VDMState.ds = getDS();
  603. VDMState.es = getES();
  604. VDMState.si = getSI();
  605. VDMState.di = getDI();
  606. VDMState.bp = getBP();
  607. VDMState.sp = getSP();
  608. VDMState.ip = getIP() + 1;
  609. VDMState.flag = 0;
  610. VDMState.ImageSize = 1024*1024;
  611. pVDM = (PVOID)GetVDMAddr(0,0);
  612. if (WriteFile (hFile,
  613. (LPVOID)&VDMState,
  614. (DWORD)sizeof(VDMState),
  615. &dwBytesWritten,
  616. NULL) == FALSE){
  617. SaveWorldCreated = FALSE;
  618. CloseHandle(hFile);
  619. return;
  620. }
  621. if (WriteFile (hFile,
  622. (LPVOID)pVDM,
  623. (DWORD)VDMState.ImageSize,
  624. &dwBytesWritten,
  625. NULL) == FALSE){
  626. SaveWorldCreated = FALSE;
  627. CloseHandle(hFile);
  628. return;
  629. }
  630. CloseHandle(hFile);
  631. }
  632. #endif
  633. return;
  634. }
  635. /* cmdInitConsole - Let Video VDD know that it can start console output
  636. * operations.
  637. *
  638. *
  639. * Entry - None
  640. *
  641. *
  642. * EXIT - None
  643. *
  644. */
  645. VOID cmdInitConsole (VOID)
  646. {
  647. if (fConOutput == FALSE) {
  648. fConOutput = TRUE;
  649. nt_init_event_thread ();
  650. }
  651. return;
  652. }
  653. /* cmdMapCodePage - Map the Win32 Code page to DOS code page
  654. */
  655. USHORT cmdMapCodePage (ULONG CodePage)
  656. {
  657. // Currently We understand US code page only
  658. if (CodePage == 1252)
  659. return 437;
  660. else
  661. return ((USHORT)CodePage);
  662. }
  663. /* GetWOWShortCutInfo - returns the startupinf.reserved field of
  664. * vdminfo for the first wow task.
  665. *
  666. * Input - Bufsize - pointer to bufsize
  667. * Buf - buffer where the info is returned
  668. *
  669. * Output
  670. * Success - returns TRUE, BufSize has the length of buffer filled in
  671. * Failure - returns FALSE, Bufsize has the required buffer size.
  672. */
  673. BOOL GetWOWShortCutInfo (PULONG Bufsize, PVOID Buf)
  674. {
  675. if (*Bufsize >= VDMInfo.ReservedLen) {
  676. *Bufsize = VDMInfo.ReservedLen;
  677. if (Bufsize)
  678. strncpy (Buf, VDMInfo.Reserved, VDMInfo.ReservedLen);
  679. return TRUE;
  680. }
  681. else {
  682. *Bufsize = VDMInfo.ReservedLen;
  683. return FALSE;
  684. }
  685. }
  686. VOID cmdUpdateCurrentDirectories(BYTE CurDrive)
  687. {
  688. DWORD cchRemain, cchCurDir;
  689. CHAR *lpszCurDir;
  690. BYTE Drive;
  691. DWORD DriveType;
  692. CHAR achName[] = "=?:";
  693. CHAR RootName[] = "?:\\";
  694. // allocate new space for the new current directories
  695. lpszzCurrentDirectories = (CHAR*) malloc(MAX_PATH);
  696. cchCurrentDirectories = 0;
  697. cchRemain = MAX_PATH;
  698. lpszCurDir = lpszzCurrentDirectories;
  699. if (lpszCurDir != NULL) {
  700. Drive = 0;
  701. // current directory is the first entry
  702. achName[1] = CurDrive + 'A';
  703. cchCurrentDirectories = GetEnvironmentVariable(
  704. achName,
  705. lpszCurDir,
  706. cchRemain
  707. );
  708. if (cchCurrentDirectories == 0 || cchCurrentDirectories > MAX_PATH) {
  709. free(lpszzCurrentDirectories);
  710. lpszzCurrentDirectories = NULL;
  711. cchCurrentDirectories = 0;
  712. return;
  713. }
  714. cchRemain -= ++cchCurrentDirectories;
  715. // we got current directory already. Keep the drive number
  716. lpszCurDir += cchCurrentDirectories;
  717. while (Drive < 26) {
  718. // ignore invalid drives and current drive
  719. if (Drive != CurDrive) {
  720. DriveType = demGetPhysicalDriveType(Drive);
  721. if (DriveType == DRIVE_UNKNOWN) {
  722. RootName[0] = (CHAR)('A' + Drive);
  723. DriveType = GetDriveTypeOem(RootName);
  724. }
  725. if (DriveType != DRIVE_UNKNOWN &&
  726. DriveType != DRIVE_NO_ROOT_DIR )
  727. {
  728. achName[1] = Drive + 'A';
  729. cchCurDir = GetEnvironmentVariable(
  730. achName,
  731. lpszCurDir,
  732. cchRemain
  733. );
  734. if(cchCurDir > cchRemain) {
  735. lpszCurDir = (CHAR *)realloc(lpszzCurrentDirectories,
  736. cchRemain + MAX_PATH + cchCurrentDirectories
  737. );
  738. if (lpszCurDir == NULL) {
  739. free(lpszzCurrentDirectories);
  740. lpszzCurrentDirectories = NULL;
  741. cchCurrentDirectories = 0;
  742. return;
  743. }
  744. lpszzCurrentDirectories = lpszCurDir;
  745. lpszCurDir += cchCurrentDirectories;
  746. cchRemain += MAX_PATH;
  747. cchCurDir = GetEnvironmentVariable(
  748. achName,
  749. lpszCurDir,
  750. cchRemain
  751. );
  752. }
  753. if (cchCurDir != 0) {
  754. // GetEnvironmentVariable doesn't count the NULL char
  755. lpszCurDir += ++cchCurDir;
  756. cchRemain -= cchCurDir;
  757. cchCurrentDirectories += cchCurDir;
  758. }
  759. }
  760. }
  761. // next drive
  762. Drive++;
  763. }
  764. lpszCurDir = lpszzCurrentDirectories;
  765. // need space for the ending NULL and shrink the space if necessary
  766. lpszzCurrentDirectories = (CHAR *) realloc(lpszCurDir, cchCurrentDirectories + 1);
  767. if (lpszzCurrentDirectories != NULL && cchCurrentDirectories != 0){
  768. lpszzCurrentDirectories[cchCurrentDirectories++] = '\0';
  769. SetVDMCurrentDirectories(cchCurrentDirectories, lpszzCurrentDirectories);
  770. free(lpszzCurrentDirectories);
  771. lpszzCurrentDirectories = NULL;
  772. cchCurrentDirectories = 0;
  773. }
  774. else {
  775. free(lpszCurDir);
  776. cchCurrentDirectories = 0;
  777. }
  778. }
  779. }
  780. /* This SVC function tells command.com, if the VDM was started without an
  781. * existing console. If so, on finding a TSR, command.com will return
  782. * back to GetNextVDMCommand, rather than putting its own popup.
  783. *
  784. * Entry - None
  785. *
  786. * Exit - Client (AL) = 0 if started with an existing console
  787. * Client (AL) = 1 if started with new console
  788. */
  789. VOID cmdGetStartInfo (VOID)
  790. {
  791. setAL((BYTE) (DosSessionId ? 1 : 0));
  792. return;
  793. }
  794. #ifdef DBCS // this should go to US build also
  795. /* This SVC function changes the window title. This function get called
  796. * from command.com when TSRs are installed and scs_cmdprompt is off
  797. * (command.com does its prompt).
  798. *
  799. * Entry - Client (AL) = 0, restore bare title
  800. * Client (AL) != 1, set new program title,
  801. * DS:SI point to a CRLF terminated program name
  802. *
  803. * Exit - none
  804. *
  805. */
  806. VOID cmdSetWinTitle(VOID)
  807. {
  808. static CHAR achCommandPrompt[64] = {'\0'};
  809. CHAR achBuf[256], *pch, *pch1;
  810. if (achCommandPrompt[0] == '\0') {
  811. if (!LoadString(GetModuleHandle(NULL),
  812. IDS_PROMPT,
  813. achCommandPrompt,
  814. 64
  815. ))
  816. strcpy(achCommandPrompt, "Command Prompt");
  817. }
  818. if (getAL() == 0)
  819. SetConsoleTitleA(achCommandPrompt);
  820. else {
  821. pch = (CHAR *)GetVDMAddr(getDS(), getSI());
  822. pch1 = strchr(pch, 0x0d);
  823. if (pch1 == NULL)
  824. SetConsoleTitleA(achCommandPrompt);
  825. else {
  826. *pch1 = '\0';
  827. strcpy(achBuf, achCommandPrompt);
  828. strcat(achBuf, " - ");
  829. strcat(achBuf, pch);
  830. *pch1 = 0x0d;
  831. SetConsoleTitleA(achBuf);
  832. }
  833. }
  834. }
  835. #endif // DBCS
  836. #if defined(NEC_98)
  837. /* cmdGetCursorPos -
  838. *
  839. *
  840. * Entry - None
  841. *
  842. *
  843. * EXIT - DX cursor position
  844. *
  845. */
  846. VOID cmdGetCursorPos(VOID)
  847. {
  848. setDX( (USHORT)(nt_get_cursor_pos()));
  849. return;
  850. }
  851. #endif // NEC_98