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.

914 lines
26 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. ntvdm64.c
  5. Abstract:
  6. Support for 16-bit process thunking on NT64
  7. Author:
  8. 12-Jan-1999 PeterHal
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <wow64t.h>
  16. #include <shlobj.h>
  17. #include <stdio.h>
  18. #define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))
  19. #if DBG
  20. #define DEBUG_PRINT(args) DbgPrint args
  21. #else
  22. #define DEBUG_PRINT(args)
  23. #endif
  24. typedef struct {
  25. LPCWSTR Name;
  26. LPCWSTR Version;
  27. LPCWSTR ProdName;
  28. LPCWSTR CmdLine;
  29. LPCWSTR MappedExe;
  30. } NTVDM64_ENTRY;
  31. typedef CONST NTVDM64_ENTRY *PNTVDM64_ENTRY;
  32. CONST NTVDM64_ENTRY NtVdm64Entries[] = {
  33. {L"ACMSETUP301", L"3.01", L"Microsoft Setup for Windows", L"-m \"%m\" %c", L"setup16.exe"},
  34. {L"ACMSETUP30", L"3.0", L"Microsoft Setup for Windows", L"-m \"%m\" %c", L"setup16.exe"},
  35. {L"ACMSETUP26", L"2.6", L"Microsoft Setup for Windows", L"-m \"%m\" %c", L"setup16.exe"},
  36. {L"ACMSETUP12", L"1.2", L"Microsoft Setup for Windows", L"-m \"%m\" %c", L"setup16.exe"},
  37. {L"INSTALLSHIELD5", L"5*", L"InstallShield*", L"-isw64\"%m\" %c", L"InstallShield\\setup.exe"}
  38. };
  39. #if !_WIN64
  40. CONST int CsidlList[] = {
  41. CSIDL_COMMON_STARTMENU,
  42. CSIDL_COMMON_PROGRAMS,
  43. CSIDL_COMMON_STARTUP,
  44. CSIDL_COMMON_DESKTOPDIRECTORY,
  45. CSIDL_COMMON_APPDATA,
  46. CSIDL_COMMON_TEMPLATES,
  47. CSIDL_COMMON_DOCUMENTS,
  48. CSIDL_COMMON_ADMINTOOLS,
  49. CSIDL_COMMON_FAVORITES
  50. };
  51. #endif
  52. LONG
  53. CreateNtvdm64Entry(
  54. HKEY hKeyVdm,
  55. PNTVDM64_ENTRY Entry
  56. )
  57. /*++
  58. Routine Description:
  59. Write a registry entry for a single entry in the table
  60. Arguments:
  61. hKeyVdm - key to write the entry to
  62. Entry - the entry to write
  63. Return Value:
  64. LONG - a return code from a Registry API, 0 for success
  65. --*/
  66. {
  67. LONG l;
  68. HKEY h;
  69. WCHAR Path[MAX_PATH];
  70. if (!GetSystemWindowsDirectoryW(Path, sizeof(Path)/sizeof(Path[0]))) {
  71. return 1;
  72. }
  73. if ((lstrlenW(Path) + (sizeof (L"\\" WOW64_SYSTEM_DIRECTORY_U L"\\") / sizeof(WCHAR))) >= (sizeof(Path)/sizeof(Path[0]))) {
  74. return 1;
  75. }
  76. wcscat(Path, L"\\" WOW64_SYSTEM_DIRECTORY_U L"\\");
  77. if ((lstrlenW(Path) + lstrlenW(Entry->MappedExe)) >= (sizeof(Path)/sizeof(Path[0]))) {
  78. return 1;
  79. }
  80. wcscat(Path, Entry->MappedExe);
  81. l = RegCreateKeyW(hKeyVdm, Entry->Name, &h);
  82. if (l) {
  83. return l;
  84. }
  85. l = RegSetValueExW(h, L"CommandLine", 0, REG_SZ, (BYTE *)Entry->CmdLine, (wcslen(Entry->CmdLine)+1)*sizeof(WCHAR));
  86. if (l) {
  87. return l;
  88. }
  89. l = RegSetValueExW(h, L"ProductName", 0, REG_SZ, (BYTE *)Entry->ProdName, (wcslen(Entry->ProdName)+1)*sizeof(WCHAR));
  90. if (l) {
  91. return l;
  92. }
  93. l = RegSetValueExW(h, L"ProductVersion", 0, REG_SZ, (BYTE *)Entry->Version, (wcslen(Entry->Version)+1)*sizeof(WCHAR));
  94. if (l) {
  95. return l;
  96. }
  97. l = RegSetValueExW(h, L"MappedExeName", 0, REG_SZ, (BYTE *)Path, (wcslen(Path)+1)*sizeof(WCHAR));
  98. return l;
  99. }
  100. STDAPI
  101. DllInstall(
  102. BOOL bInstall,
  103. LPCWSTR pszCmdLine
  104. )
  105. /*++
  106. Routine Description:
  107. Routine called during guimode setup to register ntvdm64.dll
  108. Arguments:
  109. bInstall - TRUE if registering, FALSE if unregistering
  110. pszCmdLine - command-line
  111. Return Value:
  112. HRESULT
  113. --*/
  114. {
  115. HKEY hKeyVdm;
  116. LONG l;
  117. SIZE_T i;
  118. WCHAR Path[MAX_PATH];
  119. BOOL bResult;
  120. UNREFERENCED_PARAMETER(pszCmdLine);
  121. if (!bInstall) {
  122. // There is no uninstall for ntvdm64
  123. return NOERROR;
  124. }
  125. l = RegCreateKeyW(HKEY_LOCAL_MACHINE,
  126. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NtVdm64",
  127. &hKeyVdm);
  128. if (l) {
  129. return E_FAIL;
  130. }
  131. for (i=0; i<ARRAYSIZE(NtVdm64Entries); ++i) {
  132. l = CreateNtvdm64Entry(hKeyVdm, &NtVdm64Entries[i]);
  133. if (l) {
  134. break;
  135. }
  136. }
  137. RegCloseKey(hKeyVdm);
  138. if (l) {
  139. return E_FAIL;
  140. }
  141. #if !_WIN64
  142. //
  143. // Call shell32, asking for some common CSIDL_ values. This forces
  144. // shell32 to create values under HKLM\Software\Microsoft\Windows\
  145. // Explorere\Shell Folders. Some apps (VB, VC, MSDN) expect these
  146. // values to be present in the registry, but they are created on-demand
  147. // as a side-effect of calling the shell APIs to query for them. On x86
  148. // NT, guimode setup itself calls shell32 several times, while creating
  149. // the Start Menu, etc. so several values are always present when apps
  150. // run for the first time.
  151. //
  152. for (i=0; i<sizeof(CsidlList)/sizeof(CsidlList[0]); ++i) {
  153. bResult = SHGetSpecialFolderPathW(NULL, Path, CsidlList[i], TRUE);
  154. if (!bResult) {
  155. return E_FAIL;
  156. }
  157. }
  158. #endif
  159. return NOERROR;
  160. }
  161. //-----------------------------------------------------------------------
  162. // This section is ripped off from mvdm\wow32\wkman.c
  163. //
  164. // MyVerQueryValue checks several popular code page values for the given
  165. // string. This may need to be extended ala WinFile's wfdlgs2.c to search
  166. // the translation table. For now we only need a few.
  167. //
  168. BOOL
  169. MyVerQueryValue(
  170. const LPVOID pBlock,
  171. LPWSTR lpName,
  172. LPVOID * lplpBuffer,
  173. PUINT puLen
  174. )
  175. {
  176. DWORD dwDefaultLanguage[] = {0x04E40409, 0x00000409};
  177. WCHAR szSubBlock[128];
  178. PDWORD pdwTranslation;
  179. DWORD uLen;
  180. BOOL fRet;
  181. int i;
  182. if(!VerQueryValue(pBlock, "\\VarFileInfo\\Translation", (PVOID*)&pdwTranslation, &uLen)) {
  183. pdwTranslation = dwDefaultLanguage;
  184. uLen = sizeof (dwDefaultLanguage);
  185. }
  186. fRet = FALSE;
  187. while ((uLen > 0) && !fRet) {
  188. swprintf(szSubBlock, L"\\StringFileInfo\\%04X%04X\\%ws",
  189. LOWORD(*pdwTranslation),
  190. HIWORD(*pdwTranslation),
  191. lpName);
  192. fRet = VerQueryValueW(pBlock, szSubBlock, lplpBuffer, puLen);
  193. pdwTranslation++;
  194. uLen -= sizeof (DWORD);
  195. }
  196. if (!fRet) {
  197. DEBUG_PRINT(("NtVdm64: Failed to get resource %ws.\n", lpName));
  198. }
  199. return fRet;
  200. }
  201. //
  202. // Utility routine to fetch the Product Name and Product Version strings
  203. // from a given EXE.
  204. //
  205. BOOL
  206. WowGetProductNameVersion(
  207. LPCWSTR pszExePath,
  208. LPWSTR pszProductName,
  209. DWORD cbProductName,
  210. LPWSTR pszProductVersion,
  211. DWORD cbProductVersion
  212. )
  213. {
  214. DWORD dwZeroMePlease;
  215. DWORD cbVerInfo;
  216. LPVOID lpVerInfo = NULL;
  217. LPWSTR pName;
  218. DWORD cbName;
  219. LPWSTR pVersion;
  220. DWORD cbVersion;
  221. *pszProductName = 0;
  222. *pszProductVersion = 0;
  223. cbVerInfo = GetFileVersionInfoSizeW((LPWSTR)pszExePath, &dwZeroMePlease);
  224. if (!cbVerInfo) {
  225. return TRUE;
  226. }
  227. lpVerInfo = RtlAllocateHeap( RtlProcessHeap(), 0, (cbVerInfo));
  228. if (!lpVerInfo) {
  229. DEBUG_PRINT(("NtVdm64: Failed to allocate version info.\n"));
  230. return FALSE;
  231. }
  232. if (!GetFileVersionInfoW((LPWSTR)pszExePath, 0, cbVerInfo, lpVerInfo)) {
  233. DEBUG_PRINT(("NtVdm64: Failed to get version info. GLE %x\n", GetLastError()));
  234. return FALSE;
  235. }
  236. if (MyVerQueryValue(lpVerInfo, L"ProductName", &pName, &cbName)) {
  237. if (cbName <= cbProductName) {
  238. wcscpy(pszProductName, pName);
  239. } else {
  240. DEBUG_PRINT(("NtVdm64: ProductName resource too large %ws. Size %x\n", pName, cbName));
  241. }
  242. }
  243. if (MyVerQueryValue(lpVerInfo, L"ProductVersion", &pVersion, &cbVersion)) {
  244. if (cbVersion <= cbProductVersion) {
  245. wcscpy(pszProductVersion, pVersion);
  246. } else {
  247. DEBUG_PRINT(("NtVdm64: ProductVersion resource too large %ws. Size %x\n", pVersion, cbVersion));
  248. }
  249. }
  250. RtlFreeHeap(RtlProcessHeap(), 0, lpVerInfo);
  251. return TRUE;
  252. }
  253. //-----------------------------------------------------------------------
  254. BOOL
  255. MapCommandLine(
  256. HKEY hkeyMapping,
  257. LPCWSTR lpWin16ApplicationName,
  258. LPCWSTR lpMappedApplicationName,
  259. BOOL fPrefixMappedApplicationName,
  260. LPCWSTR lpCommandLine,
  261. LPWSTR *lplpMappedCommandLine
  262. )
  263. /*++
  264. Routine Description:
  265. Maps the command line for a Win16 application.
  266. Arguments:
  267. hkeyMapping - open registry keyfor the mapping entry
  268. lpWin16ApplicationName - Win16 file name (with path)
  269. lpMappedApplicationName - the ported version
  270. of lpWin16ApplicationName
  271. fPrefixMappedApplicationName
  272. - TRUE means that the original lpApplicationName was NULL.
  273. The application name was stripped from the head of
  274. lpCommandLine.
  275. The mapped application name needs to be added to the
  276. head of the mapped command line.
  277. - FALSE means that the original lpAPplicationName was non-NULL.
  278. the lpCommandLine argument is identical to the original
  279. lpCommandLine argument.
  280. lpCommandLine - see comment for fPrefixMappedApplicationName.
  281. lplpMappedCommandLine - returns the mapped command line
  282. caller must free the returned pointer using RtlFreeHeap
  283. Return Value:
  284. TRUE if the mapping was successful
  285. --*/
  286. {
  287. WCHAR achBuffer[MAX_PATH+1];
  288. DWORD dwBufferLength;
  289. DWORD dwType;
  290. LPWSTR lpsz;
  291. LPWSTR lpMappedCommandLine;
  292. DWORD dwRequiredBufferLength;
  293. LONG result;
  294. LPCWSTR lpOriginalCommandLine;
  295. // set default command line to empty string
  296. if (NULL == lpCommandLine) {
  297. lpCommandLine = L"";
  298. }
  299. lpOriginalCommandLine = lpCommandLine;
  300. // get the command line map from the registry
  301. dwBufferLength = ARRAYSIZE(achBuffer);
  302. result = RegQueryValueExW(hkeyMapping, L"CommandLine", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
  303. if (ERROR_SUCCESS != result || dwType != REG_SZ) {
  304. DEBUG_PRINT(("NtVdm64: CommandLine failed to get REG_SZ value. Result %x Type %x\n", result, dwType));
  305. return FALSE;
  306. }
  307. // calculate mapped buffer size and allocate it
  308. dwRequiredBufferLength = 1;
  309. if (fPrefixMappedApplicationName) {
  310. dwRequiredBufferLength += wcslen(lpMappedApplicationName) + 1;
  311. } else {
  312. while (*lpCommandLine && *lpCommandLine != L' ') {
  313. dwRequiredBufferLength++;
  314. lpCommandLine++;
  315. }
  316. // consume any extra spaces
  317. while (*lpCommandLine == L' ') {
  318. lpCommandLine++;
  319. }
  320. // account for one space in the output buffer
  321. dwRequiredBufferLength++;
  322. }
  323. lpsz = achBuffer;
  324. while (*lpsz) {
  325. if (*lpsz == L'%') {
  326. lpsz += 1;
  327. switch (*lpsz) {
  328. // %c : Insert Original Command Line
  329. case L'c':
  330. case L'C':
  331. lpsz += 1;
  332. dwRequiredBufferLength += wcslen(lpCommandLine);
  333. break;
  334. // %m : Insert Original Module Name
  335. case L'm':
  336. case L'M':
  337. lpsz += 1;
  338. dwRequiredBufferLength += wcslen(lpWin16ApplicationName);
  339. break;
  340. // %% : Insert a real %
  341. case L'%':
  342. lpsz += 1;
  343. dwRequiredBufferLength += 1;
  344. break;
  345. // %\0 : eat terminating %\0
  346. case 0:
  347. DEBUG_PRINT(("NtVdm64: ignoring trailing %% in CommandLine.\n"));
  348. break;
  349. // %x : undefined macro expands to nothing
  350. default:
  351. DEBUG_PRINT(("NtVdm64: ignoring unknown macro %%%wc in CommandLine.\n", *lpsz));
  352. lpsz += 1;
  353. break;
  354. }
  355. } else {
  356. lpsz += 1;
  357. dwRequiredBufferLength += 1;
  358. }
  359. }
  360. *lplpMappedCommandLine = RtlAllocateHeap(RtlProcessHeap(), 0, dwRequiredBufferLength * sizeof (WCHAR));
  361. if (!*lplpMappedCommandLine) {
  362. DEBUG_PRINT(("NtVdm64: failed to allocate CommandLine. GLE %x.\n", GetLastError()));
  363. return FALSE;
  364. }
  365. // map the buffer
  366. lpCommandLine = lpOriginalCommandLine;
  367. lpsz = achBuffer;
  368. lpMappedCommandLine = *lplpMappedCommandLine;
  369. if (fPrefixMappedApplicationName) {
  370. wcscpy(lpMappedCommandLine, lpMappedApplicationName);
  371. lpMappedCommandLine += wcslen(lpMappedApplicationName);
  372. *lpMappedCommandLine = L' ';
  373. lpMappedCommandLine += 1;
  374. } else {
  375. // copy in the first whitespace-delimited part of the old
  376. // command-line as it is the name of the app.
  377. while (*lpCommandLine && *lpCommandLine != L' ') {
  378. *lpMappedCommandLine = *lpCommandLine;
  379. lpMappedCommandLine++;
  380. lpCommandLine++;
  381. }
  382. // add in a space of padding and skip over any spaces in the
  383. // original command line
  384. *lpMappedCommandLine++ = L' ';
  385. while (*lpCommandLine == L' ') {
  386. lpCommandLine++;
  387. }
  388. }
  389. while (*lpsz) {
  390. if (*lpsz == L'%') {
  391. lpsz += 1;
  392. switch (*lpsz) {
  393. // %c : Insert Original Command Line
  394. case L'c':
  395. case L'C':
  396. lpsz += 1;
  397. wcscpy(lpMappedCommandLine, lpCommandLine);
  398. lpMappedCommandLine += wcslen(lpCommandLine);
  399. break;
  400. // %m : Insert Original Module Name
  401. case L'm':
  402. case L'M':
  403. lpsz += 1;
  404. wcscpy(lpMappedCommandLine, lpWin16ApplicationName);
  405. lpMappedCommandLine += wcslen(lpWin16ApplicationName);
  406. break;
  407. // %% : Insert a real %
  408. case L'%':
  409. lpsz += 1;
  410. *lpMappedCommandLine = L'%';
  411. lpMappedCommandLine += 1;
  412. break;
  413. // %\0 : eat terminating %\0
  414. case 0:
  415. break;
  416. // %x : undefined macro expands to nothing
  417. default:
  418. lpsz += 1;
  419. break;
  420. }
  421. } else {
  422. *lpMappedCommandLine = *lpsz;
  423. lpMappedCommandLine += 1;
  424. lpsz += 1;
  425. }
  426. }
  427. *lpMappedCommandLine = L'\0';
  428. return TRUE;
  429. }
  430. int
  431. CompareStrings(
  432. LPWSTR lpRegString,
  433. LPCWSTR lpExeString
  434. )
  435. /*++
  436. Routine Description:
  437. Compares strings using a minimal wildcard support in addition
  438. to just a stock wcscmp. The RegString can have an optional '*'
  439. which is used as a wildcard that matches any characters upto the
  440. end of the string.
  441. Arguments:
  442. lpRegString - string loaded from the registry
  443. lpExeString - string loaded from the app's resource section
  444. Return Value:
  445. same as wcscmp: 0 for equal, nonzero non-equal
  446. --*/
  447. {
  448. LPCWSTR pRegStar;
  449. if (wcscmp(lpRegString, lpExeString) == 0) {
  450. // an exact match
  451. return 0;
  452. }
  453. // not an exact match - see if the registry key contains a wildcard
  454. pRegStar = wcschr(lpRegString, L'*');
  455. if (!pRegStar) {
  456. // No wildcard in the registry key, so no match
  457. return -1;
  458. }
  459. if (pRegStar == lpRegString) {
  460. // Wildcard is the first character - match everything
  461. return 0;
  462. }
  463. // Compare only upto the character before the '*'
  464. return wcsncmp(lpRegString, lpExeString,
  465. pRegStar - lpRegString);
  466. }
  467. BOOL
  468. CheckMapArguments(
  469. HKEY hkeyMapping,
  470. LPCWSTR lpApplicationName,
  471. LPCWSTR lpProductName,
  472. LPCWSTR lpProductVersion,
  473. LPWSTR lpMappedApplicationName,
  474. DWORD dwMappedApplicationNameSize,
  475. BOOL fPrefixMappedApplicationName,
  476. LPCWSTR lpCommandLine,
  477. LPWSTR *lplpMappedCommandLine
  478. )
  479. /*++
  480. Routine Description:
  481. Attempts to map a Win16 application and command line to their ported version
  482. using a single entry in the NtVdm64 mapping in the registry.
  483. Arguments:
  484. hkeyMapping - open registry keyfor the mapping entry
  485. lpApplicationName - Win16 file name (with path)
  486. lpExeName - Win16 file name wihtout path
  487. lpProductName - value of ProductName Version resource of lpApplicationName
  488. lpProductVersion - value of ProductVersion version resource of lpApplicationName
  489. lpMappedApplicationName - returns the name of the ported version
  490. of lpApplicationName
  491. dwMappedApplicationNameSize - size of lpMappedApplicationName buffer
  492. fPrefixMappedApplicationName
  493. - TRUE means that the original lpApplicationName was NULL.
  494. The application name was stripped from the head of
  495. lpCommandLine.
  496. The mapped application name needs to be added to the
  497. head of the mapped command line.
  498. - FALSE means that the original lpAPplicationName was non-NULL.
  499. the lpCommandLine argument is identical to the original
  500. lpCommandLine argument.
  501. lpCommandLine - see comment for fPrefixMappedApplicationName.
  502. lplpMappedCommandLine - returns the mapped command line
  503. caller must free the returned pointer using RtlFreeHeap
  504. Return Value:
  505. TRUE if the mapping was successful
  506. --*/
  507. {
  508. WCHAR achBuffer[MAX_PATH+1];
  509. DWORD dwBufferLength;
  510. DWORD dwType;
  511. LONG result;
  512. dwBufferLength = ARRAYSIZE(achBuffer);
  513. result = RegQueryValueExW(hkeyMapping, L"ProductName", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
  514. if (ERROR_SUCCESS != result || dwType != REG_SZ) {
  515. DEBUG_PRINT(("NtVdm64: Failed to open ProductName REG_SZ key. Result %x. Type %x\n", result, dwType));
  516. return FALSE;
  517. }
  518. if (CompareStrings(achBuffer, lpProductName)) {
  519. DEBUG_PRINT(("NtVdm64: ProductName mismatch %ws vs %ws\n", achBuffer, lpProductName));
  520. return FALSE;
  521. }
  522. dwBufferLength = ARRAYSIZE(achBuffer);
  523. result = RegQueryValueExW(hkeyMapping, L"ProductVersion", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
  524. if (ERROR_SUCCESS != result || dwType != REG_SZ) {
  525. DEBUG_PRINT(("NtVdm64: Failed to open ProductVersion REG_SZ key. Result %x. Type %x\n", result, dwType));
  526. return FALSE;
  527. }
  528. if (CompareStrings(achBuffer, lpProductVersion)) {
  529. DEBUG_PRINT(("NtVdm64: ProductVersion mismatch %ws vs %ws\n", achBuffer, lpProductVersion));
  530. return FALSE;
  531. }
  532. dwBufferLength = ARRAYSIZE(achBuffer);
  533. result = RegQueryValueExW(hkeyMapping, L"MappedExeName", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
  534. if (ERROR_SUCCESS != result) {
  535. DEBUG_PRINT(("NtVdm64: Failed to open MappedExeName REG_SZ key. Result %x.\n", result));
  536. return FALSE;
  537. }
  538. if (dwType == REG_EXPAND_SZ) {
  539. WCHAR achBuffer2[MAX_PATH+1];
  540. wcscpy(achBuffer2, achBuffer);
  541. dwBufferLength = ExpandEnvironmentStringsW(achBuffer2, achBuffer, ARRAYSIZE(achBuffer));
  542. if (dwBufferLength == 0 || dwBufferLength > ARRAYSIZE(achBuffer)) {
  543. DEBUG_PRINT(("NtVdm64: MappedExeName failed to expand environment strings in %ws. Length %x\n", achBuffer, dwBufferLength));
  544. return FALSE;
  545. }
  546. } else if (dwType != REG_SZ) {
  547. DEBUG_PRINT(("NtVdm64: MappedExeName value doesn't have string type. Type %x\n", dwType));
  548. return FALSE;
  549. }
  550. if (dwBufferLength > dwMappedApplicationNameSize) {
  551. DEBUG_PRINT(("NtVdm64: MappedExeName too long. Length %x\n", dwBufferLength));
  552. return FALSE;
  553. }
  554. wcscpy(lpMappedApplicationName, achBuffer);
  555. if (!MapCommandLine(hkeyMapping, lpApplicationName, lpMappedApplicationName, fPrefixMappedApplicationName, lpCommandLine, lplpMappedCommandLine)) {
  556. return FALSE;
  557. }
  558. return TRUE;
  559. }
  560. BOOL
  561. MapArguments(
  562. LPCWSTR lpApplicationName,
  563. LPWSTR lpMappedApplicationName,
  564. DWORD dwMappedApplicationNameSize,
  565. BOOL fPrefixMappedApplicationName,
  566. LPCWSTR lpCommandLine,
  567. LPWSTR *lplpMappedCommandLine
  568. )
  569. /*++
  570. Routine Description:
  571. Maps a Win16 application and command line to their ported version
  572. using the NtVdm64 mapping in the registry.
  573. Arguments:
  574. lpApplicationName - Win16 file name not optional
  575. lpMappedApplicationName - returns the name of the ported version
  576. of lpApplicationName
  577. dwMappedApplicationNameSize - size of lpMappedApplicationName buffer
  578. fPrefixMappedApplicationName
  579. - TRUE means that the original lpApplicationName was NULL.
  580. The application name was stripped from the head of
  581. lpCommandLine.
  582. The mapped application name needs to be added to the
  583. head of the mapped command line.
  584. - FALSE means that the original lpAPplicationName was non-NULL.
  585. the lpCommandLine argument is identical to the original
  586. lpCommandLine argument.
  587. lpCommandLine - see comment for fPrefixMappedApplicationName.
  588. lplpMappedCommandLine - returns the mapped command line
  589. caller must free the returned pointer using RtlFreeHeap
  590. Return Value:
  591. TRUE if the mapping was successful
  592. --*/
  593. {
  594. HKEY hkeyMappingRoot;
  595. LONG result;
  596. DWORD dwIndex;
  597. WCHAR achSubKeyName[MAX_PATH+1];
  598. DWORD dwSubKeyNameLength;
  599. BOOL mapped;
  600. WCHAR achExeNameBuffer[MAX_PATH+1];
  601. LPWSTR lpExeName;
  602. WCHAR achProductName[MAX_PATH+1];
  603. WCHAR achProductVersion[MAX_PATH+1];
  604. //
  605. // get the .exe name without the preceding path
  606. //
  607. if (0 == SearchPathW(
  608. NULL,
  609. lpApplicationName,
  610. (PWSTR)L".exe",
  611. MAX_PATH,
  612. achExeNameBuffer,
  613. &lpExeName
  614. )) {
  615. DEBUG_PRINT(("NtVdm64: SearchPathW failed: %ws\n", lpApplicationName));
  616. return FALSE;
  617. }
  618. if (!WowGetProductNameVersion(lpApplicationName,
  619. achProductName,
  620. ARRAYSIZE(achProductName),
  621. achProductVersion,
  622. ARRAYSIZE(achProductVersion))) {
  623. return FALSE;
  624. }
  625. mapped = FALSE;
  626. result = RegOpenKeyW(HKEY_LOCAL_MACHINE,
  627. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NtVdm64",
  628. &hkeyMappingRoot
  629. );
  630. if (ERROR_SUCCESS != result) {
  631. DEBUG_PRINT(("NtVdm64: Failed to Open NtVdm64 Registry Key : %x\n", result));
  632. return FALSE;
  633. }
  634. dwIndex = 0;
  635. dwSubKeyNameLength = ARRAYSIZE(achSubKeyName);
  636. while (!mapped && ERROR_SUCCESS == (result = RegEnumKeyW(hkeyMappingRoot, dwIndex, achSubKeyName, dwSubKeyNameLength))) {
  637. HKEY hkeyMapping;
  638. result = RegOpenKeyW(hkeyMappingRoot, achSubKeyName, &hkeyMapping);
  639. if (ERROR_SUCCESS == result) {
  640. mapped = CheckMapArguments(hkeyMapping,
  641. lpApplicationName,
  642. achProductName,
  643. achProductVersion,
  644. lpMappedApplicationName,
  645. dwMappedApplicationNameSize,
  646. fPrefixMappedApplicationName,
  647. lpCommandLine,
  648. lplpMappedCommandLine);
  649. RegCloseKey(hkeyMapping);
  650. }
  651. dwSubKeyNameLength = ARRAYSIZE(achSubKeyName);
  652. dwIndex += 1;
  653. }
  654. RegCloseKey(hkeyMappingRoot);
  655. if ( !mapped )
  656. DEBUG_PRINT(("NtVdm64: Unknown 16bit app or given parameters are wrong\n"));
  657. return mapped;
  658. }
  659. extern
  660. BOOL STDAPICALLTYPE ApphelpCheckExe(
  661. LPCWSTR lpApplicationName,
  662. BOOL bApphelp,
  663. BOOL bShim,
  664. BOOL bUseModuleName);
  665. BOOL
  666. CheckAppCompat(
  667. LPCWSTR lpApplicationName
  668. )
  669. /*++
  670. Check application compatibility database for blocked application,
  671. possibly show UI advising user of a problem
  672. --*/
  673. {
  674. return ApphelpCheckExe(lpApplicationName,
  675. TRUE,
  676. FALSE,
  677. FALSE);
  678. }
  679. BOOL
  680. WINAPI
  681. NtVdm64CreateProcess(
  682. BOOL fPrefixMappedApplicationName,
  683. LPCWSTR lpApplicationName,
  684. LPCWSTR lpCommandLine,
  685. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  686. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  687. BOOL bInheritHandles,
  688. DWORD dwCreationFlags,
  689. LPVOID lpEnvironment,
  690. LPCWSTR lpCurrentDirectory,
  691. LPSTARTUPINFOW lpStartupInfo,
  692. LPPROCESS_INFORMATION lpProcessInformation
  693. )
  694. /*++
  695. Routine Description:
  696. Checks if there is a ported version of the Win16 lpApplicationName and
  697. if so creates a process with the ported version.
  698. Arguments:
  699. fPrefixMappedApplicationName
  700. - TRUE means that the original lpApplicationName was NULL.
  701. The application name was stripped from the head of
  702. lpCommandLine.
  703. The mapped application name needs to be added to the
  704. head of the mapped command line.
  705. - FALSE means that the original lpAPplicationName was non-NULL.
  706. the lpCommandLine argument is identical to the original
  707. lpCommandLine argument.
  708. lpApplicationName - Win16 file name not optional
  709. lpCommandLine - see comment for fPrefixMappedApplicationName.
  710. other arguments are identical to CreateProcessW.
  711. Return Value:
  712. Same as CreateProcessW
  713. --*/
  714. {
  715. WCHAR achMappedApplicationName[MAX_PATH+1];
  716. LPWSTR lpMappedCommandLine;
  717. BOOL Result;
  718. ASSERT(lpApplicationName);
  719. //
  720. // check appcompat
  721. //
  722. if (!CheckAppCompat(lpApplicationName)) {
  723. SetLastError(ERROR_CANCELLED);
  724. return FALSE;
  725. }
  726. if (lpCommandLine == NULL) {
  727. lpCommandLine = L"";
  728. }
  729. lpMappedCommandLine = NULL;
  730. Result = MapArguments(lpApplicationName,
  731. achMappedApplicationName,
  732. ARRAYSIZE(achMappedApplicationName),
  733. fPrefixMappedApplicationName,
  734. lpCommandLine,
  735. &lpMappedCommandLine);
  736. if (Result) {
  737. Result = CreateProcessW((fPrefixMappedApplicationName ?
  738. NULL :
  739. achMappedApplicationName),
  740. lpMappedCommandLine,
  741. lpProcessAttributes,
  742. lpThreadAttributes,
  743. bInheritHandles,
  744. dwCreationFlags,
  745. lpEnvironment,
  746. lpCurrentDirectory,
  747. lpStartupInfo,
  748. lpProcessInformation);
  749. if (lpMappedCommandLine) {
  750. RtlFreeHeap(RtlProcessHeap(), 0, lpMappedCommandLine);
  751. }
  752. } else {
  753. SetLastError(ERROR_BAD_EXE_FORMAT);
  754. }
  755. return Result;
  756. }