Windows NT 4.0 source code leak
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.

3275 lines
88 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. vdm.c
  5. Abstract:
  6. This module implements Win32 APIs for VDMs
  7. Author:
  8. Sudeepb Bharati (sudeepb) 04-Sep-1991
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #pragma hdrstop
  13. #include "ntdbg.h"
  14. BOOL
  15. APIENTRY
  16. GetBinaryTypeA(
  17. IN LPCSTR lpApplicationName,
  18. OUT LPDWORD lpBinaryType
  19. )
  20. /*++
  21. Routine Description: ANSI version of GetBinaryTypeW.
  22. This API returns the binary type of lpApplicationName.
  23. Arguments:
  24. lpApplicationName - Full pathname of the binary
  25. lpBinaryType - pointer where binary type will be returned.
  26. Return Value:
  27. TRUE - if SUCCESS; lpBinaryType has following
  28. SCS_32BIT_BINARY - Win32 Binary (NT or Chicago)
  29. SCS_DOS_BINARY - DOS Binary
  30. SCS_WOW_BINARY - Windows 3.X Binary
  31. SCS_PIF_BINARY - PIF file
  32. SCS_POSIX_BINARY - POSIX Binary
  33. SCS_OS216_BINARY - OS/2 Binary
  34. FALSE - if file not found or of unknown type. More info with GetLastError
  35. --*/
  36. {
  37. NTSTATUS Status;
  38. PUNICODE_STRING CommandLine;
  39. ANSI_STRING AnsiString;
  40. UNICODE_STRING DynamicCommandLine;
  41. BOOLEAN bReturn = FALSE;
  42. CommandLine = &NtCurrentTeb()->StaticUnicodeString;
  43. RtlInitAnsiString(&AnsiString,lpApplicationName);
  44. if ( (ULONG)AnsiString.Length<<1 < (ULONG)NtCurrentTeb()->StaticUnicodeString.MaximumLength ) {
  45. DynamicCommandLine.Buffer = NULL;
  46. Status = RtlAnsiStringToUnicodeString(CommandLine,&AnsiString,FALSE);
  47. if ( !NT_SUCCESS(Status) ) {
  48. BaseSetLastNTError(Status);
  49. return FALSE;
  50. }
  51. }
  52. else {
  53. Status = RtlAnsiStringToUnicodeString(&DynamicCommandLine,&AnsiString,TRUE);
  54. if ( !NT_SUCCESS(Status) ) {
  55. BaseSetLastNTError(Status);
  56. return FALSE;
  57. }
  58. }
  59. bReturn = GetBinaryTypeW(
  60. DynamicCommandLine.Buffer ? DynamicCommandLine.Buffer : CommandLine->Buffer,
  61. lpBinaryType);
  62. if (DynamicCommandLine.Buffer) {
  63. RtlFreeUnicodeString(&DynamicCommandLine);
  64. DynamicCommandLine.Buffer = NULL;
  65. }
  66. return(bReturn);
  67. }
  68. BOOL
  69. WINAPI
  70. GetBinaryTypeW(
  71. IN LPCWSTR lpApplicationName,
  72. OUT LPDWORD lpBinaryType
  73. )
  74. /*++
  75. Routine Description: Unicode version.
  76. This API returns the binary type of lpApplicationName.
  77. Arguments:
  78. lpApplicationName - Full pathname of the binary
  79. lpBinaryType - pointer where binary type will be returned.
  80. Return Value:
  81. TRUE - if SUCCESS; lpBinaryType has following
  82. SCS_32BIT_BINARY - Win32 Binary (NT or Chicago)
  83. SCS_DOS_BINARY - DOS Binary
  84. SCS_WOW_BINARY - Windows 3.X Binary
  85. SCS_PIF_BINARY - PIF file
  86. SCS_POSIX_BINARY - POSIX Binary
  87. SCS_OS216_BINARY - OS/2 Binary
  88. FALSE - if file not found or of unknown type. More info with GetLastError
  89. --*/
  90. {
  91. NTSTATUS Status;
  92. UNICODE_STRING PathName;
  93. RTL_RELATIVE_NAME RelativeName;
  94. BOOLEAN TranslationStatus;
  95. OBJECT_ATTRIBUTES Obja;
  96. PVOID FreeBuffer = NULL;
  97. HANDLE FileHandle, SectionHandle=NULL;
  98. IO_STATUS_BLOCK IoStatusBlock;
  99. LONG fBinaryType = SCS_32BIT_BINARY;
  100. BOOLEAN bReturn = FALSE;
  101. SECTION_IMAGE_INFORMATION ImageInformation;
  102. try {
  103. //
  104. // Translate to an NT name.
  105. //
  106. TranslationStatus = RtlDosPathNameToNtPathName_U(
  107. // DynamicCommandLine.Buffer ? DynamicCommandLine.Buffer : CommandLine->Buffer,
  108. lpApplicationName,
  109. &PathName,
  110. NULL,
  111. &RelativeName
  112. );
  113. if ( !TranslationStatus ) {
  114. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  115. goto GBTtryexit;
  116. }
  117. FreeBuffer = PathName.Buffer;
  118. if ( RelativeName.RelativeName.Length ) {
  119. PathName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  120. }
  121. else {
  122. RelativeName.ContainingDirectory = NULL;
  123. }
  124. InitializeObjectAttributes(
  125. &Obja,
  126. &PathName,
  127. OBJ_CASE_INSENSITIVE,
  128. RelativeName.ContainingDirectory,
  129. NULL
  130. );
  131. //
  132. // Open the file for execute access
  133. //
  134. Status = NtOpenFile(
  135. &FileHandle,
  136. SYNCHRONIZE | FILE_EXECUTE,
  137. &Obja,
  138. &IoStatusBlock,
  139. FILE_SHARE_READ | FILE_SHARE_DELETE,
  140. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  141. );
  142. if (!NT_SUCCESS(Status) ) {
  143. BaseSetLastNTError(Status);
  144. goto GBTtryexit;
  145. }
  146. //
  147. // Create a section object backed by the file
  148. //
  149. Status = NtCreateSection(
  150. &SectionHandle,
  151. SECTION_ALL_ACCESS,
  152. NULL,
  153. NULL,
  154. PAGE_EXECUTE,
  155. SEC_IMAGE,
  156. FileHandle
  157. );
  158. NtClose(FileHandle);
  159. if (!NT_SUCCESS(Status) ) {
  160. SectionHandle = NULL;
  161. switch (Status) {
  162. case STATUS_INVALID_IMAGE_NE_FORMAT:
  163. #ifdef i386
  164. fBinaryType = SCS_OS216_BINARY;
  165. break;
  166. #endif
  167. case STATUS_INVALID_IMAGE_PROTECT:
  168. fBinaryType = SCS_DOS_BINARY;
  169. break;
  170. case STATUS_INVALID_IMAGE_WIN_16:
  171. fBinaryType = SCS_WOW_BINARY;
  172. break;
  173. case STATUS_INVALID_IMAGE_NOT_MZ:
  174. fBinaryType = BaseIsDosApplication(&PathName, Status);
  175. if (!fBinaryType){
  176. BaseSetLastNTError(Status);
  177. goto GBTtryexit;
  178. }
  179. fBinaryType = (fBinaryType == BINARY_TYPE_DOS_PIF) ?
  180. SCS_PIF_BINARY : SCS_DOS_BINARY;
  181. break;
  182. default:
  183. BaseSetLastNTError(Status);
  184. goto GBTtryexit;
  185. }
  186. }
  187. else {
  188. //
  189. // Query the section
  190. //
  191. Status = NtQuerySection(
  192. SectionHandle,
  193. SectionImageInformation,
  194. &ImageInformation,
  195. sizeof( ImageInformation ),
  196. NULL
  197. );
  198. if (!NT_SUCCESS( Status )) {
  199. BaseSetLastNTError(Status);
  200. goto GBTtryexit;
  201. }
  202. if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL) {
  203. SetLastError(ERROR_BAD_EXE_FORMAT);
  204. goto GBTtryexit;
  205. }
  206. if (ImageInformation.Machine !=
  207. RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress)->FileHeader.Machine) {
  208. #ifdef MIPS
  209. if ( ImageInformation.Machine == IMAGE_FILE_MACHINE_R3000 ||
  210. ImageInformation.Machine == IMAGE_FILE_MACHINE_R4000 ) {
  211. ;
  212. }
  213. else {
  214. SetLastError(ERROR_BAD_EXE_FORMAT);
  215. goto GBTtryexit;
  216. }
  217. #else
  218. SetLastError(ERROR_BAD_EXE_FORMAT);
  219. goto GBTtryexit;
  220. #endif // MIPS
  221. }
  222. if ( ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI &&
  223. ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI ) {
  224. if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_POSIX_CUI ) {
  225. fBinaryType = SCS_POSIX_BINARY;
  226. }
  227. }
  228. }
  229. *lpBinaryType = fBinaryType;
  230. bReturn = TRUE;
  231. GBTtryexit:;
  232. }
  233. finally {
  234. if (SectionHandle)
  235. NtClose(SectionHandle);
  236. if (FreeBuffer)
  237. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  238. }
  239. return bReturn;
  240. }
  241. VOID
  242. APIENTRY
  243. VDMOperationStarted
  244. (
  245. BOOL IsWowCaller
  246. )
  247. /*++
  248. Routine Description:
  249. This routine is used by MVDM to tell base that it has hooked
  250. ctrl-c handler with console. If the cmd window is killed
  251. before VDM could hook ctrl-c, then we wont get a chance to
  252. cleanup our data structures. The absence of this call tells
  253. base that it has to clean up the resources next time a
  254. call is made to create a VDM.
  255. Arguments:
  256. IsWowCaller - TRUE if the caller is WOWVDM
  257. Return Value:
  258. None
  259. --*/
  260. {
  261. BaseUpdateVDMEntry(UPDATE_VDM_HOOKED_CTRLC,
  262. NULL,
  263. 0,
  264. IsWowCaller);
  265. return;
  266. }
  267. BOOL
  268. APIENTRY
  269. GetNextVDMCommand(
  270. PVDMINFO lpVDMInfo
  271. )
  272. /*++
  273. Routine Description:
  274. This routine is used by MVDM to get a new command to execute. The
  275. VDM is blocked untill a DOS/WOW binary is encountered.
  276. Arguments:
  277. lpVDMInfo - pointer to VDMINFO where new DOS command and other
  278. enviornment information is returned.
  279. if lpVDMInfo is NULL, then the caller is
  280. asking whether its the first VDM in the system.
  281. Return Value:
  282. TRUE - The operation was successful. lpVDMInfo is filled in.
  283. FALSE/NULL - The operation failed.
  284. --*/
  285. {
  286. NTSTATUS Status;
  287. BASE_API_MSG m;
  288. PBASE_GET_NEXT_VDM_COMMAND_MSG a = (PBASE_GET_NEXT_VDM_COMMAND_MSG)&m.u.GetNextVDMCommand;
  289. PBASE_EXIT_VDM_MSG c= (PBASE_EXIT_VDM_MSG)&m.u.ExitVDM;
  290. PBASE_IS_FIRST_VDM_MSG d= (PBASE_IS_FIRST_VDM_MSG)&m.u.IsFirstVDM;
  291. PBASE_SET_REENTER_COUNT_MSG e = (PBASE_SET_REENTER_COUNT_MSG)&m.u.SetReenterCount;
  292. PCSR_CAPTURE_HEADER CaptureBuffer;
  293. ULONG Len,nPointers;
  294. USHORT VDMStateSave;
  295. // Special case to query the first VDM In the system.
  296. if(lpVDMInfo == NULL){
  297. Status = CsrClientCallServer(
  298. (PCSR_API_MSG)&m,
  299. NULL,
  300. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  301. BasepIsFirstVDM
  302. ),
  303. sizeof( *d )
  304. );
  305. if (NT_SUCCESS(Status)) {
  306. return(d->FirstVDM);
  307. }
  308. else {
  309. BaseSetLastNTError(Status);
  310. return FALSE;
  311. }
  312. }
  313. // Special case to increment/decrement the re-enterancy count
  314. if (lpVDMInfo->VDMState == INCREMENT_REENTER_COUNT ||
  315. lpVDMInfo->VDMState == DECREMENT_REENTER_COUNT) {
  316. e->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  317. e->fIncDec = lpVDMInfo->VDMState;
  318. Status = CsrClientCallServer(
  319. (PCSR_API_MSG)&m,
  320. NULL,
  321. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  322. BasepSetReenterCount
  323. ),
  324. sizeof( *e )
  325. );
  326. if (NT_SUCCESS(Status)) {
  327. return TRUE;
  328. }
  329. else {
  330. BaseSetLastNTError(Status);
  331. return FALSE;
  332. }
  333. }
  334. VDMStateSave = lpVDMInfo->VDMState;
  335. if(VDMStateSave & ASKING_FOR_WOW_BINARY)
  336. a->ConsoleHandle = (HANDLE)-1;
  337. else
  338. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  339. if (lpVDMInfo->VDMState & ASKING_FOR_PIF)
  340. a->iTask = lpVDMInfo->iTask;
  341. a->AppLen = lpVDMInfo->AppLen;
  342. a->PifLen = lpVDMInfo->PifLen;
  343. a->CmdLen = lpVDMInfo->CmdSize;
  344. a->EnvLen = lpVDMInfo->EnviornmentSize;
  345. a->ExitCode = lpVDMInfo->ErrorCode;
  346. a->VDMState = VDMStateSave;
  347. a->WaitObjectForVDM = 0;
  348. a->DesktopLen = lpVDMInfo->DesktopLen;
  349. a->TitleLen = lpVDMInfo->TitleLen;
  350. a->ReservedLen = lpVDMInfo->ReservedLen;
  351. a->CurDirectoryLen = lpVDMInfo->CurDirectoryLen;
  352. // Find the total space for capture buffer
  353. // startup info
  354. Len = ROUND_UP(sizeof(STARTUPINFOA),4);
  355. nPointers = 1;
  356. if (lpVDMInfo->CmdSize) {
  357. Len += ROUND_UP(a->CmdLen,4);
  358. nPointers++;
  359. }
  360. if (lpVDMInfo->AppLen) {
  361. Len +=ROUND_UP(a->AppLen,4);
  362. nPointers++;
  363. }
  364. if (lpVDMInfo->PifLen) {
  365. Len +=ROUND_UP(a->PifLen,4);
  366. nPointers++;
  367. }
  368. if (lpVDMInfo->Enviornment) {
  369. nPointers++;
  370. Len+= (lpVDMInfo->EnviornmentSize) ?
  371. ROUND_UP(lpVDMInfo->EnviornmentSize, 4) : 4;
  372. }
  373. if (lpVDMInfo->CurDirectoryLen == 0)
  374. a->CurDirectory = NULL;
  375. else{
  376. Len += ROUND_UP(lpVDMInfo->CurDirectoryLen,4);
  377. nPointers++;
  378. }
  379. if (lpVDMInfo->DesktopLen == 0)
  380. a->Desktop = NULL;
  381. else {
  382. Len += ROUND_UP(lpVDMInfo->DesktopLen,4);
  383. nPointers++;
  384. }
  385. if (lpVDMInfo->TitleLen == 0)
  386. a->Title = NULL;
  387. else {
  388. Len += ROUND_UP(lpVDMInfo->TitleLen,4);
  389. nPointers++;
  390. }
  391. if (lpVDMInfo->ReservedLen == 0)
  392. a->Reserved = NULL;
  393. else {
  394. Len += ROUND_UP(lpVDMInfo->ReservedLen,4);
  395. nPointers++;
  396. }
  397. CaptureBuffer = CsrAllocateCaptureBuffer(nPointers, 0, Len);
  398. if (CaptureBuffer == NULL) {
  399. BaseSetLastNTError( STATUS_NO_MEMORY );
  400. return FALSE;
  401. }
  402. if (lpVDMInfo->CmdLine) {
  403. CsrAllocateMessagePointer( CaptureBuffer,
  404. lpVDMInfo->CmdSize,
  405. (PVOID *)&a->CmdLine
  406. );
  407. }
  408. else {
  409. a->CmdLine = NULL;
  410. }
  411. if (lpVDMInfo->AppLen) {
  412. CsrAllocateMessagePointer( CaptureBuffer,
  413. lpVDMInfo->AppLen,
  414. (PVOID *)&a->AppName
  415. );
  416. }
  417. else {
  418. a->AppName = NULL;
  419. }
  420. if (lpVDMInfo->PifLen) {
  421. CsrAllocateMessagePointer( CaptureBuffer,
  422. lpVDMInfo->PifLen,
  423. (PVOID *)&a->PifFile
  424. );
  425. }
  426. else {
  427. a->PifFile = NULL;
  428. }
  429. if (lpVDMInfo->EnviornmentSize) {
  430. CsrAllocateMessagePointer( CaptureBuffer,
  431. lpVDMInfo->EnviornmentSize,
  432. (PVOID *)&a->Env
  433. );
  434. }
  435. else {
  436. a->Env = NULL;
  437. }
  438. if (lpVDMInfo->CurDirectoryLen)
  439. CsrAllocateMessagePointer( CaptureBuffer,
  440. lpVDMInfo->CurDirectoryLen,
  441. (PVOID *)&a->CurDirectory
  442. );
  443. else
  444. a->CurDirectory = NULL;
  445. CsrAllocateMessagePointer( CaptureBuffer,
  446. sizeof(STARTUPINFOA),
  447. (PVOID *)&a->StartupInfo
  448. );
  449. if (lpVDMInfo->DesktopLen)
  450. CsrAllocateMessagePointer( CaptureBuffer,
  451. lpVDMInfo->DesktopLen,
  452. (PVOID *)&a->Desktop
  453. );
  454. else
  455. a->Desktop = NULL;
  456. if (lpVDMInfo->TitleLen)
  457. CsrAllocateMessagePointer( CaptureBuffer,
  458. lpVDMInfo->TitleLen,
  459. (PVOID *)&a->Title
  460. );
  461. else
  462. a->Title = NULL;
  463. if (lpVDMInfo->ReservedLen)
  464. CsrAllocateMessagePointer( CaptureBuffer,
  465. lpVDMInfo->ReservedLen,
  466. (PVOID *)&a->Reserved
  467. );
  468. else
  469. a->Reserved = NULL;
  470. retry:
  471. Status = CsrClientCallServer(
  472. (PCSR_API_MSG)&m,
  473. CaptureBuffer,
  474. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  475. BasepGetNextVDMCommand
  476. ),
  477. sizeof( *a )
  478. );
  479. if (a->WaitObjectForVDM) {
  480. Status = NtWaitForSingleObject(a->WaitObjectForVDM,FALSE,NULL);
  481. if (Status != STATUS_SUCCESS){
  482. BaseSetLastNTError(Status);
  483. return FALSE;
  484. }
  485. else {
  486. a->VDMState |= ASKING_FOR_SECOND_TIME;
  487. a->ExitCode = 0;
  488. goto retry;
  489. }
  490. }
  491. if (NT_SUCCESS(Status)) {
  492. Status = (NTSTATUS)m.ReturnValue;
  493. }
  494. if (!NT_SUCCESS( Status )) {
  495. if (Status == STATUS_INVALID_PARAMETER) {
  496. //This means one of the buffer size is less than required.
  497. lpVDMInfo->CmdSize = a->CmdLen;
  498. lpVDMInfo->AppLen = a->AppLen;
  499. lpVDMInfo->PifLen = a->PifLen;
  500. lpVDMInfo->EnviornmentSize = a->EnvLen;
  501. lpVDMInfo->CurDirectoryLen = a->CurDirectoryLen;
  502. lpVDMInfo->DesktopLen = a->DesktopLen;
  503. lpVDMInfo->TitleLen = a->TitleLen;
  504. lpVDMInfo->ReservedLen = a->ReservedLen;
  505. }
  506. else {
  507. lpVDMInfo->CmdSize = 0;
  508. lpVDMInfo->AppLen = 0;
  509. lpVDMInfo->PifLen = 0;
  510. lpVDMInfo->EnviornmentSize = 0;
  511. lpVDMInfo->CurDirectoryLen = 0;
  512. lpVDMInfo->DesktopLen = 0;
  513. lpVDMInfo->TitleLen = 0;
  514. lpVDMInfo->ReservedLen = 0;
  515. }
  516. CsrFreeCaptureBuffer( CaptureBuffer );
  517. BaseSetLastNTError(Status);
  518. return FALSE;
  519. }
  520. try {
  521. if (lpVDMInfo->CmdSize)
  522. RtlMoveMemory(lpVDMInfo->CmdLine,
  523. a->CmdLine,
  524. a->CmdLen);
  525. if (lpVDMInfo->AppLen)
  526. RtlMoveMemory(lpVDMInfo->AppName,
  527. a->AppName,
  528. a->AppLen);
  529. if (lpVDMInfo->PifLen)
  530. RtlMoveMemory(lpVDMInfo->PifFile,
  531. a->PifFile,
  532. a->PifLen);
  533. if (lpVDMInfo->Enviornment)
  534. RtlMoveMemory(lpVDMInfo->Enviornment,
  535. a->Env,
  536. a->EnvLen);
  537. if (lpVDMInfo->CurDirectoryLen)
  538. RtlMoveMemory(lpVDMInfo->CurDirectory,
  539. a->CurDirectory,
  540. a->CurDirectoryLen);
  541. if (a->VDMState & STARTUP_INFO_RETURNED)
  542. RtlMoveMemory(&lpVDMInfo->StartupInfo,
  543. a->StartupInfo,
  544. sizeof(STARTUPINFOA));
  545. if (lpVDMInfo->DesktopLen){
  546. RtlMoveMemory(lpVDMInfo->Desktop,
  547. a->Desktop,
  548. a->DesktopLen);
  549. lpVDMInfo->StartupInfo.lpDesktop = lpVDMInfo->Desktop;
  550. }
  551. if (lpVDMInfo->TitleLen){
  552. RtlMoveMemory(lpVDMInfo->Title,
  553. a->Title,
  554. a->TitleLen);
  555. lpVDMInfo->StartupInfo.lpTitle = lpVDMInfo->Title;
  556. }
  557. if (lpVDMInfo->ReservedLen){
  558. RtlMoveMemory(lpVDMInfo->Reserved,
  559. a->Reserved,
  560. a->ReservedLen);
  561. lpVDMInfo->StartupInfo.lpReserved = lpVDMInfo->Reserved;
  562. }
  563. lpVDMInfo->CmdSize = a->CmdLen;
  564. lpVDMInfo->AppLen = a->AppLen;
  565. lpVDMInfo->PifLen = a->PifLen;
  566. lpVDMInfo->EnviornmentSize = a->EnvLen;
  567. if (a->VDMState & STARTUP_INFO_RETURNED)
  568. lpVDMInfo->VDMState = STARTUP_INFO_RETURNED;
  569. else
  570. lpVDMInfo->VDMState = 0;
  571. lpVDMInfo->CurDrive = a->CurrentDrive;
  572. lpVDMInfo->StdIn = a->StdIn;
  573. lpVDMInfo->StdOut = a->StdOut;
  574. lpVDMInfo->StdErr = a->StdErr;
  575. lpVDMInfo->iTask = a->iTask;
  576. lpVDMInfo->CodePage = a->CodePage;
  577. lpVDMInfo->CurDirectoryLen = a->CurDirectoryLen;
  578. lpVDMInfo->DesktopLen = a->DesktopLen;
  579. lpVDMInfo->TitleLen = a->TitleLen;
  580. lpVDMInfo->ReservedLen = a->ReservedLen;
  581. lpVDMInfo->dwCreationFlags = a->dwCreationFlags;
  582. lpVDMInfo->fComingFromBat = a->fComingFromBat;
  583. CsrFreeCaptureBuffer( CaptureBuffer );
  584. return TRUE;
  585. }
  586. except ( EXCEPTION_EXECUTE_HANDLER ) {
  587. BaseSetLastNTError(GetExceptionCode());
  588. CsrFreeCaptureBuffer( CaptureBuffer );
  589. return FALSE;
  590. }
  591. }
  592. VOID
  593. APIENTRY
  594. ExitVDM(
  595. BOOL IsWowCaller,
  596. ULONG iWowTask
  597. )
  598. /*++
  599. Routine Description:
  600. This routine is used by MVDM to exit.
  601. Arguments:
  602. IsWowCaller - TRUE if the caller is WOWVDM.
  603. FALSE if the caller is DOSVDM
  604. iWowTask - if IsWowCaller == FALSE then Dont Care
  605. - if IsWowCaller == TRUE && iWowTask != -1 kill iWowTask task
  606. - if IsWowCaller == TRUE && iWowTask == -1 kill all wow task
  607. Return Value:
  608. None
  609. --*/
  610. {
  611. NTSTATUS Status;
  612. BASE_API_MSG m;
  613. PBASE_EXIT_VDM_MSG c= (PBASE_EXIT_VDM_MSG)&m.u.ExitVDM;
  614. if(IsWowCaller){
  615. c->ConsoleHandle = (HANDLE)-1;
  616. c->iWowTask = iWowTask;
  617. }
  618. else {
  619. c->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  620. }
  621. c->WaitObjectForVDM =0;
  622. Status = CsrClientCallServer(
  623. (PCSR_API_MSG)&m,
  624. NULL,
  625. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  626. BasepExitVDM
  627. ),
  628. sizeof( *c )
  629. );
  630. if (NT_SUCCESS(Status) && c->WaitObjectForVDM) {
  631. NtClose (c->WaitObjectForVDM);
  632. }
  633. return;
  634. }
  635. /*++
  636. Routine Description:
  637. Set new VDM current directories
  638. Arguments:
  639. cchCurDir - length of buffer in bytes
  640. lpszCurDir - buffer to return the current director of NTVDM
  641. Return Value:
  642. TRUE if function succeed
  643. FALSE if function failed, GetLastError() has the error code
  644. --*/
  645. BOOL
  646. APIENTRY
  647. SetVDMCurrentDirectories(
  648. IN ULONG cchCurDirs,
  649. IN LPSTR lpszzCurDirs
  650. )
  651. {
  652. NTSTATUS Status;
  653. PCSR_CAPTURE_HEADER CaptureBuffer;
  654. BASE_API_MSG m;
  655. PBASE_GET_SET_VDM_CUR_DIRS_MSG a = (PBASE_GET_SET_VDM_CUR_DIRS_MSG)&m.u.GetSetVDMCurDirs;
  656. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  657. // caller must have a valid console(WOW will fail)
  658. if (a->ConsoleHandle == (HANDLE) -1) {
  659. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  660. return FALSE;
  661. }
  662. if (cchCurDirs && lpszzCurDirs) {
  663. // get capture buffer, one pointer in the message
  664. CaptureBuffer = CsrAllocateCaptureBuffer(1, 0, cchCurDirs);
  665. if (CaptureBuffer == NULL) {
  666. BaseSetLastNTError( STATUS_NO_MEMORY );
  667. return FALSE;
  668. }
  669. CsrAllocateMessagePointer( CaptureBuffer,
  670. cchCurDirs,
  671. (PVOID *)&a->lpszzCurDirs
  672. );
  673. a->cchCurDirs = cchCurDirs;
  674. try {
  675. RtlMoveMemory(a->lpszzCurDirs, lpszzCurDirs, cchCurDirs);
  676. }
  677. except (EXCEPTION_EXECUTE_HANDLER) {
  678. BaseSetLastNTError(GetExceptionCode());
  679. CsrFreeCaptureBuffer(CaptureBuffer);
  680. return FALSE;
  681. }
  682. Status = CsrClientCallServer(
  683. (PCSR_API_MSG)&m,
  684. CaptureBuffer,
  685. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  686. BasepSetVDMCurDirs
  687. ),
  688. sizeof( *a )
  689. );
  690. CsrFreeCaptureBuffer(CaptureBuffer);
  691. if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  692. BaseSetLastNTError(Status);
  693. return FALSE;
  694. }
  695. }
  696. return TRUE;
  697. }
  698. /*++
  699. Routine Description:
  700. To return current directory of NTVDM.
  701. This allows the parent process(CMD.EXE in most cases) to keep track the
  702. current directory after each VDM execution.
  703. NOTE: this function doesn't apply to wow
  704. Arguments:
  705. cchCurDir - length of buffer in bytes
  706. lpszCurDir - buffer to return the current director of NTVDM
  707. Note: We don't require the process id to the running VDM because
  708. current directories are global to every VDMs under a single NTVDM
  709. control -- each console handle has its own current directories
  710. Return Value:
  711. ULONG - (1). number of bytes written to the given buffer if succeed
  712. (2). lentgh of the current directory including NULL
  713. if the provided buffer is not large enough
  714. (3). 0 then GetLastError() has the error code
  715. --*/
  716. ULONG
  717. APIENTRY
  718. GetVDMCurrentDirectories(
  719. IN ULONG cchCurDirs,
  720. IN LPSTR lpszzCurDirs
  721. )
  722. {
  723. NTSTATUS Status;
  724. PCSR_CAPTURE_HEADER CaptureBuffer;
  725. BASE_API_MSG m;
  726. PBASE_GET_SET_VDM_CUR_DIRS_MSG a = (PBASE_GET_SET_VDM_CUR_DIRS_MSG)&m.u.GetSetVDMCurDirs;
  727. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  728. if (a->ConsoleHandle == (HANDLE) -1) {
  729. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  730. return 0L;
  731. }
  732. if (cchCurDirs && lpszzCurDirs) {
  733. CaptureBuffer = CsrAllocateCaptureBuffer(1, 0, cchCurDirs);
  734. if (CaptureBuffer == NULL) {
  735. BaseSetLastNTError( STATUS_NO_MEMORY );
  736. return FALSE;
  737. }
  738. CsrAllocateMessagePointer( CaptureBuffer,
  739. cchCurDirs,
  740. (PVOID *)&a->lpszzCurDirs
  741. );
  742. a->cchCurDirs = cchCurDirs;
  743. }
  744. else {
  745. a->cchCurDirs = 0;
  746. a->lpszzCurDirs = NULL;
  747. CaptureBuffer = NULL;
  748. }
  749. m.ReturnValue = 0xffffffff;
  750. Status = CsrClientCallServer(
  751. (PCSR_API_MSG)&m,
  752. CaptureBuffer,
  753. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  754. BasepGetVDMCurDirs
  755. ),
  756. sizeof( *a )
  757. );
  758. if (m.ReturnValue == 0xffffffff) {
  759. a->cchCurDirs = 0;
  760. }
  761. if (NT_SUCCESS(Status)) {
  762. Status = m.ReturnValue;
  763. }
  764. if (NT_SUCCESS(Status)) {
  765. try {
  766. RtlMoveMemory(lpszzCurDirs, a->lpszzCurDirs, a->cchCurDirs);
  767. }
  768. except(EXCEPTION_EXECUTE_HANDLER) {
  769. Status = GetExceptionCode();
  770. a->cchCurDirs = 0;
  771. }
  772. }
  773. else {
  774. BaseSetLastNTError(Status);
  775. }
  776. if (CaptureBuffer) {
  777. CsrFreeCaptureBuffer(CaptureBuffer);
  778. }
  779. return a->cchCurDirs;
  780. }
  781. VOID
  782. APIENTRY
  783. CmdBatNotification(
  784. IN ULONG fBeginEnd
  785. )
  786. /*++
  787. Routine Description:
  788. This API lets base know about .bat processing from cmd. This is
  789. required by VDM, so that it can decided correctly when to put
  790. command.com prompt on TSRs. If the command came from .bat file
  791. then VDM should'nt put its prompt. This is important for
  792. ventura publisher and civilization apps.
  793. Arguments:
  794. fBeginEnd - CMD_BAT_OPERATION_STARTING -> .BAT processing is starting
  795. CMD_BAT_OPERATION_TERMINATING -> .BAT processing is ending
  796. Return Value:
  797. None
  798. --*/
  799. {
  800. BASE_API_MSG m;
  801. PBASE_BAT_NOTIFICATION_MSG a = (PBASE_BAT_NOTIFICATION_MSG)&m.u.BatNotification;
  802. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  803. if (a->ConsoleHandle == (HANDLE) -1)
  804. return;
  805. a->fBeginEnd = fBeginEnd;
  806. CsrClientCallServer((PCSR_API_MSG)&m,
  807. NULL,
  808. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  809. BasepBatNotification
  810. ),
  811. sizeof( *a )
  812. );
  813. return;
  814. }
  815. VOID
  816. APIENTRY
  817. RegisterWowExec(
  818. IN HANDLE hwndWowExec
  819. )
  820. /*++
  821. Routine Description:
  822. This API gives basesrv the window handle for the shared WowExec so
  823. it can send WM_WOWEXECSTARTAPP messages to WowExec. This
  824. saves having a thread in WOW dedicated to GetNextVDMCommand.
  825. Arguments:
  826. hwndWowExec - Win32 window handle for WowExec in shared WOW VDM.
  827. Separate WOW VDMs don't register their WowExec handle
  828. because they never get commands from base.
  829. Return Value:
  830. None.
  831. --*/
  832. {
  833. BASE_API_MSG m;
  834. PBASE_REGISTER_WOWEXEC_MSG a = &m.u.RegisterWowExec;
  835. a->hwndWowExec = hwndWowExec;
  836. CsrClientCallServer((PCSR_API_MSG)&m,
  837. NULL,
  838. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  839. BasepRegisterWowExec
  840. ),
  841. sizeof( *a )
  842. );
  843. return;
  844. }
  845. /*++
  846. Routine Description:
  847. This routine is used to close standard IO handles before returning to the
  848. caller
  849. Arguments:
  850. pVDMInfo - VDM Info record containing stdio handles
  851. Return Value:
  852. None
  853. --*/
  854. VOID
  855. BaseCloseStandardHandle(
  856. IN PVDMINFO pVDMInfo
  857. )
  858. {
  859. if (pVDMInfo->StdIn)
  860. NtClose (pVDMInfo->StdIn);
  861. if (pVDMInfo->StdOut)
  862. NtClose (pVDMInfo->StdOut);
  863. if (pVDMInfo->StdErr)
  864. NtClose (pVDMInfo->StdErr);
  865. pVDMInfo->StdIn = 0;
  866. pVDMInfo->StdOut = 0;
  867. pVDMInfo->StdErr = 0;
  868. }
  869. #ifdef OLD_CFG_BASED
  870. BOOL
  871. BaseGetVDMKeyword(
  872. PCHAR KeywordLine,
  873. PCONFIG_KEYWORD *pKeywordLine,
  874. PCHAR KeywordSize,
  875. PULONG VdmSize
  876. )
  877. {
  878. NTSTATUS Status;
  879. PCONFIG_FILE ConfigFile;
  880. PCONFIG_SECTION Section;
  881. STRING SectionName, KeywordName;
  882. PCONFIG_KEYWORD pKeywordSize;
  883. //
  884. // Retrieve the VDM configuration information from the config file
  885. //
  886. Status = RtlOpenConfigFile( NULL, &ConfigFile );
  887. if (!NT_SUCCESS( Status )) {
  888. return FALSE;
  889. }
  890. //
  891. // Find WOW section of config file
  892. //
  893. RtlInitString( &SectionName, "WOW" );
  894. Section = RtlLocateSectionConfigFile( ConfigFile, &SectionName );
  895. if (Section == NULL) {
  896. RtlCloseConfigFile( ConfigFile );
  897. return FALSE;
  898. }
  899. //
  900. // Get command line
  901. //
  902. RtlInitString( &KeywordName, KeywordLine );
  903. *pKeywordLine = RtlLocateKeywordConfigFile( Section, &KeywordName );
  904. if (*pKeywordLine == NULL) {
  905. RtlCloseConfigFile( ConfigFile );
  906. return FALSE;
  907. }
  908. //
  909. // Get Vdm size
  910. //
  911. RtlInitString( &KeywordName, KeywordSize );
  912. pKeywordSize = RtlLocateKeywordConfigFile( Section, &KeywordName );
  913. if (pKeywordSize == NULL) {
  914. *VdmSize = 1024L * 1024L * 16L;
  915. } else {
  916. Status = RtlCharToInteger( pKeywordSize->Value.Buffer, 0, VdmSize );
  917. if (!NT_SUCCESS( Status )) {
  918. *VdmSize = 1024L * 1024L * 16L;
  919. } else {
  920. *VdmSize *= 1024L * 1024L; // convert to MB
  921. }
  922. }
  923. return TRUE;
  924. }
  925. #endif
  926. BOOL
  927. BaseGetVDMKeyword(
  928. LPWSTR KeywordLine,
  929. LPSTR KeywordLineValue,
  930. LPDWORD KeywordLineSize,
  931. LPWSTR KeywordSize,
  932. LPDWORD VdmSize
  933. )
  934. {
  935. NTSTATUS NtStatus;
  936. UNICODE_STRING UnicodeString,UnicodeTemp;
  937. UNICODE_STRING KeyName;
  938. ANSI_STRING AnsiString;
  939. LPWSTR UnicodeBuffer,Temp;
  940. OBJECT_ATTRIBUTES ObjectAttributes;
  941. HANDLE hKey = NULL;
  942. PKEY_VALUE_FULL_INFORMATION pKeyValueInformation;
  943. //
  944. // Allocate Work buffer
  945. //
  946. UnicodeBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ), FULL_INFO_BUFFER_SIZE);
  947. if (!UnicodeBuffer) {
  948. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  949. return(FALSE);
  950. }
  951. // Open the WOW key
  952. RtlInitUnicodeString (&KeyName, WOW_ROOT);
  953. InitializeObjectAttributes(&ObjectAttributes,
  954. &KeyName,
  955. OBJ_CASE_INSENSITIVE,
  956. NULL,
  957. NULL
  958. );
  959. NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  960. if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  961. BaseSetLastNTError(NtStatus);
  962. return FALSE;
  963. }
  964. if (!GetVDMConfigValue(hKey,KeywordLine,UnicodeBuffer)) {
  965. NtClose (hKey);
  966. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  967. return(FALSE);
  968. }
  969. //
  970. // Now convert back to ANSI for the caller after doing all the substitution
  971. //
  972. pKeyValueInformation = (PVOID)UnicodeBuffer;
  973. Temp = (LPWSTR)((PBYTE) pKeyValueInformation + pKeyValueInformation->DataOffset);
  974. RtlInitUnicodeString( &UnicodeString, Temp );
  975. UnicodeTemp.Buffer = (LPWSTR)KeywordLineValue;
  976. UnicodeTemp.Length = 0;
  977. UnicodeTemp.MaximumLength = MAX_VDM_CFG_LINE;
  978. NtStatus = RtlExpandEnvironmentStrings_U (NULL,&UnicodeString, &UnicodeTemp, NULL);
  979. if (!NT_SUCCESS( NtStatus )){
  980. NtClose (hKey);
  981. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  982. return FALSE;
  983. }
  984. wcscpy(UnicodeString.Buffer,UnicodeTemp.Buffer);
  985. UnicodeString.Length = UnicodeTemp.Length;
  986. //
  987. // Set up an ANSI_STRING that points to the user's buffer
  988. //
  989. AnsiString.MaximumLength = (USHORT) *KeywordLineSize;
  990. AnsiString.Length = 0;
  991. AnsiString.Buffer = KeywordLineValue;
  992. RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
  993. *KeywordLineSize = AnsiString.Length;
  994. // Always set the VDMSize to 16Mb. (This is for reservation only)
  995. // Actual commit is done by SAS_INIT.
  996. *VdmSize = 16L; //default value is 16
  997. *VdmSize *= 1024L * 1024L; // convert From MB
  998. NtClose (hKey);
  999. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  1000. return(TRUE);
  1001. }
  1002. BOOL
  1003. GetVDMConfigValue(
  1004. HANDLE hKey,
  1005. LPWSTR Keyword,
  1006. LPWSTR UnicodeBuffer
  1007. )
  1008. {
  1009. NTSTATUS NtStatus;
  1010. UNICODE_STRING ValueName;
  1011. PKEY_VALUE_FULL_INFORMATION pKeyValueInformation = (PVOID) UnicodeBuffer;
  1012. ULONG ValueLength;
  1013. RtlInitUnicodeString(&ValueName, Keyword);
  1014. NtStatus = NtQueryValueKey(hKey,
  1015. &ValueName,
  1016. KeyValueFullInformation,
  1017. pKeyValueInformation,
  1018. FULL_INFO_BUFFER_SIZE,
  1019. &ValueLength);
  1020. if (NT_SUCCESS(NtStatus))
  1021. return TRUE;
  1022. else {
  1023. BaseSetLastNTError (NtStatus);
  1024. return FALSE;
  1025. }
  1026. }
  1027. BOOL
  1028. BaseCheckVDM(
  1029. IN ULONG BinaryType,
  1030. IN PCWCH lpApplicationName,
  1031. IN PCWCH lpCommandLine,
  1032. IN PCWCH lpCurrentDirectory,
  1033. IN ANSI_STRING *pAnsiStringEnv,
  1034. IN PBASE_API_MSG m,
  1035. IN OUT PULONG iTask,
  1036. IN DWORD dwCreationFlags,
  1037. LPSTARTUPINFOW lpStartupInfo
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. This routine calls the windows server to find out if the VDM for the
  1042. current session is already present. If so, a new process is'nt created
  1043. instead the DOS binary is dispatched to the existing VDM. Otherwise,
  1044. a new VDM process is created. This routine also passes the app name
  1045. and command line to the server in DOS int21/0ah style which is later
  1046. passed by the server to the VDM.
  1047. Arguments:
  1048. BinaryType - DOS/WOW binary
  1049. lpApplicationName -- pointer to the full path name of the executable.
  1050. lpCommandLine -- command line
  1051. lpCurrentDirectory - Current directory
  1052. lpEnvironment, - Envirinment strings
  1053. m - pointer to the base api message.
  1054. iTask - taskid for win16 apps, and no-console dos apps
  1055. dwCreationFlags - creation flags as passed to createprocess
  1056. lpStartupInfo =- pointer to startupinfo as passed to createprocess
  1057. Return Value:
  1058. OEM vs. ANSI:
  1059. The command line, Application Name, title are converted to OEM strings,
  1060. suitable for the VDM. All other strings are returned as ANSI.
  1061. TRUE -- Operation successful, VDM state and other relevant information
  1062. is in base api message.
  1063. FALSE -- Operation failed.
  1064. --*/
  1065. {
  1066. NTSTATUS Status;
  1067. PPEB Peb;
  1068. PBASE_CHECKVDM_MSG b= (PBASE_CHECKVDM_MSG)&m->u.CheckVDM;
  1069. PCSR_CAPTURE_HEADER CaptureBuffer;
  1070. ANSI_STRING AnsiStringCurrentDir,AnsiStringDesktop;
  1071. ANSI_STRING AnsiStringReserved, AnsiStringPif;
  1072. OEM_STRING OemStringCmd, OemStringAppName, OemStringTitle;
  1073. UNICODE_STRING UnicodeString;
  1074. PCHAR pch, pSlash, Buffer = NULL;
  1075. ULONG Len;
  1076. ULONG bufPointers;
  1077. LPWSTR wsBuffer;
  1078. LPWSTR wsAppName;
  1079. LPWSTR wsPifName;
  1080. LPWSTR wsCmdLine;
  1081. LPWSTR wsPif=(PWSTR)".\0p\0i\0f\0\0"; // L".pif"
  1082. LPWSTR wsSharedWowPif=L"wowexec.pif";
  1083. PWCHAR pwch;
  1084. BOOLEAN bNewConsole;
  1085. BOOLEAN bReturn = FALSE;
  1086. DWORD dw, dwTotal, Length;
  1087. WCHAR *pSrc, *pDot, *pTmp;
  1088. UNICODE_STRING * pUnicodeStringExtName;
  1089. WCHAR wchBuffer[MAX_PATH + 1];
  1090. ULONG BinarySubType;
  1091. LPWSTR lpAllocatedReserved = NULL;
  1092. DWORD HandleFlags;
  1093. // does a trivial test of the environment
  1094. if (!ARGUMENT_PRESENT(pAnsiStringEnv) ||
  1095. pAnsiStringEnv->Length > MAXIMUM_VDM_ENVIORNMENT) {
  1096. SetLastError(ERROR_INVALID_PARAMETER);
  1097. return FALSE;
  1098. }
  1099. wsCmdLine = wsAppName = NULL;
  1100. OemStringCmd.Buffer = NULL;
  1101. OemStringAppName.Buffer = NULL;
  1102. AnsiStringCurrentDir.Buffer = NULL;
  1103. AnsiStringDesktop.Buffer = NULL;
  1104. AnsiStringPif.Buffer = NULL;
  1105. OemStringTitle.Buffer = NULL;
  1106. AnsiStringReserved.Buffer = NULL;
  1107. wsBuffer = NULL;
  1108. wsPifName = NULL;
  1109. BinarySubType = BinaryType & BINARY_SUBTYPE_MASK;
  1110. BinaryType = BinaryType & ~BINARY_SUBTYPE_MASK;
  1111. bNewConsole = !NtCurrentPeb()->ProcessParameters->ConsoleHandle ||
  1112. (dwCreationFlags & CREATE_NEW_CONSOLE);
  1113. try {
  1114. if (BinaryType == BINARY_TYPE_DOS) {
  1115. //
  1116. // if the command line is a pif file we must have a new
  1117. // console since a pif file defines its own settings. This
  1118. // could be forced into a new console, but forcedos isn't
  1119. // cooperative.
  1120. //
  1121. if (BinarySubType == BINARY_TYPE_DOS_PIF && !bNewConsole) {
  1122. BaseSetLastNTError(STATUS_INVALID_IMAGE_NOT_MZ);
  1123. goto BCVTryExit;
  1124. }
  1125. Peb = NtCurrentPeb();
  1126. if (lpStartupInfo && lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) {
  1127. b->StdIn = lpStartupInfo->hStdInput;
  1128. b->StdOut = lpStartupInfo->hStdOutput;
  1129. b->StdErr = lpStartupInfo->hStdError;
  1130. }
  1131. else {
  1132. b->StdIn = Peb->ProcessParameters->StandardInput;
  1133. b->StdOut = Peb->ProcessParameters->StandardOutput;
  1134. b->StdErr = Peb->ProcessParameters->StandardError;
  1135. //
  1136. // Verify that the standard handles ntvdm process will inherit
  1137. // from the calling process are real handles. They are not
  1138. // handles if the calling process was created with
  1139. // STARTF_USEHOTKEY | STARTF_HASSHELLDATA.
  1140. // Note that CreateProcess clears STARTF_USESTANDHANDLES
  1141. // if either STARTF_USEHOTKEY or STARTF_HASSHELLDATA is set.
  1142. //
  1143. if (Peb->ProcessParameters->WindowFlags &
  1144. (STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) {
  1145. if (b->StdIn && !CONSOLE_HANDLE(b->StdIn) &&
  1146. !GetHandleInformation(b->StdIn, &HandleFlags))
  1147. b->StdIn = 0;
  1148. if (b->StdOut && !CONSOLE_HANDLE(b->StdOut) &&
  1149. !GetHandleInformation(b->StdOut, &HandleFlags)) {
  1150. if (b->StdErr == b->StdOut)
  1151. b->StdErr = 0;
  1152. b->StdOut = 0;
  1153. }
  1154. if (b->StdErr && b->StdErr != b->StdOut &&
  1155. !CONSOLE_HANDLE(b->StdErr) &&
  1156. !GetHandleInformation(b->StdErr, &HandleFlags))
  1157. b->StdErr = 0;
  1158. }
  1159. }
  1160. if (CONSOLE_HANDLE((b->StdIn)))
  1161. b->StdIn = 0;
  1162. if (CONSOLE_HANDLE((b->StdOut)))
  1163. b->StdOut = 0;
  1164. if (CONSOLE_HANDLE((b->StdErr)))
  1165. b->StdErr = 0;
  1166. }
  1167. if (BinaryType == BINARY_TYPE_SEPWOW) {
  1168. bNewConsole = TRUE;
  1169. }
  1170. //
  1171. // Convert Unicode Application Name to Oem short name
  1172. //
  1173. // skiping leading white space
  1174. while(*lpApplicationName == (WCHAR)' ' || *lpApplicationName == (WCHAR)'\t' ) {
  1175. lpApplicationName++;
  1176. }
  1177. // space for short AppName
  1178. Len = wcslen(lpApplicationName);
  1179. dwTotal = Len + 1 + MAX_PATH;
  1180. wsAppName = RtlAllocateHeap(RtlProcessHeap(),
  1181. MAKE_TAG(VDM_TAG),
  1182. dwTotal * sizeof(WCHAR)
  1183. );
  1184. if (wsAppName == NULL) {
  1185. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1186. goto BCVTryExit;
  1187. }
  1188. dw = GetShortPathNameW(lpApplicationName, wsAppName, dwTotal);
  1189. // If getting the short name is impossible, stop right here.
  1190. // We can not execute a 16bits biranry if we can not find
  1191. // its appropriate short name alias. Sorry HPFS, Sorry NFS
  1192. if (0 == dw || dw > dwTotal) {
  1193. SetLastError(ERROR_BAD_PATHNAME);
  1194. goto BCVTryExit;
  1195. }
  1196. RtlInitUnicodeString(&UnicodeString, wsAppName);
  1197. Status = RtlUnicodeStringToOemString(&OemStringAppName,
  1198. &UnicodeString,
  1199. TRUE
  1200. );
  1201. if (!NT_SUCCESS(Status) ){
  1202. BaseSetLastNTError(Status);
  1203. goto BCVTryExit;
  1204. }
  1205. //
  1206. // Find len of basename excluding extension,
  1207. // for CommandTail max len check.
  1208. //
  1209. dw = OemStringAppName.Length;
  1210. pch = OemStringAppName.Buffer;
  1211. Length = 1; // start at one for space between cmdname & cmdtail
  1212. while (dw-- && *pch != '.') {
  1213. if (*pch == '\\') {
  1214. Length = 1;
  1215. }
  1216. else {
  1217. Length++;
  1218. }
  1219. pch++;
  1220. }
  1221. //
  1222. // Find the beg of the command tail to pass as the CmdLine
  1223. //
  1224. Len = wcslen(lpApplicationName);
  1225. if (L'"' == lpCommandLine[0]) {
  1226. //
  1227. // Application name is quoted, skip the quoted text
  1228. // to get command tail.
  1229. //
  1230. pwch = (LPWSTR)&lpCommandLine[1];
  1231. while (*pwch && L'"' != *pwch++) {
  1232. ;
  1233. }
  1234. } else if (Len < wcslen(lpCommandLine) &&
  1235. 0 == _wcsnicmp(lpApplicationName, lpCommandLine, Len)) {
  1236. //
  1237. // Application path is also on the command line, skip past
  1238. // that to reach the command tail instead of looking for
  1239. // the first white space.
  1240. //
  1241. pwch = (LPWSTR)lpCommandLine + Len;
  1242. } else {
  1243. //
  1244. // We assume first token is exename (argv[0]).
  1245. //
  1246. pwch = (LPWSTR)lpCommandLine;
  1247. // skip leading white characters
  1248. while (*pwch != UNICODE_NULL &&
  1249. (*pwch == (WCHAR) ' ' || *pwch == (WCHAR) '\t')) {
  1250. pwch++;
  1251. }
  1252. // skip first token
  1253. if (*pwch == (WCHAR) '\"') { // quotes as delimiter
  1254. pwch++;
  1255. while (*pwch && *pwch++ != '\"') {
  1256. ;
  1257. }
  1258. }
  1259. else { // white space as delimiter
  1260. while (*pwch && *pwch != ' ' && *pwch != '\t') {
  1261. pwch++;
  1262. }
  1263. }
  1264. }
  1265. //
  1266. // pwch points past the application name, now skip any trailing
  1267. // whitespace.
  1268. //
  1269. while (*pwch && (L' ' == *pwch || L'\t' == *pwch)) {
  1270. pwch++;
  1271. }
  1272. wsCmdLine = pwch;
  1273. dw = wcslen(wsCmdLine);
  1274. // convert to oem
  1275. UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1276. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  1277. UnicodeString.Buffer = wsCmdLine;
  1278. Status = RtlUnicodeStringToOemString(
  1279. &OemStringCmd,
  1280. &UnicodeString,
  1281. TRUE);
  1282. if (!NT_SUCCESS(Status) ){
  1283. BaseSetLastNTError(Status);
  1284. goto BCVTryExit;
  1285. }
  1286. //
  1287. // check len of command line for dos compatibility
  1288. //
  1289. if (OemStringCmd.Length >= MAXIMUM_VDM_COMMAND_LENGTH - Length) {
  1290. SetLastError(ERROR_INVALID_PARAMETER);
  1291. goto BCVTryExit;
  1292. }
  1293. //
  1294. // Search for matching pif file. Search order is AppName dir,
  1295. // followed by win32 default search path. For the shared wow, pif
  1296. // is wowexec.pif if it exists.
  1297. //
  1298. wsBuffer = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( VDM_TAG ),MAX_PATH*sizeof(WCHAR));
  1299. if (!wsBuffer) {
  1300. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1301. goto BCVTryExit;
  1302. }
  1303. wsPifName = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( VDM_TAG ),MAX_PATH*sizeof(WCHAR));
  1304. if (!wsPifName) {
  1305. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1306. goto BCVTryExit;
  1307. }
  1308. if (BinaryType == BINARY_TYPE_WIN16) {
  1309. wcscpy(wsBuffer, wsSharedWowPif);
  1310. Len = 0;
  1311. }
  1312. else {
  1313. // start with fully qualified app name
  1314. wcscpy(wsBuffer, lpApplicationName);
  1315. // strip extension if any
  1316. pwch = wcsrchr(wsBuffer, (WCHAR)'.');
  1317. // dos application must have an extention
  1318. if (pwch == NULL) {
  1319. SetLastError(ERROR_INVALID_PARAMETER);
  1320. goto BCVTryExit;
  1321. }
  1322. wcscpy(pwch, wsPif);
  1323. Len = GetFileAttributesW(wsBuffer);
  1324. if (Len == (DWORD)(-1) || (Len & FILE_ATTRIBUTE_DIRECTORY)) {
  1325. Len = 0;
  1326. }
  1327. else {
  1328. Len = wcslen(wsBuffer) + 1;
  1329. wcsncpy(wsPifName, wsBuffer, Len);
  1330. }
  1331. }
  1332. if (!Len) { // try basename
  1333. // find beg of basename
  1334. pwch = wcsrchr(wsBuffer, (WCHAR)'\\');
  1335. if (!pwch ) {
  1336. pwch = wcsrchr(wsBuffer, (WCHAR)':');
  1337. }
  1338. // move basename to beg of wsBuffer
  1339. if (pwch++) {
  1340. while (*pwch != UNICODE_NULL &&
  1341. *pwch != (WCHAR)' ' && *pwch != (WCHAR)'\t' )
  1342. {
  1343. wsBuffer[Len++] = *pwch++;
  1344. }
  1345. wsBuffer[Len] = UNICODE_NULL;
  1346. }
  1347. if (Len) {
  1348. Len = SearchPathW(
  1349. NULL,
  1350. wsBuffer,
  1351. wsPif, // L".pif"
  1352. MAX_PATH,
  1353. wsPifName,
  1354. NULL
  1355. );
  1356. if (Len >= MAX_PATH) {
  1357. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1358. goto BCVTryExit;
  1359. }
  1360. }
  1361. }
  1362. if (!Len)
  1363. *wsPifName = UNICODE_NULL;
  1364. if (!ARGUMENT_PRESENT( lpCurrentDirectory )) {
  1365. dw = RtlGetCurrentDirectory_U(sizeof (wchBuffer), wchBuffer);
  1366. wchBuffer[dw / sizeof(WCHAR)] = UNICODE_NULL;
  1367. dw = GetShortPathNameW(wchBuffer,
  1368. wchBuffer,
  1369. sizeof(wchBuffer) / sizeof(WCHAR)
  1370. );
  1371. if (dw > sizeof(wchBuffer) / sizeof(WCHAR))
  1372. goto BCVTryExit;
  1373. else if (dw == 0) {
  1374. RtlInitUnicodeString(&UnicodeString, wchBuffer);
  1375. dw = UnicodeString.Length / sizeof(WCHAR);
  1376. }
  1377. else {
  1378. UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1379. UnicodeString.Buffer = wchBuffer;
  1380. UnicodeString.MaximumLength = (USHORT)sizeof(wchBuffer);
  1381. }
  1382. // DOS limit of 64 includes the final NULL but not the leading
  1383. // drive and slash. So here we should be checking the ansi length
  1384. // of current directory + 1 (for NULL) - 3 (for c:\).
  1385. if ( dw - 2 <= MAXIMUM_VDM_CURRENT_DIR ) {
  1386. Status = RtlUnicodeStringToAnsiString(
  1387. &AnsiStringCurrentDir,
  1388. &UnicodeString,
  1389. TRUE
  1390. );
  1391. }
  1392. else {
  1393. SetLastError(ERROR_INVALID_PARAMETER);
  1394. goto BCVTryExit;
  1395. }
  1396. if ( !NT_SUCCESS(Status) ) {
  1397. BaseSetLastNTError(Status);
  1398. goto BCVTryExit;
  1399. }
  1400. }
  1401. else {
  1402. dw = GetShortPathNameW(lpCurrentDirectory, wchBuffer,
  1403. sizeof(wchBuffer) / sizeof(WCHAR)
  1404. );
  1405. if (dw > sizeof(wchBuffer) / sizeof(WCHAR))
  1406. goto BCVTryExit;
  1407. if (dw != 0) {
  1408. UnicodeString.Buffer = wchBuffer;
  1409. UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1410. UnicodeString.MaximumLength = sizeof(wchBuffer);
  1411. }
  1412. else
  1413. RtlInitUnicodeString(&UnicodeString, lpCurrentDirectory);
  1414. Status = RtlUnicodeStringToAnsiString(
  1415. &AnsiStringCurrentDir,
  1416. &UnicodeString,
  1417. TRUE);
  1418. if ( !NT_SUCCESS(Status) ){
  1419. BaseSetLastNTError(Status);
  1420. goto BCVTryExit;
  1421. }
  1422. // DOS limit of 64 includes the final NULL but not the leading
  1423. // drive and slash. So here we should be checking the ansi length
  1424. // of current directory + 1 (for NULL) - 3 (for c:\).
  1425. if((AnsiStringCurrentDir.Length - 2) > MAXIMUM_VDM_CURRENT_DIR) {
  1426. SetLastError(ERROR_INVALID_PARAMETER);
  1427. goto BCVTryExit;
  1428. }
  1429. }
  1430. // NT allows applications to use UNC name as their current directory.
  1431. // while NTVDM can't do that. We will end up a weird drive number
  1432. // like '\' - 'a') here ????????????????????????????????
  1433. // BUGBUG
  1434. // Place Current Drive
  1435. if(AnsiStringCurrentDir.Buffer[0] <= 'Z')
  1436. b->CurDrive = AnsiStringCurrentDir.Buffer[0] - 'A';
  1437. else
  1438. b->CurDrive = AnsiStringCurrentDir.Buffer[0] - 'a';
  1439. //
  1440. // Hotkey info in NT traditionally is specified in the
  1441. // startupinfo.lpReserved field, but Win95 added a
  1442. // duplicate mechanism. If the Win95 method was used,
  1443. // map it to the NT method here so the rest of the
  1444. // VDM code only has to deal with one method.
  1445. //
  1446. // If the caller was stupid enough to specify a hotkey
  1447. // in lpReserved as well as using STARTF_USEHOTKEY,
  1448. // the STARTF_USEHOTKEY hotkey will take precedence.
  1449. //
  1450. if (lpStartupInfo && lpStartupInfo->dwFlags & STARTF_USEHOTKEY) {
  1451. DWORD cbAlloc = sizeof(WCHAR) *
  1452. (20 + // "hotkey.4294967295 " (MAXULONG)
  1453. (lpStartupInfo->lpReserved // length of prev lpReserved
  1454. ? wcslen(lpStartupInfo->lpReserved)
  1455. : 0
  1456. ) +
  1457. 1 // NULL terminator
  1458. );
  1459. lpAllocatedReserved = RtlAllocateHeap(RtlProcessHeap(),
  1460. MAKE_TAG( VDM_TAG ),
  1461. cbAlloc
  1462. );
  1463. if (lpAllocatedReserved) {
  1464. swprintf(lpAllocatedReserved,
  1465. L"hotkey.%u %s",
  1466. (DWORD) lpStartupInfo->hStdInput,
  1467. lpStartupInfo->lpReserved ? lpStartupInfo->lpReserved : L""
  1468. );
  1469. lpStartupInfo->dwFlags &= ~STARTF_USEHOTKEY;
  1470. lpStartupInfo->hStdInput = 0;
  1471. lpStartupInfo->lpReserved = lpAllocatedReserved;
  1472. }
  1473. }
  1474. //
  1475. // Allocate Capture Buffer
  1476. //
  1477. //
  1478. bufPointers = 2; // CmdLine, AppName
  1479. //
  1480. // CmdLine for capture buffer, 3 for 0xd,0xa and NULL
  1481. //
  1482. Len = ROUND_UP((OemStringCmd.Length + 3),4);
  1483. // AppName, 1 for NULL
  1484. Len += ROUND_UP((OemStringAppName.Length + 1),4);
  1485. // Env
  1486. if (pAnsiStringEnv->Length) {
  1487. bufPointers++;
  1488. Len += ROUND_UP(pAnsiStringEnv->Length, 4);
  1489. }
  1490. // CurrentDir
  1491. if (AnsiStringCurrentDir.Length){
  1492. bufPointers++;
  1493. Len += ROUND_UP((AnsiStringCurrentDir.Length +1),4); // 1 for NULL
  1494. }
  1495. // pif file name, 1 for NULL
  1496. if (wsPifName && *wsPifName != UNICODE_NULL) {
  1497. bufPointers++;
  1498. RtlInitUnicodeString(&UnicodeString,wsPifName);
  1499. Status = RtlUnicodeStringToAnsiString(&AnsiStringPif,
  1500. &UnicodeString,
  1501. TRUE
  1502. );
  1503. if ( !NT_SUCCESS(Status) ){
  1504. BaseSetLastNTError(Status);
  1505. goto BCVTryExit;
  1506. }
  1507. Len += ROUND_UP((AnsiStringPif.Length+1),4);
  1508. }
  1509. //
  1510. // startupinfo space
  1511. //
  1512. if (lpStartupInfo) {
  1513. Len += ROUND_UP(sizeof(STARTUPINFOA),4);
  1514. bufPointers++;
  1515. if (lpStartupInfo->lpDesktop) {
  1516. bufPointers++;
  1517. RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpDesktop);
  1518. Status = RtlUnicodeStringToAnsiString(
  1519. &AnsiStringDesktop,
  1520. &UnicodeString,
  1521. TRUE);
  1522. if ( !NT_SUCCESS(Status) ){
  1523. BaseSetLastNTError(Status);
  1524. goto BCVTryExit;
  1525. }
  1526. Len += ROUND_UP((AnsiStringDesktop.Length+1),4);
  1527. }
  1528. if (lpStartupInfo->lpTitle) {
  1529. bufPointers++;
  1530. RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpTitle);
  1531. Status = RtlUnicodeStringToOemString(
  1532. &OemStringTitle,
  1533. &UnicodeString,
  1534. TRUE);
  1535. if ( !NT_SUCCESS(Status) ){
  1536. BaseSetLastNTError(Status);
  1537. goto BCVTryExit;
  1538. }
  1539. Len += ROUND_UP((OemStringTitle.Length+1),4);
  1540. }
  1541. if (lpStartupInfo->lpReserved) {
  1542. bufPointers++;
  1543. RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpReserved);
  1544. Status = RtlUnicodeStringToAnsiString(
  1545. &AnsiStringReserved,
  1546. &UnicodeString,
  1547. TRUE);
  1548. if ( !NT_SUCCESS(Status) ){
  1549. BaseSetLastNTError(Status);
  1550. goto BCVTryExit;
  1551. }
  1552. Len += ROUND_UP((AnsiStringReserved.Length+1),4);
  1553. }
  1554. }
  1555. // capture message buffer
  1556. CaptureBuffer = CsrAllocateCaptureBuffer(bufPointers, 0, Len);
  1557. if (CaptureBuffer == NULL) {
  1558. BaseSetLastNTError( STATUS_NO_MEMORY );
  1559. goto BCVTryExit;
  1560. }
  1561. // Allocate CmdLine pointer
  1562. CsrAllocateMessagePointer( CaptureBuffer,
  1563. ROUND_UP((OemStringCmd.Length + 3),4),
  1564. (PVOID *)&b->CmdLine
  1565. );
  1566. // Copy Command Line
  1567. RtlMoveMemory (b->CmdLine, OemStringCmd.Buffer, OemStringCmd.Length);
  1568. b->CmdLine[OemStringCmd.Length] = 0xd;
  1569. b->CmdLine[OemStringCmd.Length+1] = 0xa;
  1570. b->CmdLine[OemStringCmd.Length+2] = 0;
  1571. b->CmdLen = (USHORT)(OemStringCmd.Length + 3);
  1572. // Allocate AppName pointer
  1573. CsrAllocateMessagePointer( CaptureBuffer,
  1574. ROUND_UP((OemStringAppName.Length + 1),4),
  1575. (PVOID *)&b->AppName
  1576. );
  1577. // Copy AppName
  1578. RtlMoveMemory (b->AppName,
  1579. OemStringAppName.Buffer,
  1580. OemStringAppName.Length
  1581. );
  1582. b->AppName[OemStringAppName.Length] = 0;
  1583. b->AppLen = OemStringAppName.Length + 1;
  1584. // Allocate PifFile pointer, Copy PifFile name
  1585. if(AnsiStringPif.Buffer) {
  1586. CsrAllocateMessagePointer( CaptureBuffer,
  1587. ROUND_UP((AnsiStringPif.Length + 1),4),
  1588. (PVOID *)&b->PifFile
  1589. );
  1590. RtlMoveMemory(b->PifFile,
  1591. AnsiStringPif.Buffer,
  1592. AnsiStringPif.Length);
  1593. b->PifFile[AnsiStringPif.Length] = 0;
  1594. b->PifLen = AnsiStringPif.Length + 1;
  1595. }
  1596. else {
  1597. b->PifLen = 0;
  1598. b->PifFile = NULL;
  1599. }
  1600. // Allocate Env pointer, Copy Env strings
  1601. if(pAnsiStringEnv->Length) {
  1602. CsrAllocateMessagePointer( CaptureBuffer,
  1603. ROUND_UP((pAnsiStringEnv->Length),4),
  1604. (PVOID *)&b->Env
  1605. );
  1606. RtlMoveMemory(b->Env,
  1607. pAnsiStringEnv->Buffer,
  1608. pAnsiStringEnv->Length);
  1609. b->EnvLen = pAnsiStringEnv->Length;
  1610. }
  1611. else {
  1612. b->EnvLen = 0;
  1613. b->Env = NULL;
  1614. }
  1615. if(AnsiStringCurrentDir.Length) {
  1616. // Allocate Curdir pointer
  1617. CsrAllocateMessagePointer( CaptureBuffer,
  1618. ROUND_UP((AnsiStringCurrentDir.Length + 1),4),
  1619. (PVOID *)&b->CurDirectory
  1620. );
  1621. // copy cur directory
  1622. RtlMoveMemory (b->CurDirectory,
  1623. AnsiStringCurrentDir.Buffer,
  1624. AnsiStringCurrentDir.Length+1);
  1625. b->CurDirectoryLen = AnsiStringCurrentDir.Length+1;
  1626. }
  1627. else {
  1628. b->CurDirectory = NULL;
  1629. b->CurDirectoryLen = 0;
  1630. }
  1631. // Allocate startupinfo pointer
  1632. if (lpStartupInfo) {
  1633. CsrAllocateMessagePointer( CaptureBuffer,
  1634. ROUND_UP(sizeof(STARTUPINFOA),4),
  1635. (PVOID *)&b->StartupInfo
  1636. );
  1637. // Copy startupinfo
  1638. b->StartupInfo->dwX = lpStartupInfo->dwX;
  1639. b->StartupInfo->dwY = lpStartupInfo->dwY;
  1640. b->StartupInfo->dwXSize = lpStartupInfo->dwXSize;
  1641. b->StartupInfo->dwYSize = lpStartupInfo->dwYSize;
  1642. b->StartupInfo->dwXCountChars= lpStartupInfo->dwXCountChars;
  1643. b->StartupInfo->dwYCountChars= lpStartupInfo->dwYCountChars;
  1644. b->StartupInfo->dwFillAttribute=lpStartupInfo->dwFillAttribute;
  1645. b->StartupInfo->dwFlags = lpStartupInfo->dwFlags;
  1646. b->StartupInfo->wShowWindow = lpStartupInfo->wShowWindow;
  1647. b->StartupInfo->cb = sizeof(STARTUPINFOA);
  1648. }
  1649. else {
  1650. b->StartupInfo = NULL;
  1651. }
  1652. // Allocate pointer for Desktop info if needed
  1653. if (AnsiStringDesktop.Buffer) {
  1654. CsrAllocateMessagePointer( CaptureBuffer,
  1655. ROUND_UP((AnsiStringDesktop.Length + 1),4),
  1656. (PVOID *)&b->Desktop
  1657. );
  1658. // Copy desktop string
  1659. RtlMoveMemory (b->Desktop,
  1660. AnsiStringDesktop.Buffer,
  1661. AnsiStringDesktop.Length+1);
  1662. b->DesktopLen =AnsiStringDesktop.Length+1;
  1663. }
  1664. else {
  1665. b->Desktop = NULL;
  1666. b->DesktopLen =0;
  1667. }
  1668. // Allocate pointer for Title info if needed
  1669. if (OemStringTitle.Buffer) {
  1670. CsrAllocateMessagePointer( CaptureBuffer,
  1671. ROUND_UP((OemStringTitle.Length + 1),4),
  1672. (PVOID *)&b->Title
  1673. );
  1674. // Copy title string
  1675. RtlMoveMemory (b->Title,
  1676. OemStringTitle.Buffer,
  1677. OemStringTitle.Length+1);
  1678. b->TitleLen = OemStringTitle.Length+1;
  1679. }
  1680. else {
  1681. b->Title = NULL;
  1682. b->TitleLen = 0;
  1683. }
  1684. // Allocate pointer for Reserved field if needed
  1685. if (AnsiStringReserved.Buffer) {
  1686. CsrAllocateMessagePointer( CaptureBuffer,
  1687. ROUND_UP((AnsiStringReserved.Length + 1),4),
  1688. (PVOID *)&b->Reserved
  1689. );
  1690. // Copy reserved string
  1691. RtlMoveMemory (b->Reserved,
  1692. AnsiStringReserved.Buffer,
  1693. AnsiStringReserved.Length+1);
  1694. b->ReservedLen = AnsiStringReserved.Length+1;
  1695. }
  1696. else {
  1697. b->Reserved = NULL;
  1698. b->ReservedLen = 0;
  1699. }
  1700. if (BinaryType == BINARY_TYPE_WIN16)
  1701. b->ConsoleHandle = (HANDLE)-1;
  1702. else if (bNewConsole)
  1703. b->ConsoleHandle = 0;
  1704. else
  1705. b->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  1706. b->VDMState = FALSE;
  1707. b->BinaryType = BinaryType;
  1708. b->CodePage = (ULONG) GetConsoleCP ();
  1709. b->dwCreationFlags = dwCreationFlags;
  1710. Status = CsrClientCallServer(
  1711. (PCSR_API_MSG)m,
  1712. CaptureBuffer,
  1713. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  1714. BasepCheckVDM
  1715. ),
  1716. sizeof( *b )
  1717. );
  1718. CsrFreeCaptureBuffer(CaptureBuffer);
  1719. if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m->ReturnValue)) {
  1720. BaseSetLastNTError((NTSTATUS)m->ReturnValue);
  1721. goto BCVTryExit;
  1722. }
  1723. *iTask = b->iTask;
  1724. bReturn = TRUE;
  1725. BCVTryExit:;
  1726. }
  1727. finally {
  1728. if(Buffer != NULL)
  1729. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)Buffer);
  1730. if(wsBuffer != NULL)
  1731. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)wsBuffer);
  1732. if(wsPifName != NULL)
  1733. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)wsPifName);
  1734. if(OemStringCmd.Buffer != NULL)
  1735. RtlFreeOemString(&OemStringCmd);
  1736. if(OemStringAppName.Buffer != NULL)
  1737. RtlFreeOemString(&OemStringAppName);
  1738. if(AnsiStringPif.Buffer != NULL)
  1739. RtlFreeAnsiString(&AnsiStringPif);
  1740. if(AnsiStringCurrentDir.Buffer != NULL)
  1741. RtlFreeAnsiString(&AnsiStringCurrentDir);
  1742. if(AnsiStringDesktop.Buffer != NULL)
  1743. RtlFreeAnsiString(&AnsiStringDesktop);
  1744. if(OemStringTitle.Buffer != NULL)
  1745. RtlFreeAnsiString(&OemStringTitle);
  1746. if(AnsiStringReserved.Buffer != NULL)
  1747. RtlFreeAnsiString(&AnsiStringReserved);
  1748. if (wsAppName != NULL)
  1749. RtlFreeHeap(RtlProcessHeap(), 0, wsAppName);
  1750. if (lpAllocatedReserved != NULL)
  1751. RtlFreeHeap(RtlProcessHeap(), 0, lpAllocatedReserved);
  1752. }
  1753. return bReturn;
  1754. }
  1755. BOOL
  1756. BaseUpdateVDMEntry(
  1757. IN ULONG UpdateIndex,
  1758. IN OUT HANDLE *WaitHandle,
  1759. IN ULONG IndexInfo,
  1760. IN ULONG BinaryType
  1761. )
  1762. {
  1763. NTSTATUS Status;
  1764. BASE_API_MSG m;
  1765. PBASE_UPDATE_VDM_ENTRY_MSG c= (PBASE_UPDATE_VDM_ENTRY_MSG)&m.u.UpdateVDMEntry;
  1766. switch (UpdateIndex) {
  1767. case UPDATE_VDM_UNDO_CREATION:
  1768. c->iTask = (ULONG)*WaitHandle;
  1769. c->VDMCreationState = (USHORT)IndexInfo;
  1770. break;
  1771. case UPDATE_VDM_PROCESS_HANDLE:
  1772. c->VDMProcessHandle = *WaitHandle; // Actually this is VDM handle
  1773. c->iTask = IndexInfo;
  1774. break;
  1775. }
  1776. if(BinaryType == BINARY_TYPE_WIN16)
  1777. c->ConsoleHandle = (HANDLE)-1;
  1778. else if (c->iTask)
  1779. c->ConsoleHandle = 0;
  1780. else
  1781. c->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  1782. c->EntryIndex = (WORD)UpdateIndex;
  1783. c->BinaryType = BinaryType;
  1784. Status = CsrClientCallServer(
  1785. (PCSR_API_MSG)&m,
  1786. NULL,
  1787. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  1788. BasepUpdateVDMEntry
  1789. ),
  1790. sizeof( *c )
  1791. );
  1792. if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  1793. BaseSetLastNTError((NTSTATUS)m.ReturnValue);
  1794. return FALSE;
  1795. }
  1796. switch (UpdateIndex) {
  1797. case UPDATE_VDM_UNDO_CREATION:
  1798. break;
  1799. case UPDATE_VDM_PROCESS_HANDLE:
  1800. *WaitHandle = c->WaitObjectForParent;
  1801. break;
  1802. }
  1803. return TRUE;
  1804. }
  1805. ULONG
  1806. BaseIsDosApplication(
  1807. IN PUNICODE_STRING PathName,
  1808. IN NTSTATUS Status
  1809. )
  1810. /*++
  1811. Routine Description:
  1812. Determines if app is a ".com" or a ".pif" type of app
  1813. by looking at the extension, and the Status from NtCreateSection
  1814. for PAGE_EXECUTE.
  1815. Arguments:
  1816. PathName -- Supplies a pointer to the path string
  1817. Status -- Status code from CreateSection call
  1818. bNewConsole -- Pif can exec only from a new console
  1819. Return Value:
  1820. file is a com\pif dos application
  1821. SCS_DOS_BINARY - ".com", may also be a .exe extension
  1822. SCS_PIF_BINARY - ".pif"
  1823. 0 -- file is not a dos application, may be a .bat or .cmd file
  1824. --*/
  1825. {
  1826. UNICODE_STRING String;
  1827. // check for .com extension
  1828. String.Length = BaseDotComSuffixName.Length;
  1829. String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1830. sizeof(WCHAR)]);
  1831. if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE))
  1832. return BINARY_TYPE_DOS_COM;
  1833. // check for .pif extension
  1834. String.Length = BaseDotPifSuffixName.Length;
  1835. String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1836. sizeof(WCHAR)]);
  1837. if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE))
  1838. return BINARY_TYPE_DOS_PIF;
  1839. // check for .exe extension
  1840. String.Length = BaseDotExeSuffixName.Length;
  1841. String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1842. sizeof(WCHAR)]);
  1843. if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE))
  1844. return BINARY_TYPE_DOS_EXE;
  1845. return 0;
  1846. }
  1847. BOOL
  1848. BaseGetVdmConfigInfo(
  1849. IN LPCWSTR CommandLine,
  1850. IN ULONG DosSeqId,
  1851. IN ULONG BinaryType,
  1852. IN PUNICODE_STRING CmdLineString,
  1853. OUT PULONG VdmSize
  1854. )
  1855. /*++
  1856. Routine Description:
  1857. This routine locates the VDM configuration information for Wow vdms in
  1858. the system configuration file. It also reconstructs the commandline so
  1859. that we can start the VDM. The new command line is composed from the
  1860. information in the configuration file + the old command line.
  1861. Arguments:
  1862. CommandLine -- pointer to a string pointer that is used to pass the
  1863. command line string
  1864. DosSeqId - new console session id.
  1865. VdmSize -- Returns the size in bytes of the VDM to be created
  1866. BinaryType - dos, sharedwow, sepwow
  1867. Return Value:
  1868. TRUE -- VDM configuration information was available
  1869. FALSE -- VDM configuration information was not available
  1870. Notes:
  1871. --*/
  1872. {
  1873. NTSTATUS Status;
  1874. BOOL bRet;
  1875. DWORD dw;
  1876. ANSI_STRING AnsiString;
  1877. LPSTR NewCmdLine=NULL;
  1878. PCH pSrc, pDst, pch;
  1879. ULONG Len;
  1880. char CmdLine[MAX_VDM_CFG_LINE];
  1881. CmdLineString->Buffer = NULL;
  1882. Len = MAX_VDM_CFG_LINE;
  1883. if (BinaryType == BINARY_TYPE_DOS) {
  1884. bRet = BaseGetVDMKeyword(CMDLINE, CmdLine, &Len, DOSSIZE, VdmSize);
  1885. }
  1886. else {
  1887. bRet = BaseGetVDMKeyword(WOWCMDLINE, CmdLine, &Len, WOWSIZE, VdmSize);
  1888. }
  1889. if (!bRet) {
  1890. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1891. return FALSE;
  1892. }
  1893. //
  1894. // Allocate memory to replace the CommandLine
  1895. // extra space is needed for long->short name conversion,
  1896. // separate wow, and extension.
  1897. //
  1898. NewCmdLine = RtlAllocateHeap(RtlProcessHeap(),
  1899. MAKE_TAG( VDM_TAG ),
  1900. MAX_PATH + MAX_VDM_CFG_LINE
  1901. );
  1902. if (!NewCmdLine) {
  1903. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1904. return FALSE;
  1905. }
  1906. //
  1907. // Copy over the cmdline checking for special args
  1908. // and locating the beg of wowkernel
  1909. //
  1910. pSrc = CmdLine;
  1911. pDst = NewCmdLine;
  1912. //
  1913. // first token must be "\\%SystemRoot%\\system32\\ntvdm", search
  1914. // for the tail of the pathname to traverse possible long file name
  1915. // safely.
  1916. //
  1917. pch = strstr(pSrc, "\\system32\\ntvdm");
  1918. if (!pch) {
  1919. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1920. return FALSE;
  1921. }
  1922. // mov pch to trailing space in "ntvdm "
  1923. while (*pch && *pch != ' ') {
  1924. pch++;
  1925. }
  1926. //
  1927. // copy first token (ntvdm path name), surrounded by quotes for
  1928. // possible long file name
  1929. //
  1930. *pDst++ = '\"';
  1931. while (pSrc < pch) {
  1932. *pDst++ = *pSrc++;
  1933. }
  1934. *pDst++ = '\"';
  1935. //
  1936. // Add -f arg, so ntvdm knows it wasn't invoked directly
  1937. //
  1938. *pDst++ = ' ';
  1939. *pDst++ = '-';
  1940. *pDst++ = 'f';
  1941. //
  1942. // Add DosSeqId for new console
  1943. //
  1944. if (DosSeqId) {
  1945. sprintf(pDst, " -i%lx", DosSeqId);
  1946. pDst += strlen(pDst);
  1947. }
  1948. //
  1949. // Copy over everything up to the " -a " (exclusive)
  1950. // CAVEAT: we assume -a is last
  1951. //
  1952. pch = strstr(pSrc, " -a ");
  1953. if (pch) {
  1954. while (pSrc < pch) {
  1955. *pDst++ = *pSrc++;
  1956. }
  1957. }
  1958. else {
  1959. while (*pSrc) {
  1960. *pDst++ = *pSrc++;
  1961. }
  1962. }
  1963. *pDst = '\0';
  1964. //
  1965. // for wow -a is mandatory to specify win16 krnl, and is expected
  1966. // to be the last cmdline parameter
  1967. //
  1968. if (BinaryType != BINARY_TYPE_DOS) { // shared wow, sep wow
  1969. PCH pWowKernel;
  1970. if (!*pSrc) {
  1971. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1972. return FALSE;
  1973. }
  1974. //
  1975. // Add -w to tell ntvdm its wow (mandatory)
  1976. //
  1977. *pDst++ = ' ';
  1978. *pDst++ = '-';
  1979. *pDst++ = 'w';
  1980. //
  1981. // copy over the " -a WowKernelPathname" argument
  1982. // and locate beg of WowKernelPathname in destination
  1983. //
  1984. pWowKernel = pDst;
  1985. while (*pSrc) {
  1986. *pDst++ = *pSrc++;
  1987. }
  1988. pWowKernel += 4; // find beg of WowKernelPathaname
  1989. while (*pWowKernel == ' ') {
  1990. pWowKernel++;
  1991. }
  1992. //
  1993. // Append file extension to destination
  1994. //
  1995. strcpy(pDst, ".exe");
  1996. //
  1997. // convert wowkernel to short name
  1998. //
  1999. Len = MAX_PATH + MAX_VDM_CFG_LINE - ((ULONG)pWowKernel - (ULONG)NewCmdLine) -1;
  2000. dw = GetShortPathNameA(pWowKernel, pWowKernel, Len);
  2001. if (dw > Len) {
  2002. RtlFreeHeap(RtlProcessHeap(), 0, NewCmdLine);
  2003. return FALSE;
  2004. }
  2005. }
  2006. RtlInitAnsiString(&AnsiString, NewCmdLine);
  2007. Status = RtlAnsiStringToUnicodeString(CmdLineString, &AnsiString, TRUE);
  2008. if (!NT_SUCCESS(Status)) {
  2009. BaseSetLastNTError(Status);
  2010. RtlFreeHeap(RtlProcessHeap(), 0, NewCmdLine);
  2011. CmdLineString->Buffer = NULL;
  2012. return FALSE;
  2013. }
  2014. RtlFreeHeap(RtlProcessHeap(), 0, NewCmdLine);
  2015. return TRUE;
  2016. }
  2017. BOOL
  2018. BaseCheckForVDM(
  2019. IN HANDLE hProcess,
  2020. OUT LPDWORD lpExitCode
  2021. )
  2022. {
  2023. NTSTATUS Status;
  2024. EVENT_BASIC_INFORMATION ebi;
  2025. BASE_API_MSG m;
  2026. PBASE_GET_VDM_EXIT_CODE_MSG a = (PBASE_GET_VDM_EXIT_CODE_MSG)&m.u.GetVDMExitCode;
  2027. Status = NtQueryEvent (
  2028. hProcess,
  2029. EventBasicInformation,
  2030. &ebi,
  2031. sizeof(ebi),
  2032. NULL);
  2033. if(!NT_SUCCESS(Status))
  2034. return FALSE;
  2035. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  2036. a->hParent = hProcess;
  2037. Status = CsrClientCallServer(
  2038. (PCSR_API_MSG)&m,
  2039. NULL,
  2040. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  2041. BasepGetVDMExitCode),
  2042. sizeof( *a )
  2043. );
  2044. if (!NT_SUCCESS(Status)) {
  2045. return FALSE;
  2046. }
  2047. *lpExitCode = (DWORD)a->ExitCode;
  2048. return TRUE;
  2049. }
  2050. DWORD
  2051. APIENTRY
  2052. GetShortPathNameA(
  2053. IN LPCSTR lpszLongPath,
  2054. IN LPSTR lpShortPath,
  2055. IN DWORD cchBuffer
  2056. )
  2057. {
  2058. UNICODE_STRING UString, UStringRet;
  2059. ANSI_STRING AString;
  2060. NTSTATUS Status;
  2061. LPWSTR lpShortPathW;
  2062. DWORD ReturnValue=0;
  2063. if (lpszLongPath == NULL) {
  2064. SetLastError(ERROR_INVALID_PARAMETER);
  2065. return 0;
  2066. }
  2067. try {
  2068. RtlInitAnsiString(&AString, lpszLongPath);
  2069. Status = Basep8BitStringToUnicodeString(&UString,
  2070. &AString,
  2071. TRUE
  2072. );
  2073. if (!NT_SUCCESS(Status)){
  2074. BaseSetLastNTError(Status);
  2075. goto gspTryExit;
  2076. }
  2077. if (ARGUMENT_PRESENT(lpShortPath) && cchBuffer > 0) {
  2078. lpShortPathW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2079. cchBuffer * sizeof(WCHAR)
  2080. );
  2081. if (lpShortPathW == NULL) {
  2082. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2083. goto gspTryExit;
  2084. }
  2085. }
  2086. else {
  2087. lpShortPathW = NULL;
  2088. cchBuffer = 0;
  2089. }
  2090. ReturnValue = GetShortPathNameW(UString.Buffer,
  2091. lpShortPathW,
  2092. cchBuffer
  2093. );
  2094. if (ReturnValue != 0 && ReturnValue <= cchBuffer) {
  2095. if (ARGUMENT_PRESENT(lpShortPath)) {
  2096. AString.Buffer = lpShortPath;
  2097. AString.MaximumLength = (USHORT) cchBuffer;
  2098. UString.MaximumLength = (USHORT)(cchBuffer * sizeof(WCHAR));
  2099. UStringRet.Buffer = lpShortPathW;
  2100. UStringRet.Length = (USHORT)(ReturnValue * sizeof(WCHAR));
  2101. Status = BasepUnicodeStringTo8BitString(&AString,
  2102. &UStringRet,
  2103. FALSE
  2104. );
  2105. if (!NT_SUCCESS(Status)) {
  2106. BaseSetLastNTError(Status);
  2107. ReturnValue=0;
  2108. goto gspTryExit;
  2109. }
  2110. }
  2111. }
  2112. gspTryExit:;
  2113. }
  2114. finally {
  2115. RtlFreeUnicodeString(&UString);
  2116. RtlFreeHeap(RtlProcessHeap(), 0, lpShortPathW);
  2117. }
  2118. return ReturnValue;
  2119. }
  2120. /****
  2121. GetShortPathName
  2122. Description:
  2123. This function converts the given path name to its short form if
  2124. needed. The conversion may not be necessary and in that case,
  2125. this function simply copies down the given name to the return buffer.
  2126. The caller can have the return buffer set equal to the given path name
  2127. address.
  2128. Parameters:
  2129. lpszLongPath - Points to a NULL terminated string.
  2130. lpszShortPath - Buffer address to return the short name.
  2131. cchBuffer - Buffer size in char of lpszShortPath.
  2132. Return Value
  2133. If the GetShortPathName function succeeds, the return value is the length,
  2134. in characters, of the string copied to lpszShortPath,
  2135. not including the terminating
  2136. null character.
  2137. If the lpszShortPath is too small, the return value is
  2138. the size of the buffer, in
  2139. characters, required to hold the path.
  2140. If the function fails, the return value is zero. To get
  2141. extended error information, use
  2142. the GetLastError function.
  2143. Remarks:
  2144. The "short name" can be longer than its "long name". lpszLongPath doesn't
  2145. have to be a fully qualified path name or a long path name.
  2146. ****/
  2147. DWORD
  2148. APIENTRY
  2149. GetShortPathNameW(
  2150. IN LPCWSTR lpszLongPath,
  2151. IN LPWSTR lpszShortPath,
  2152. IN DWORD cchBuffer
  2153. )
  2154. {
  2155. RTL_PATH_TYPE RtlPathType;
  2156. LPWSTR p, p1, p2, pLast, pDst;
  2157. DWORD wchTotal, Length;
  2158. WCHAR wch, BufferForFileNameInfo[4 + 14];
  2159. IO_STATUS_BLOCK IoStatusBlock;
  2160. OBJECT_ATTRIBUTES Obja;
  2161. NTSTATUS Status;
  2162. PFILE_NAME_INFORMATION pFileNameInfo;
  2163. HANDLE Handle;
  2164. PWCHAR pLocalBuffer;
  2165. UINT uReturnVal;
  2166. BOOLEAN TranslationStatus;
  2167. UINT Count;
  2168. UNICODE_STRING UStringNtName;
  2169. uReturnVal = 0;
  2170. UStringNtName.Buffer = NULL;
  2171. pLocalBuffer = NULL;
  2172. if (!ARGUMENT_PRESENT(lpszLongPath)) {
  2173. SetLastError(ERROR_INVALID_PARAMETER);
  2174. return 0;
  2175. }
  2176. try {
  2177. // decide the path type, we want to find out the position of
  2178. // the first character of the first name
  2179. RtlPathType = RtlDetermineDosPathNameType_U(lpszLongPath);
  2180. switch (RtlPathType) {
  2181. // form: "\\server_name\share_name\rest_of_the_path"
  2182. case RtlPathTypeUncAbsolute:
  2183. p = (LPWSTR)lpszLongPath + 2;
  2184. Count = 2;
  2185. // guard for UNICODE_NULL is necessary because
  2186. // RtlDetermineDosPathNameType_U doesn't really
  2187. // verify an UNC name.
  2188. while (Count && *p != UNICODE_NULL) {
  2189. if (*p == L'\\' || *p == L'/')
  2190. Count--;
  2191. p++;
  2192. }
  2193. break;
  2194. // form: "\\.\rest_of_the_path"
  2195. case RtlPathTypeLocalDevice:
  2196. p = (LPWSTR)lpszLongPath + 4;
  2197. break;
  2198. // form: "\\."
  2199. case RtlPathTypeRootLocalDevice:
  2200. p = NULL;
  2201. break;
  2202. // form: "D:\rest_of_the_path"
  2203. case RtlPathTypeDriveAbsolute:
  2204. p = (LPWSTR)lpszLongPath + 3;
  2205. break;
  2206. // form: "D:rest_of_the_path"
  2207. case RtlPathTypeDriveRelative:
  2208. p = (LPWSTR)lpszLongPath + 2;
  2209. break;
  2210. // form: "\rest_of_the_path"
  2211. case RtlPathTypeRooted:
  2212. p = (LPWSTR)lpszLongPath + 1;
  2213. break;
  2214. // form: "rest_of_the_path"
  2215. case RtlPathTypeRelative:
  2216. p = (LPWSTR) lpszLongPath;
  2217. break;
  2218. default:
  2219. p = NULL;
  2220. break;
  2221. }
  2222. if (p == NULL || *p == UNICODE_NULL ||
  2223. !BaseSearchLongName_U(p, &p1)) {
  2224. // nothing to convert, copy down the source string
  2225. // to the buffer if necessary
  2226. if (p == NULL)
  2227. Length = wcslen(lpszLongPath) + 1;
  2228. else if (*p == UNICODE_NULL)
  2229. Length = (DWORD)(p - lpszLongPath + 1);
  2230. else
  2231. Length = (DWORD)(p1 - lpszLongPath + 1);
  2232. if (cchBuffer >= Length) {
  2233. if (ARGUMENT_PRESENT(lpszShortPath) && lpszShortPath != lpszLongPath) {
  2234. RtlMoveMemory(lpszShortPath, lpszLongPath, Length * sizeof(WCHAR));
  2235. }
  2236. uReturnVal = Length - 1;
  2237. goto gsnTryExit;
  2238. }
  2239. else {
  2240. uReturnVal = Length;
  2241. goto gsnTryExit;
  2242. }
  2243. }
  2244. // Make a local buffer so that we won't overlap the
  2245. // source pathname in case the short name is longer than the
  2246. // long name.
  2247. if (cchBuffer > 0 && ARGUMENT_PRESENT(lpszShortPath)) {
  2248. pLocalBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2249. cchBuffer * sizeof(WCHAR));
  2250. if (pLocalBuffer == NULL){
  2251. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2252. goto gsnTryExit;
  2253. }
  2254. }
  2255. pDst = pLocalBuffer;
  2256. pLast = (LPWSTR)lpszLongPath;
  2257. UStringNtName.Buffer = NULL;
  2258. wchTotal = 0;
  2259. while (TRUE) {
  2260. // p1 points to the first LFN character
  2261. // copy the short name in the source first
  2262. Length = (DWORD)(p1 - pLast);
  2263. if (Length > 0) {
  2264. wchTotal += Length;
  2265. if (cchBuffer > wchTotal && ARGUMENT_PRESENT(lpszShortPath)) {
  2266. RtlMoveMemory(pDst, pLast, Length * sizeof(WCHAR));
  2267. pDst += Length;
  2268. }
  2269. }
  2270. p2 = p1;
  2271. while (*p2 != UNICODE_NULL) {
  2272. if (*p2 == L'\\' || *p2 == L'/')
  2273. break;
  2274. p2++;
  2275. }
  2276. wch = *p2;
  2277. *p2 = UNICODE_NULL;
  2278. // forgot to free the buffer while going to the loop???
  2279. ASSERT(UStringNtName.Buffer == NULL);
  2280. // convert to nt path name. This will take care of
  2281. // \. and \..
  2282. TranslationStatus = RtlDosPathNameToNtPathName_U(lpszLongPath,
  2283. &UStringNtName,
  2284. NULL,
  2285. NULL
  2286. );
  2287. *p2 = wch;
  2288. if (!TranslationStatus) {
  2289. SetLastError(ERROR_PATH_NOT_FOUND);
  2290. goto gsnTryExit;
  2291. }
  2292. pFileNameInfo = (PFILE_NAME_INFORMATION)BufferForFileNameInfo;
  2293. InitializeObjectAttributes(&Obja,
  2294. &UStringNtName,
  2295. OBJ_CASE_INSENSITIVE,
  2296. NULL,
  2297. NULL
  2298. );
  2299. // use FILE_READ_ATTRIBUTES so we don't have to worry about
  2300. // sharing violation.
  2301. Status = NtOpenFile(&Handle,
  2302. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  2303. &Obja,
  2304. &IoStatusBlock,
  2305. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2306. FILE_SYNCHRONOUS_IO_NONALERT
  2307. );
  2308. // free the buffer because we don't need it any more
  2309. RtlFreeUnicodeString(&UStringNtName);
  2310. UStringNtName.Buffer = NULL;
  2311. if (!NT_SUCCESS(Status)) {
  2312. BaseSetLastNTError(Status);
  2313. goto gsnTryExit;
  2314. }
  2315. // get the short name
  2316. Status = NtQueryInformationFile(Handle,
  2317. &IoStatusBlock,
  2318. pFileNameInfo,
  2319. sizeof(BufferForFileNameInfo),
  2320. FileAlternateNameInformation
  2321. );
  2322. NtClose(Handle);
  2323. if (!NT_SUCCESS(Status)) {
  2324. BaseSetLastNTError(Status);
  2325. goto gsnTryExit;
  2326. }
  2327. // the returned length is in bytes!!
  2328. wchTotal += pFileNameInfo->FileNameLength / sizeof(WCHAR);
  2329. if (cchBuffer > wchTotal && ARGUMENT_PRESENT(lpszShortPath)) {
  2330. RtlMoveMemory(pDst,
  2331. pFileNameInfo->FileName,
  2332. pFileNameInfo->FileNameLength
  2333. );
  2334. pDst += pFileNameInfo->FileNameLength / sizeof(WCHAR);
  2335. }
  2336. // if nothing left, we are done
  2337. if (*p2 == UNICODE_NULL)
  2338. break;
  2339. else {
  2340. pLast = p2;
  2341. p1 = p2 + 1;
  2342. }
  2343. // get next name
  2344. p2 = p1;
  2345. if (!BaseSearchLongName_U(p2, &p1) ) {
  2346. Length = (DWORD)(p1 - pLast);
  2347. wchTotal += Length;
  2348. if (cchBuffer > wchTotal && ARGUMENT_PRESENT(lpszShortPath)) {
  2349. RtlMoveMemory(pDst, pLast, Length * sizeof(WCHAR));
  2350. pDst += Length;
  2351. }
  2352. break;
  2353. }
  2354. }
  2355. if (cchBuffer > wchTotal && ARGUMENT_PRESENT(lpszShortPath)) {
  2356. RtlMoveMemory(lpszShortPath, pLocalBuffer, wchTotal * sizeof(WCHAR));
  2357. lpszShortPath[wchTotal] = UNICODE_NULL;
  2358. uReturnVal = wchTotal;
  2359. }
  2360. else
  2361. uReturnVal = wchTotal + 1;
  2362. gsnTryExit:;
  2363. }
  2364. finally {
  2365. if (UStringNtName.Buffer != NULL)
  2366. RtlFreeUnicodeString(&UStringNtName);
  2367. if (pLocalBuffer != NULL)
  2368. RtlFreeHeap(RtlProcessHeap(), 0, pLocalBuffer);
  2369. }
  2370. return uReturnVal;
  2371. }
  2372. /**
  2373. This function search a long name(invalid dos name) in the given string.
  2374. The following characters are not valid in file name domain:
  2375. * + , : ; < = > ? [ ] |
  2376. Input: lpPathName
  2377. ppLongName
  2378. Output: FALSE if no LFN was found in the given pathname.
  2379. *ppLongName will point to the last character(should be UNICODE_NULL)
  2380. in the given pathname.
  2381. TRUE if a LFN was found. *ppLongName points to the first
  2382. character in the LFN
  2383. NOTE: space characters are valid for FAT file names. This function
  2384. will return TRUE(long name found) if space characters are found
  2385. in the given pathname.
  2386. **/
  2387. // (1). base name longer than 8 chars
  2388. // (2). extention longer than 3 chars
  2389. // (3). more than 2 dots.
  2390. // (4). two dots but not ".."
  2391. // (5). "basename."
  2392. // (6). ".ext"
  2393. // note that "basename." would never happen on win32 because
  2394. // win32 api strips the trailing '.'
  2395. #define IsInvalidDosFileName(BaseNameLen, ExtentionLen, Dots) \
  2396. (BaseNameLen > 8 || ExtentionLen > 3 || Dots > 2 || \
  2397. (Dots == 2 && (ExtentionLen + BaseNameLen)) || \
  2398. (Dots == 1 && (!BaseNameLen && ExtentionLen)) || \
  2399. (Dots == 1 && (BaseNameLen && !ExtentionLen)))
  2400. BOOL BaseSearchLongName_U(
  2401. LPCWSTR lpPathName,
  2402. LPWSTR *ppLongName
  2403. )
  2404. {
  2405. BOOL fLongNameFound, Done;
  2406. UINT BaseNameLen, ExtentionLen, Dots;
  2407. LPWSTR p;
  2408. ASSERT(lpPathName && ppLongName);
  2409. p = (LPWSTR)lpPathName;
  2410. fLongNameFound = FALSE;
  2411. *ppLongName = p;
  2412. Dots = 0;
  2413. BaseNameLen = 0;
  2414. ExtentionLen = 0;
  2415. Done = FALSE;
  2416. while (!Done && !fLongNameFound) {
  2417. switch (*p) {
  2418. case L'.':
  2419. Dots++;
  2420. p++;
  2421. break;
  2422. case L'\\':
  2423. case L'/':
  2424. if (IsInvalidDosFileName(BaseNameLen, ExtentionLen, Dots)) {
  2425. fLongNameFound = TRUE;
  2426. }
  2427. else {
  2428. *ppLongName = ++p;
  2429. // reset all counters for the next file/dir name
  2430. Dots = 0;
  2431. BaseNameLen = 0;
  2432. ExtentionLen = 0;
  2433. }
  2434. break;
  2435. case UNICODE_NULL:
  2436. if (IsInvalidDosFileName(BaseNameLen, ExtentionLen, Dots)) {
  2437. fLongNameFound = TRUE;
  2438. }
  2439. else
  2440. *ppLongName = p;
  2441. Done = TRUE;
  2442. break;
  2443. // space is a valid char on FAT volume but not on NTFS.
  2444. // we treated it like invalid one so the caller will be
  2445. // aware of it.
  2446. case L' ':
  2447. case L'*':
  2448. case L'+':
  2449. case L',':
  2450. case L':':
  2451. case L';':
  2452. case L'<':
  2453. case L'=':
  2454. case L'>':
  2455. case L'?':
  2456. case L'[':
  2457. case L']':
  2458. case L'|':
  2459. fLongNameFound = TRUE;
  2460. break;
  2461. default:
  2462. if (!Dots)
  2463. BaseNameLen++;
  2464. else
  2465. ExtentionLen++;
  2466. p++;
  2467. break;
  2468. }
  2469. }
  2470. return (fLongNameFound);
  2471. }
  2472. /**
  2473. function to create VDM environment for the new executable.
  2474. Input: lpEnvironmen = optinal environment strings prototype in UNICODE.
  2475. If it is NULL, this function use the environment
  2476. block attached to the process
  2477. pAStringEnv = pointer to a ANSI_STRING to receive the
  2478. new environment strings.
  2479. pUStringEnv = pointer to a UNICODE_STRING to receive the
  2480. new environment strings.
  2481. Output: FALSE if the creattion failed.
  2482. TRUE creation successful, pAStringEnv has been setup.
  2483. This function was provided so that BaseCheckVdm can have correct
  2484. environment(includes the newly create NTVDM process). This was done
  2485. because before command.com gets the next command, users can have
  2486. tons of things specified in config.sys and autoexec.bat which
  2487. may rely on current directory of each drive.
  2488. **/
  2489. BOOL BaseCreateVDMEnvironment(
  2490. PWCHAR lpEnvironment,
  2491. ANSI_STRING * pAStringEnv,
  2492. UNICODE_STRING *pUStringEnv
  2493. )
  2494. {
  2495. WCHAR *pEnv, *pDst, *EnvStrings,* pTmp, *pNewEnv;
  2496. DWORD cchEnv, dw, Length, dwRemain;
  2497. NTSTATUS Status;
  2498. UINT NameType;
  2499. BOOL bRet = FALSE;
  2500. if (!ARGUMENT_PRESENT(pAStringEnv) || !ARGUMENT_PRESENT(pUStringEnv)){
  2501. SetLastError(ERROR_INVALID_PARAMETER);
  2502. return FALSE;
  2503. }
  2504. try {
  2505. // the environment strings are shared by every thread of the same
  2506. // process. Since we have no idea of what the caller process
  2507. // is, we have to grab the entire environment to our local buffer in one
  2508. // shot then we can walk through the strings.
  2509. // Note that if another thread makes call to RtlSetEnvironmentVariable
  2510. // then we are out of sync. It is a problem of process structure and
  2511. // I don't want to think about it now.
  2512. // The funny thing is that we have to assume the environment
  2513. // is a block of strings(otherwise, how can we do it?)t, nothing more and
  2514. // nothing less. If someday and somebody dares to change it, he will be
  2515. // the one to blame. If the caller(CreateProcess)
  2516. // provides the environment, we assume it is safe to walk through it.
  2517. //
  2518. if (lpEnvironment == NULL) {
  2519. // create a new environment and inherit the current process env
  2520. Status = RtlCreateEnvironment(TRUE, (PVOID *)&EnvStrings);
  2521. if (!NT_SUCCESS(Status))
  2522. goto bveTryExit;
  2523. }
  2524. else
  2525. EnvStrings = lpEnvironment;
  2526. if (EnvStrings == NULL) {
  2527. SetLastError(ERROR_BAD_ENVIRONMENT);
  2528. goto bveTryExit;
  2529. }
  2530. // figure out how long the environment is
  2531. // why can Rtl just provides such a function for us?
  2532. //
  2533. cchEnv = 0;
  2534. pEnv = EnvStrings;
  2535. // environment is double-null terminated
  2536. while (!(*pEnv++ == UNICODE_NULL && *pEnv == UNICODE_NULL))
  2537. cchEnv++;
  2538. // count the last two NULLs
  2539. cchEnv += 2;
  2540. // we don't want to change the original environment, so
  2541. // make a local buffer for it.
  2542. pNewEnv = (LPWSTR)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2543. (cchEnv + MAX_PATH) * sizeof(WCHAR));
  2544. if (pNewEnv == NULL) {
  2545. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2546. goto bveTryExit;
  2547. }
  2548. // give the last two for null
  2549. dwRemain = MAX_PATH - 2;
  2550. // now walk through the environment string
  2551. pEnv = EnvStrings;
  2552. // the new environmet will be
  2553. pDst = pNewEnv;
  2554. while (*pEnv != UNICODE_NULL) {
  2555. pTmp = pEnv;
  2556. // current directory environment has the form as:
  2557. // "=d:=d:\pathname" where d: is the drive designator.
  2558. if (pEnv[0] == (WCHAR) '=' ) {
  2559. if (((pEnv[1] >= (WCHAR) 'A' && pEnv[1] <= (WCHAR) 'Z') ||
  2560. (pEnv[1] >= (WCHAR) 'a' && pEnv[1] <= (WCHAR) 'z')) &&
  2561. pEnv[2] == (WCHAR) ':' &&
  2562. pEnv[3] == (WCHAR) '=') {
  2563. // copy the name and the '='
  2564. *pDst++ = *pEnv++;*pDst++ = *pEnv++;
  2565. *pDst++ = *pEnv++;*pDst++ = *pEnv++;
  2566. // current dir is single path
  2567. NameType = ENV_NAME_TYPE_SINGLE_PATH;
  2568. }
  2569. else {
  2570. // a weird environment was detected.
  2571. // treat it as no path
  2572. NameType = ENV_NAME_TYPE_NO_PATH;
  2573. }
  2574. }
  2575. else {
  2576. // copy down the name and the '='
  2577. while (*pEnv && (*pDst++ = *pEnv++) != (WCHAR) '=')
  2578. ;
  2579. // and check the type
  2580. NameType = BaseGetEnvNameType_U(pTmp, (DWORD)(pEnv - pTmp) - 1);
  2581. }
  2582. if (NameType == ENV_NAME_TYPE_NO_PATH) {
  2583. while ((*pDst++ = *pEnv++) != UNICODE_NULL)
  2584. ;
  2585. }
  2586. else if (NameType == ENV_NAME_TYPE_SINGLE_PATH) {
  2587. Length = wcslen(pEnv) + 1;
  2588. dw = GetShortPathNameW(pEnv, pDst, Length + dwRemain);
  2589. // if the conversion failed, we simply pass down the original
  2590. // one no matter what the reason is. This is done because we
  2591. // are doing the environment strings.
  2592. if (dw == 0 || dw >= Length + dwRemain){
  2593. RtlMoveMemory(pDst, pEnv, Length * sizeof(WCHAR));
  2594. dw = Length - 1;
  2595. }
  2596. pDst += dw + 1;
  2597. pEnv += Length;
  2598. if (dw > Length)
  2599. dwRemain -= dw - Length;
  2600. }
  2601. else {
  2602. // multiple path name found.
  2603. // the character ';' is used for seperator
  2604. pTmp = pEnv;
  2605. while(*pEnv != UNICODE_NULL) {
  2606. if (*pEnv == (WCHAR) ';') {
  2607. // length not include the ';'
  2608. Length = (DWORD)(pEnv - pTmp);
  2609. if (Length > 0) {
  2610. *pEnv = UNICODE_NULL;
  2611. dw = GetShortPathNameW(pTmp, pDst, Length + 1 + dwRemain);
  2612. // again, if the conversion failed, use the original one
  2613. if (dw == 0 || dw > Length + dwRemain) {
  2614. RtlMoveMemory(pDst, pTmp, Length * sizeof(WCHAR));
  2615. dw = Length;
  2616. }
  2617. pDst += dw;
  2618. *pDst++ = *pEnv++ = (WCHAR)';';
  2619. if (dw > Length)
  2620. dwRemain -= dw - Length;
  2621. }
  2622. // skip all consecutive ';'
  2623. while (*pEnv == (WCHAR) ';')
  2624. *pDst++ = *pEnv++;
  2625. pTmp = pEnv;
  2626. }
  2627. else
  2628. pEnv++;
  2629. }
  2630. // convert the last one
  2631. if ((Length = (DWORD)(pEnv - pTmp)) != 0) {
  2632. dw = GetShortPathNameW(pTmp, pDst, Length+1 + dwRemain);
  2633. if (dw == 0 || dw > Length) {
  2634. RtlMoveMemory(pDst, pTmp, Length * sizeof(WCHAR));
  2635. dw = Length;
  2636. }
  2637. pDst += dw;
  2638. if (dw > Length)
  2639. dwRemain -= dw - Length;
  2640. }
  2641. *pDst++ = *pEnv++;
  2642. }
  2643. }
  2644. *pDst++ = UNICODE_NULL;
  2645. cchEnv = (DWORD) pDst - (DWORD)pNewEnv;
  2646. pUStringEnv->MaximumLength = pUStringEnv->Length = (USHORT)cchEnv;
  2647. pUStringEnv->Buffer = pNewEnv;
  2648. Status = RtlUnicodeStringToAnsiString(pAStringEnv,
  2649. pUStringEnv,
  2650. TRUE
  2651. );
  2652. if (!NT_SUCCESS(Status)) {
  2653. BaseSetLastNTError(Status);
  2654. }
  2655. else
  2656. bRet = TRUE;
  2657. bveTryExit:;
  2658. }
  2659. finally {
  2660. if (lpEnvironment == NULL && EnvStrings != NULL)
  2661. RtlDestroyEnvironment(EnvStrings);
  2662. }
  2663. return bRet;
  2664. }
  2665. /**
  2666. Destroy the environment block created by BaseCreateVDMEnvironment
  2667. Input: ANSI_STRING * pAnsiStringVDMEnv
  2668. Environment block in ANSI, should be freed via
  2669. RtlFreeAnsiString
  2670. UNICODE_STRING * pUnicodeStringEnv
  2671. Environment block in UNICODE. The Buffer should
  2672. be freed with RtlFreeHeap.
  2673. Output: should always be TRUE.
  2674. **/
  2675. BOOL
  2676. BaseDestroyVDMEnvironment(
  2677. ANSI_STRING *pAStringEnv,
  2678. UNICODE_STRING *pUStringEnv
  2679. )
  2680. {
  2681. if (pAStringEnv->Buffer)
  2682. RtlFreeAnsiString(pAStringEnv);
  2683. if (pUStringEnv->Buffer)
  2684. RtlFreeHeap(RtlProcessHeap(), 0, pUStringEnv->Buffer);
  2685. return TRUE;
  2686. }
  2687. /**
  2688. This function returns the name type of the given environment variable name
  2689. The name type has three possibilities. Each one represents if the
  2690. given name can have pathnames as its value.
  2691. ENV_NAME_TYPE_NO_PATH: no pathname can be its value
  2692. ENV_NAME_TYPE_SINGLE_PATH: single pathname
  2693. ENV_NAME_MULTIPLE_PATH: multiple path
  2694. SIDE NOTE:
  2695. Currently, nt can not installed on a long path and it seems
  2696. that systemroot and windir are never be in long path.
  2697. **/
  2698. UINT
  2699. BaseGetEnvNameType_U(WCHAR * Name, DWORD NameLength)
  2700. {
  2701. // so far we only take care of three predefined names:
  2702. // PATH
  2703. // WINDIR and
  2704. // SYSTEMROOT.
  2705. //
  2706. static ENV_INFO EnvInfoTable[STD_ENV_NAME_COUNT] = {
  2707. {ENV_NAME_TYPE_MULTIPLE_PATH, 4, ENV_NAME_PATH},
  2708. {ENV_NAME_TYPE_SINGLE_PATH, 6, ENV_NAME_WINDIR},
  2709. {ENV_NAME_TYPE_SINGLE_PATH, 10, ENV_NAME_SYSTEMROOT}
  2710. };
  2711. UINT NameType;
  2712. int i;
  2713. NameType = ENV_NAME_TYPE_NO_PATH;
  2714. for (i = 0; i < STD_ENV_NAME_COUNT; i++) {
  2715. if (EnvInfoTable[i].NameLength == NameLength &&
  2716. !_wcsnicmp(EnvInfoTable[i].Name, Name, NameLength)) {
  2717. NameType = EnvInfoTable[i].NameType;
  2718. break;
  2719. }
  2720. }
  2721. return NameType;
  2722. }