From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/loader.c | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 9ecaf438322..cd621a04ff4 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -4616,10 +4616,27 @@ static void test_wow64_redirection(void) char buffer[MAX_PATH]; static const char *dlls[] = {"wlanapi.dll", "dxgi.dll", "dwrite.dll"}; unsigned i; + HMODULE mod, mod_fixed, kernelbase; + IMAGE_NT_HEADERS *nt; + WORD machine;
if (!is_wow64) return;
+ kernelbase = GetModuleHandleW(L"kernelbase.dll"); + nt = RtlImageNtHeader(kernelbase); + machine = nt->FileHeader.Machine; + + ok(!GetModuleHandleA("rasapi32.dll"), "rasapi32.dll is already loaded.\n"); + + mod = LoadLibraryExW(L"c:\windows\system32\rasapi32.dll", 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE); + mod_fixed = (HMODULE)((ULONG_PTR)mod & ~(ULONG_PTR)3); + ok(!!mod_fixed, "got NULL.\n" ); + nt = RtlImageNtHeader(mod_fixed); + ok(!!nt, "got NULL.\n"); + ok(nt->FileHeader.Machine == machine, "got wrong machine.\n"); + FreeLibrary(mod); + /* Disable FS redirection, then test loading system libraries (pick ones that shouldn't * already be loaded in this process). */ @@ -4632,6 +4649,34 @@ static void test_wow64_redirection(void) test_wow64_redirection_for_dll(buffer, TRUE); }
+ mod = LoadLibraryExW(L"c:\windows\system32\kernelbase.dll", 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE); + ok(!!mod, "got NULL.\n" ); + ok(mod == kernelbase, "got different modules.\n"); + FreeLibrary(mod); + + mod = LoadLibraryExW(L"c:\windows\system32\kernelbase.dll", 0, LOAD_LIBRARY_AS_DATAFILE); + ok(!!mod, "got NULL.\n" ); + ok(mod == kernelbase, "got different modules.\n"); + FreeLibrary(mod); + + ok(!GetModuleHandleA("rasapi32.dll"), "rasapi32.dll is already loaded.\n"); + mod = LoadLibraryExW(L"c:\windows\system32\rasapi32.dll", 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE); + mod_fixed = (HMODULE)((ULONG_PTR)mod & ~(ULONG_PTR)3); + ok(!!mod_fixed, "got NULL.\n" ); + nt = RtlImageNtHeader(mod_fixed); + ok(!!nt, "got NULL.\n"); + ok(nt->FileHeader.Machine != machine, "got 32 bit dll.\n"); + FreeLibrary(mod); + + ok(!GetModuleHandleA("rasapi32.dll"), "rasapi32.dll is already loaded.\n"); + mod = LoadLibraryExW(L"c:\windows\system32\rasapi32.dll", 0, LOAD_LIBRARY_AS_DATAFILE); + mod_fixed = (HMODULE)((ULONG_PTR)mod & ~(ULONG_PTR)3); + ok(!!mod_fixed, "got NULL.\n" ); + nt = RtlImageNtHeader(mod_fixed); + ok(!!nt, "got NULL.\n"); + ok(nt->FileHeader.Machine != machine, "got 32 bit dll.\n"); + FreeLibrary(mod); + ok(pWow64RevertWow64FsRedirection(OldValue), "Re-enabling FS redirection failed\n"); /* and results don't depend whether redirection is enabled or not */ for (i = 0; i < ARRAY_SIZE(dlls); i++)
From: Paul Gofman pgofman@codeweavers.com
--- dlls/version/tests/info.c | 109 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+)
diff --git a/dlls/version/tests/info.c b/dlls/version/tests/info.c index 9eba180f215..b498f5331c8 100644 --- a/dlls/version/tests/info.c +++ b/dlls/version/tests/info.c @@ -30,6 +30,14 @@ #include "verrsrc.h" #include "wine/test.h"
+static BOOL is_wow64; + +static char system_dir[MAX_PATH]; +static char syswow_dir[MAX_PATH]; + +static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(void **); +static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(void *); + #define MY_LAST_ERROR ((DWORD)-1) #define EXPECT_BAD_PATH__NOT_FOUND \ ok( (ERROR_PATH_NOT_FOUND == GetLastError()) || \ @@ -868,8 +876,108 @@ static void test_GetFileVersionInfoEx(void) return; }
+static void test_wow64_redirection(void) +{ + char buf[MAX_PATH], buf2[MAX_PATH]; + UINT size, translation; + char *ver, *p; + void *cookie; + HMODULE module; + BOOL ret; + + if (!is_wow64) + return; + + ret = pWow64DisableWow64FsRedirection(&cookie); + ok(ret, "got error %lu.\n", GetLastError()); + + sprintf(buf, "%s\psapi.dll", syswow_dir); + sprintf(buf2, "%s\test.dll", syswow_dir); + ret = CopyFileA(buf, buf2, FALSE); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + ret = pWow64RevertWow64FsRedirection(cookie); + ok(ret, "got error %lu.\n", GetLastError()); + skip("Can't copy file to system directory.\n"); + return; + } + ok(ret, "got error %lu.\n", GetLastError()); + + sprintf(buf, "%s\iphlpapi.dll", system_dir); + sprintf(buf2, "%s\test.dll", system_dir); + ret = CopyFileA(buf, buf2, FALSE); + ok(ret, "got error %lu.\n", GetLastError()); + + module = LoadLibraryA("test.dll"); + ok(!!module, "got error %lu.\n", GetLastError()); + + size = GetFileVersionInfoSizeW(L"C:\windows\system32\test.dll", NULL); + ok(size, "got error %lu.\n", GetLastError()); + ver = malloc(size); + ret = GetFileVersionInfoW(L"C:\windows\system32\test.dll", 0, size, ver); + ok(ret, "got error %lu.\n", GetLastError()); + ret = VerQueryValueA(ver, "\VarFileInfo\Translation", (void **)&p, &size); + ok(ret, "got error %lu.\n", GetLastError()); + translation = *(UINT *)p; + translation = MAKELONG(HIWORD(translation), LOWORD(translation)); + sprintf(buf, "\StringFileInfo\%08x\OriginalFileName", translation); + ret = VerQueryValueA(ver, buf, (LPVOID*)&p, &size); + ok(ret, "got error %lu.\n", GetLastError()); + /* When the module is already loaded GetFileVersionInfoW finds redirected loaded one while the file which + * should've been open with disabled redirection is different. */ + ok(!strnicmp(p, "psapi", 5), "got %s.\n", debugstr_a(p)); + free(ver); + + FreeLibrary(module); + + size = GetFileVersionInfoSizeW(L"C:\windows\system32\test.dll", NULL); + ok(size, "got error %lu.\n", GetLastError()); + ver = malloc(size); + ret = GetFileVersionInfoW(L"C:\windows\system32\test.dll", 0, size, ver); + ok(ret, "got error %lu.\n", GetLastError()); + ret = VerQueryValueA(ver, "\VarFileInfo\Translation", (void **)&p, &size); + ok(ret, "got error %lu.\n", GetLastError()); + translation = *(UINT *)p; + translation = MAKELONG(HIWORD(translation), LOWORD(translation)); + sprintf(buf, "\StringFileInfo\%08x\OriginalFileName", translation); + ret = VerQueryValueA(ver, buf, (LPVOID*)&p, &size); + ok(ret, "got error %lu.\n", GetLastError()); + /* When the module is not loaded GetFileVersionInfoW finds the module in system32 as one would expect. */ + ok(!strnicmp(p, "iphlpapi", 8), "got %s.\n", debugstr_a(p)); + free(ver); + + sprintf(buf2, "%s\test.dll", syswow_dir); + ret = DeleteFileA(buf2); + ok(ret, "got error %lu.\n", GetLastError()); + + sprintf(buf2, "%s\test.dll", system_dir); + ret = DeleteFileA(buf2); + ok(ret, "got error %lu.\n", GetLastError()); + + ret = pWow64RevertWow64FsRedirection(cookie); + ok(ret, "got error %lu.\n", GetLastError()); +} + START_TEST(info) { + HMODULE kernel32 =kernel32 = GetModuleHandleA("kernel32.dll"); + BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); + DWORD size; + + pWow64DisableWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64DisableWow64FsRedirection"); + pWow64RevertWow64FsRedirection = (void *)GetProcAddress(kernel32, "Wow64RevertWow64FsRedirection"); + + if ((pIsWow64Process = (void *)GetProcAddress(kernel32, "IsWow64Process"))) + pIsWow64Process( GetCurrentProcess(), &is_wow64 ); + + size = GetSystemDirectoryA(system_dir, ARRAY_SIZE(system_dir)); + ok(size && size < ARRAY_SIZE(system_dir), "Couldn't get system directory: %lu\n", GetLastError()); + if (is_wow64) + { + size = GetSystemWow64DirectoryA(syswow_dir, ARRAY_SIZE(syswow_dir)); + ok(size && size < ARRAY_SIZE(syswow_dir), "Couldn't get wow directory: %lu\n", GetLastError()); + } + test_info_size(); test_info(); test_32bit_win(); @@ -877,4 +985,5 @@ START_TEST(info) test_VerQueryValue_EmptyData(); test_extra_block(); test_GetFileVersionInfoEx(); + test_wow64_redirection(); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/msi/tests/install.c | 150 ++++++++++++++++++++++++++++----------- 1 file changed, 107 insertions(+), 43 deletions(-)
diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c index 3bf28cc1e54..57ee48c2d7a 100644 --- a/dlls/msi/tests/install.c +++ b/dlls/msi/tests/install.c @@ -52,6 +52,8 @@ char PROG_FILES_DIR_NATIVE[MAX_PATH]; char COMMON_FILES_DIR[MAX_PATH]; char APP_DATA_DIR[MAX_PATH]; char WINDOWS_DIR[MAX_PATH]; +static char system_dir[MAX_PATH]; +static char syswow_dir[MAX_PATH];
static const char *customdll;
@@ -102,7 +104,7 @@ static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n" static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" "File\tFile\n" - "five.txt\tFive\tfive.txt\t1000\t\t\t16384\t5\n" + "five.txt\tFive\tfive.txt\t1000\t0.0.0.0\t\t16384\t5\n" "four.txt\tFour\tfour.txt\t1000\t\t\t16384\t4\n" "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n" "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n" @@ -1348,9 +1350,9 @@ static const CHAR x64_directory_dat[] = "CABOUTDIR\tMSITESTDIR\tcabout\n" "CHANGEDDIR\tMSITESTDIR\tchanged:second\n" "FIRSTDIR\tMSITESTDIR\tfirst\n" - "MSITESTDIR\tProgramFiles64Folder\tmsitest\n" + "MSITESTDIR\tSystem64Folder\tmsitest\n" "NEWDIR\tCABOUTDIR\tnew\n" - "ProgramFiles64Folder\tTARGETDIR\t.\n" + "System64Folder\tTARGETDIR\t.\n" "TARGETDIR\t\tSourceDir";
static const CHAR sr_install_exec_seq_dat[] = @@ -2388,6 +2390,16 @@ BOOL get_system_dirs(void) if(!GetWindowsDirectoryA(WINDOWS_DIR, MAX_PATH)) return FALSE;
+ size = GetSystemDirectoryA(system_dir, ARRAY_SIZE(system_dir)); + if (!size || size >= ARRAY_SIZE(system_dir)) + return FALSE; + if (is_wow64) + { + size = GetSystemWow64DirectoryA(syswow_dir, ARRAY_SIZE(syswow_dir)); + if (!size || size >= ARRAY_SIZE(syswow_dir)) + return FALSE; + } + return TRUE; }
@@ -2430,13 +2442,11 @@ static void create_test_files(void) DeleteFileA("five.txt"); }
-BOOL delete_pf(const CHAR *rel_path, BOOL is_file) +static BOOL delete_pf_dir(const char *rel_path, BOOL is_file, const char *basedir) { - CHAR path[MAX_PATH]; + char path[MAX_PATH];
- lstrcpyA(path, PROG_FILES_DIR); - lstrcatA(path, "\"); - lstrcatA(path, rel_path); + sprintf(path, "%s\%s", basedir, rel_path);
if (is_file) return DeleteFileA(path); @@ -2444,18 +2454,9 @@ BOOL delete_pf(const CHAR *rel_path, BOOL is_file) return RemoveDirectoryA(path); }
-static BOOL delete_pf_native(const CHAR *rel_path, BOOL is_file) +BOOL delete_pf(const CHAR *rel_path, BOOL is_file) { - CHAR path[MAX_PATH]; - - lstrcpyA(path, PROG_FILES_DIR_NATIVE); - lstrcatA(path, "\"); - lstrcatA(path, rel_path); - - if (is_file) - return DeleteFileA(path); - else - return RemoveDirectoryA(path); + return delete_pf_dir(rel_path, is_file, PROG_FILES_DIR); }
static BOOL delete_cf(const CHAR *rel_path, BOOL is_file) @@ -6215,7 +6216,12 @@ error:
static void test_wow64(void) { + WIN32_FILE_ATTRIBUTE_DATA attr; + char path[MAX_PATH]; + HMODULE module; + DWORD dll_size; void *cookie; + BOOL ret; UINT r;
if (!is_wow64) @@ -6230,7 +6236,59 @@ static void test_wow64(void) return; }
- create_test_files(); + sprintf(path, "%s\msitest", "C:\windows\syswow64"); + ret = CreateDirectoryA(path, NULL); + ok(ret, "got error %lu.\n", GetLastError()); + sprintf(path, "%s\msitest\cabout", "C:\windows\syswow64"); + ret = CreateDirectoryA(path, NULL); + ok(ret, "got error %lu.\n", GetLastError()); + sprintf(path, "%s\msitest\cabout\new", "C:\windows\syswow64"); + ret = CreateDirectoryA(path, NULL); + ok(ret, "got error %lu.\n", GetLastError()); + + sprintf(path, "%s\msitest\cabout\new\five.txt", "C:\windows\syswow64"); + ret = CopyFileA("C:\windows\system32\psapi.dll", path, FALSE); + ok(ret, "got error %lu.\n", GetLastError()); + + module = LoadLibraryA(path); + ok(!!module, "failed to load module.\n"); + + Wow64DisableWow64FsRedirection(&cookie); + + sprintf(path, "%s\msitest", "C:\windows\system32"); + ret = CreateDirectoryA(path, NULL); + ok(ret, "%s, got error %lu.\n", path, GetLastError()); + sprintf(path, "%s\msitest\cabout", "C:\windows\system32"); + ret = CreateDirectoryA(path, NULL); + ok(ret, "got error %lu.\n", GetLastError()); + sprintf(path, "%s\msitest\cabout\new", "C:\windows\system32"); + ret = CreateDirectoryA(path, NULL); + ok(ret, "got error %lu.\n", GetLastError()); + + sprintf(path, "%s\msitest\cabout\new\five.txt", "C:\windows\system32"); + create_file(path, 100); + + CreateDirectoryA("msitest", NULL); + + create_file("msitest\one.txt", 100); + CreateDirectoryA("msitest\first", NULL); + create_file("msitest\first\two.txt", 100); + CreateDirectoryA("msitest\second", NULL); + create_file("msitest\second\three.txt", 100); + + create_file("four.txt", 100); + ret = GetFileAttributesExA("C:\windows\system32\psapi.dll", GetFileExInfoStandard, &attr); + ok(ret, "got error %lu.\n", GetLastError()); + dll_size = attr.nFileSizeLow; + ret = CopyFileA("C:\windows\system32\psapi.dll", "five.txt", FALSE); + ok(ret, "got error %lu.\n", GetLastError()); + create_cab_file("msitest.cab", MEDIA_SIZE, "four.txt\0five.txt\0"); + create_file("msitest\filename", 100); + + DeleteFileA("four.txt"); + DeleteFileA("five.txt"); + Wow64RevertWow64FsRedirection(cookie); + create_database_template(msifile, x64_tables, ARRAY_SIZE(x64_tables), 200, "x64;0"); r = MsiInstallProductA(msifile, NULL); if (r == ERROR_INSTALL_PACKAGE_REJECTED) @@ -6238,32 +6296,38 @@ static void test_wow64(void) skip("Not enough rights to perform tests\n"); goto error; } + FreeLibrary(module);
Wow64DisableWow64FsRedirection(&cookie);
- ok(!delete_pf("msitest\cabout\new\five.txt", TRUE), "File installed\n"); - ok(!delete_pf("msitest\cabout\new", FALSE), "Directory created\n"); - ok(!delete_pf("msitest\cabout\four.txt", TRUE), "File installed\n"); - ok(!delete_pf("msitest\cabout", FALSE), "Directory created\n"); - ok(!delete_pf("msitest\changed\three.txt", TRUE), "File installed\n"); - ok(!delete_pf("msitest\changed", FALSE), "Directory created\n"); - ok(!delete_pf("msitest\first\two.txt", TRUE), "File installed\n"); - ok(!delete_pf("msitest\first", FALSE), "Directory created\n"); - ok(!delete_pf("msitest\one.txt", TRUE), "File installed\n"); - ok(!delete_pf("msitest\filename", TRUE), "File installed\n"); - ok(!delete_pf("msitest", FALSE), "Directory created\n"); - - ok(delete_pf_native("msitest\cabout\new\five.txt", TRUE), "File not installed\n"); - ok(delete_pf_native("msitest\cabout\new", FALSE), "Directory not created\n"); - ok(delete_pf_native("msitest\cabout\four.txt", TRUE), "File not installed\n"); - ok(delete_pf_native("msitest\cabout", FALSE), "Directory not created\n"); - ok(delete_pf_native("msitest\changed\three.txt", TRUE), "File not installed\n"); - ok(delete_pf_native("msitest\changed", FALSE), "Directory not created\n"); - ok(delete_pf_native("msitest\first\two.txt", TRUE), "File not installed\n"); - ok(delete_pf_native("msitest\first", FALSE), "Directory not created\n"); - ok(delete_pf_native("msitest\one.txt", TRUE), "File not installed\n"); - ok(delete_pf_native("msitest\filename", TRUE), "File not installed\n"); - ok(delete_pf_native("msitest", FALSE), "Directory not created\n"); + ok(delete_pf_dir("msitest\cabout\new\five.txt", TRUE, syswow_dir), "File installed\n"); + ok(delete_pf_dir("msitest\cabout\new", FALSE, syswow_dir), "Directory created\n"); + ok(!delete_pf_dir("msitest\cabout\four.txt", TRUE, syswow_dir), "File installed\n"); + ok(delete_pf_dir("msitest\cabout", FALSE, syswow_dir), "Directory created\n"); + ok(!delete_pf_dir("msitest\changed\three.txt", TRUE, syswow_dir), "File installed\n"); + ok(!delete_pf_dir("msitest\changed", FALSE, syswow_dir), "Directory created\n"); + ok(!delete_pf_dir("msitest\first\two.txt", TRUE, syswow_dir), "File installed\n"); + ok(!delete_pf_dir("msitest\first", FALSE, syswow_dir), "Directory created\n"); + ok(!delete_pf_dir("msitest\one.txt", TRUE, syswow_dir), "File installed\n"); + ok(!delete_pf_dir("msitest\filename", TRUE, syswow_dir), "File installed\n"); + ok(delete_pf_dir("msitest", FALSE, syswow_dir), "Directory created\n"); + + sprintf(path, "%s\msitest\cabout\new\five.txt", system_dir); + ret = GetFileAttributesExA(path, GetFileExInfoStandard, &attr); + ok(ret, "got error %lu.\n", GetLastError()); + todo_wine ok(attr.nFileSizeLow == dll_size, "got %lu, expected %lu.\n", attr.nFileSizeLow, dll_size); + + ok(delete_pf_dir("msitest\cabout\new\five.txt", TRUE, system_dir), "File not installed\n"); + ok(delete_pf_dir("msitest\cabout\new", FALSE, system_dir), "Directory not created\n"); + ok(delete_pf_dir("msitest\cabout\four.txt", TRUE, system_dir), "File not installed\n"); + ok(delete_pf_dir("msitest\cabout", FALSE, system_dir), "Directory not created\n"); + ok(delete_pf_dir("msitest\changed\three.txt", TRUE, system_dir), "File not installed\n"); + ok(delete_pf_dir("msitest\changed", FALSE, system_dir), "Directory not created\n"); + ok(delete_pf_dir("msitest\first\two.txt", TRUE, system_dir), "File not installed\n"); + ok(delete_pf_dir("msitest\first", FALSE, system_dir), "Directory not created\n"); + ok(delete_pf_dir("msitest\one.txt", TRUE, system_dir), "File not installed\n"); + ok(delete_pf_dir("msitest\filename", TRUE, system_dir), "File not installed\n"); + ok(delete_pf_dir("msitest", FALSE, system_dir), "Directory not created\n");
Wow64RevertWow64FsRedirection(cookie);
From: Paul Gofman pgofman@codeweavers.com
--- dlls/msi/appsearch.c | 20 ++++---------------- dlls/msi/files.c | 24 ++++++++++++++---------- dlls/msi/msipriv.h | 2 +- 3 files changed, 19 insertions(+), 27 deletions(-)
diff --git a/dlls/msi/appsearch.c b/dlls/msi/appsearch.c index 88450087196..092a61560a4 100644 --- a/dlls/msi/appsearch.c +++ b/dlls/msi/appsearch.c @@ -178,18 +178,9 @@ static WCHAR *search_file( MSIPACKAGE *package, WCHAR *path, struct signature *s if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY)) return NULL;
- size = msi_get_file_version_info( package, path, 0, NULL ); - if (!size) + if (!(buffer = msi_get_file_version_info( package, path ))) return wcsdup(path);
- buffer = malloc(size); - if (!buffer) - return NULL; - - size = msi_get_file_version_info( package, path, size, buffer ); - if (!size) - goto done; - if (!VerQueryValueW(buffer, L"\", (LPVOID)&info, &size) || !info) goto done;
@@ -656,17 +647,14 @@ static UINT file_version_matches( MSIPACKAGE *package, const struct signature *s BOOL *matches ) { UINT len; - void *version; VS_FIXEDFILEINFO *info = NULL; - DWORD size = msi_get_file_version_info( package, filePath, 0, NULL ); + void *version;
*matches = FALSE;
- if (!size) return ERROR_SUCCESS; - if (!(version = malloc( size ))) return ERROR_OUTOFMEMORY; + if (!(version = msi_get_file_version_info( package, filePath ))) return ERROR_SUCCESS;
- if (msi_get_file_version_info( package, filePath, size, version )) - VerQueryValueW( version, L"\", (void **)&info, &len ); + VerQueryValueW( version, L"\", (void **)&info, &len );
if (info) { diff --git a/dlls/msi/files.c b/dlls/msi/files.c index 35166788dae..8dd2b67a792 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -157,27 +157,31 @@ static BOOL apply_filepatch( MSIPACKAGE *package, const WCHAR *patch, const WCHA return ret; }
-DWORD msi_get_file_version_info( MSIPACKAGE *package, const WCHAR *path, DWORD buflen, BYTE *buffer ) +BYTE *msi_get_file_version_info( MSIPACKAGE *package, const WCHAR *path ) { - DWORD size, handle; + DWORD size; + BYTE *buffer = NULL; + msi_disable_fs_redirection( package ); - if (buffer) size = GetFileVersionInfoW( path, 0, buflen, buffer ); - else size = GetFileVersionInfoSizeW( path, &handle ); + if (!(size = GetFileVersionInfoSizeW( path, NULL ))) goto done; + if (!(buffer = malloc( size ))) goto done; + if (!GetFileVersionInfoW( path, 0, size, buffer )) + { + free( buffer ); + buffer = NULL; + } +done: msi_revert_fs_redirection( package ); - return size; + return buffer; }
VS_FIXEDFILEINFO *msi_get_disk_file_version( MSIPACKAGE *package, const WCHAR *filename ) { VS_FIXEDFILEINFO *ptr, *ret; - DWORD version_size; UINT size; void *version;
- if (!(version_size = msi_get_file_version_info( package, filename, 0, NULL ))) return NULL; - if (!(version = malloc( version_size ))) return NULL; - - msi_get_file_version_info( package, filename, version_size, version ); + if (!(version = msi_get_file_version_info( package, filename ))) return NULL;
if (!VerQueryValueW( version, L"\", (void **)&ptr, &size )) { diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index e20ead557ce..aebfc85ab76 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -1114,7 +1114,7 @@ extern BOOL msi_set_file_attributes( MSIPACKAGE *, const WCHAR *, DWORD ); extern HANDLE msi_find_first_file( MSIPACKAGE *, const WCHAR *, WIN32_FIND_DATAW * ); extern BOOL msi_find_next_file( MSIPACKAGE *, HANDLE, WIN32_FIND_DATAW * ); extern BOOL msi_move_file( MSIPACKAGE *, const WCHAR *, const WCHAR *, DWORD ); -extern DWORD msi_get_file_version_info( MSIPACKAGE *, const WCHAR *, DWORD, BYTE * ); +extern BYTE *msi_get_file_version_info( MSIPACKAGE *, const WCHAR * ); extern BOOL msi_create_full_path( MSIPACKAGE *, const WCHAR * ); extern DWORD msi_get_disk_file_size( MSIPACKAGE *, const WCHAR * ); extern VS_FIXEDFILEINFO *msi_get_disk_file_version( MSIPACKAGE *, const WCHAR * );
From: Paul Gofman pgofman@codeweavers.com
--- dlls/msi/files.c | 12 ++++++++++++ dlls/msi/tests/install.c | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/dlls/msi/files.c b/dlls/msi/files.c index 8dd2b67a792..328b0e47a2d 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -159,10 +159,21 @@ static BOOL apply_filepatch( MSIPACKAGE *package, const WCHAR *patch, const WCHA
BYTE *msi_get_file_version_info( MSIPACKAGE *package, const WCHAR *path ) { + WCHAR tmp_filename[MAX_PATH]; DWORD size; BYTE *buffer = NULL;
+ *tmp_filename = 0; msi_disable_fs_redirection( package ); + if (is_wow64 && is_platform_64bit( package->platform ) && GetModuleHandleW( path )) + { + WCHAR temppath[MAX_PATH]; + + GetTempPathW( ARRAY_SIZE(temppath), temppath ); + if (!GetTempFileNameW( temppath, L"msi", 0, tmp_filename )) goto done; + if (!CopyFileW( path, tmp_filename, FALSE )) goto done; + path = tmp_filename; + } if (!(size = GetFileVersionInfoSizeW( path, NULL ))) goto done; if (!(buffer = malloc( size ))) goto done; if (!GetFileVersionInfoW( path, 0, size, buffer )) @@ -171,6 +182,7 @@ BYTE *msi_get_file_version_info( MSIPACKAGE *package, const WCHAR *path ) buffer = NULL; } done: + if (*tmp_filename) DeleteFileW(tmp_filename); msi_revert_fs_redirection( package ); return buffer; } diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c index 57ee48c2d7a..4b967d1aa4b 100644 --- a/dlls/msi/tests/install.c +++ b/dlls/msi/tests/install.c @@ -6315,7 +6315,7 @@ static void test_wow64(void) sprintf(path, "%s\msitest\cabout\new\five.txt", system_dir); ret = GetFileAttributesExA(path, GetFileExInfoStandard, &attr); ok(ret, "got error %lu.\n", GetLastError()); - todo_wine ok(attr.nFileSizeLow == dll_size, "got %lu, expected %lu.\n", attr.nFileSizeLow, dll_size); + ok(attr.nFileSizeLow == dll_size, "got %lu, expected %lu.\n", attr.nFileSizeLow, dll_size);
ok(delete_pf_dir("msitest\cabout\new\five.txt", TRUE, system_dir), "File not installed\n"); ok(delete_pf_dir("msitest\cabout\new", FALSE, system_dir), "Directory not created\n");
Now if a 32 bit loader tries to install 64 bit library into system32 directory and checks the version of the one which is there, and at the same time has (unlrelated) 32 bit library with the same path loaded from syswow64, the version will be loaded from the installer's in-process loaded library and not the one which exists on disk in unredirected system32.
One could expect that it is GetFileVersionInfo() bug which will get the version info from the long library. But the test in patch 2 shows that GetFileVersionInfo() behaves like on Windows there, while test in patch 3 shows that MSI checks the version correctly on Windows. Which suggests msi.dll is the right place to fix it.
It's possible that native performs the version check from a 64-bit service process so it doesn't have this problem. That would be a big change in msi however. Which dll triggered this?
I came across that looking at older VC redists trying to install ucrtbase.dll (while they will only try to install it with older Win version set).
While Windows msi.dll might be ending up using installer service indeed for file operations, we have that implemented differently now. Do we necessarily need it working the same way and have to introduce a service to fix such a bug? Unless there are bigger known problems which demand that?
As an alternative to file copy to check the version (while is it bad? the conditions for that are quite specific) we could in theory duplicate some code from kernelbase/version.c which gets the version info from PE file directly.
Also, all the file operations now are guarded with wow64 redirection disablement, isn't that in principle same sort of a workaround of msi not using updater service? Which workaround just happens to not work right for this particular case.
You're right that disabling redirection works around missing installer service and it would be nice to solve this some day. We also have msi property bugs related to this architecture difference.
Copying the file as a workaround isn't very pretty IMO and I think a local copy of version info parsing is a cleaner workaround.