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

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