MUI_RC_CONFIG layout is based on the description from http://hostagebrain.blogspot.com/2015/11/multilingual-user-interface.html
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/kernel32/tests/resource.c | 235 ++++++++++++++++++++++++++++++++- 1 file changed, 234 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/resource.c b/dlls/kernel32/tests/resource.c index 6c5bc99c0c5..626645a8979 100644 --- a/dlls/kernel32/tests/resource.c +++ b/dlls/kernel32/tests/resource.c @@ -2,6 +2,7 @@ * Unit test suite for resource functions. * * Copyright 2006 Mike McCormack + * Copyright 2022 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,8 +19,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include <windows.h> +#include <stdarg.h> #include <stdio.h> +#include <assert.h> +#include <windows.h>
#include "wine/test.h"
@@ -520,10 +523,240 @@ static void test_internal_structure(void) ok( EndUpdateResourceW( res, TRUE ), "EndUpdateResourceW failed\n"); }
+typedef struct +{ + DWORD dwSignature; + DWORD dwSize; + DWORD dwVersion; + DWORD unknown1; + DWORD unknown2; + DWORD unknown3; + DWORD dwFileType; + BYTE pServiceChecksum[16]; + BYTE pChecksum[16]; + DWORD unknown4[6]; + DWORD dwTypeNameMainOffset; + DWORD dwTypeNameMainSize; + DWORD dwTypeIDMainOffset; + DWORD dwTypeIDMainSize; + DWORD dwTypeNameMUIOffset; + DWORD dwTypeNameMUISize; + DWORD dwTypeIDMUIOffset; + DWORD dwTypeIDMUISize; + DWORD unknown5; + DWORD unknown6; + DWORD dwLanguageNameOffset; + DWORD dwLanguageNameSize; +} MUI_RC_CONFIG; + +static void *offset_to_data(void *base, DWORD offset) +{ + return (char *)base + offset; +} + +static void test_GetFileMUIInfo(void) +{ +#define MUI_QUERY_ALL (MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME | MUI_QUERY_RESOURCE_TYPES) + static const BYTE zero[8]; + static const WCHAR path[] = L"urlmon.dll"; + char buf[1024]; + HRSRC rsrc; + MUI_RC_CONFIG *rc_cfg; + char *p1, *p2; + FILEMUIINFO *info = (FILEMUIINFO *)buf; + DWORD size, full_size; + HMODULE module; + int ret; + + module = LoadLibraryExW(path, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE); + ok(module != NULL, "LoadLibraryEx error %lu\n", GetLastError()); + rsrc = FindResourceW(module, MAKEINTRESOURCEW(1), L"MUI"); + todo_wine + ok(rsrc != 0, "MUI resource not found\n"); + if (!rsrc) + { + skip("MUI resource not found\n"); + FreeLibrary(module); + return; + } + rc_cfg = LockResource(LoadResource(module, rsrc)); + ok(rc_cfg->dwVersion == MAKELONG(0,1), "got %08lx\n", rc_cfg->dwVersion); + ok(rc_cfg->dwFileType == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN, "got %08lx\n", rc_cfg->dwFileType); + + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(0, path, NULL, NULL); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + info->dwSize = sizeof(*info); + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(0, path, info, NULL); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(MUI_QUERY_ALL, path, NULL, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + + size = 0; + ret = GetFileMUIInfo(0, path, NULL, &size); + ok(ret, "GetFileMUIInfo error %lu\n", GetLastError()); + ok(size == sizeof(FILEMUIINFO), "got %lu bytes\n", size); + + memset(info, 0, sizeof(*info)); + size = info->dwSize = sizeof(*info) - 1; + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(0, path, info, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError()); + + memset(info, 0, sizeof(*info)); + size = info->dwSize = sizeof(*info); + ret = GetFileMUIInfo(0, path, info, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + ok(!size, "got %lu\n", size); + ok(info->dwSize == sizeof(*info), "got %lu\n", info->dwSize); + ok(!info->dwVersion, "got %08lx\n", info->dwVersion); + + memset(info, 0, sizeof(*info)); + size = info->dwSize = sizeof(*info); + info->dwVersion = MUI_FILEINFO_VERSION; + ret = GetFileMUIInfo(0, path, info, &size); + ok(ret, "GetFileMUIInfo error %lu\n", GetLastError()); + + memset(buf, 0, sizeof(buf)); + size = info->dwSize = 1; + info->dwVersion = MUI_FILEINFO_VERSION; + info->dwFileType = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(0, path, info, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError()); + ok(info->dwVersion == MUI_FILEINFO_VERSION, "got %08lx\n", info->dwVersion); + ok(info->dwFileType == 0xdeadbeef, "got %08lx\n", info->dwFileType); + + memset(buf, 0, sizeof(buf)); + info->dwSize = sizeof(*info); + size = sizeof(*info) + 1; + info->dwVersion = MUI_FILEINFO_VERSION; + info->dwFileType = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(0, path, info, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + ok(info->dwVersion == MUI_FILEINFO_VERSION, "got %08lx\n", info->dwVersion); + ok(info->dwFileType == 0xdeadbeef, "got %08lx\n", info->dwFileType); + + full_size = 0; + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(MUI_QUERY_ALL, path, NULL, &full_size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError()); + + memset(buf, 0, sizeof(buf)); + info->dwSize = size = sizeof(*info); + info->dwVersion = 0; + info->dwFileType = 0xdeadbeef; + memcpy(info->abBuffer, "deadbeef", 8); + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(MUI_QUERY_ALL, path, info, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + ok(info->dwVersion == 0, "got %08lx\n", info->dwVersion); + ok(info->dwFileType == 0, "got %08lx\n", info->dwFileType); + ok(!memcmp(info->abBuffer, zero, 8), "got %.8s\n", info->abBuffer); + + memset(buf, 0, sizeof(buf)); + info->dwSize = size = sizeof(*info); + info->dwVersion = 0xdeadbeef; + info->dwFileType = 0xdeadbeef; + memcpy(info->abBuffer, "deadbeef", 8); + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(MUI_QUERY_ALL, path, info, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError()); + ok(info->dwVersion == 0xdeadbeef, "got %08lx\n", info->dwVersion); + ok(info->dwFileType == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN, "got %08lx\n", info->dwFileType); + ok(!memcmp(info->abBuffer, zero, 8), "got %.8s\n", info->abBuffer); + + memset(buf, 0, sizeof(buf)); + info->dwSize = size = sizeof(*info); + info->dwVersion = 0xdeadbeef; + info->dwFileType = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetFileMUIInfo(MUI_QUERY_ALL, path, info, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError()); + ok(info->dwVersion == 0xdeadbeef, "got %08lx\n", info->dwVersion); + ok(info->dwFileType == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN, "got %08lx\n", info->dwFileType); + + memset(buf, 0, sizeof(buf)); + info->dwSize = size = full_size; + info->dwVersion = 0; + info->dwFileType = 0xdeadbeef; + ret = GetFileMUIInfo(MUI_QUERY_ALL, path, info, &size); + ok(!ret, "GetFileMUIInfo should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + ok(size == 0, "got %08lx\n", size); + ok(info->dwVersion == 0, "got %08lx\n", info->dwVersion); + ok(info->dwFileType == 0, "got %08lx\n", info->dwFileType); + ok(!memcmp(info->abBuffer, zero, 8), "got %.8s\n", info->abBuffer); + + memset(buf, 0, sizeof(buf)); + info->dwSize = size = full_size; + info->dwVersion = MUI_FILEINFO_VERSION; + info->dwFileType = 0xdeadbeef; + ret = GetFileMUIInfo(MUI_QUERY_ALL, path, info, &size); + ok(ret || broken(GetLastError() == ERROR_INSUFFICIENT_BUFFER) /* Some Win10 versions */, "GetFileMUIInfo error %lu\n", GetLastError()); + while (!ret) /* Try to recover from Win10 breakage */ + { + size += 2; + assert(size <= sizeof(buf)); + info->dwSize = size; + ret = GetFileMUIInfo(MUI_QUERY_ALL, path, info, &size); + } + ok(info->dwVersion == MUI_FILEINFO_VERSION, "got %08lx\n", info->dwVersion); + ok(info->dwFileType == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN, "got %08lx\n", info->dwFileType); + + ok(!memcmp(info->pChecksum, rc_cfg->pChecksum, 16), "Checksum doesn't match\n"); + ok(!memcmp(info->pServiceChecksum, rc_cfg->pServiceChecksum, 16), "ServiceChecksum doesn't match\n"); + + p1 = offset_to_data(rc_cfg, rc_cfg->dwLanguageNameOffset); + p2 = offset_to_data(info, info->dwLanguageNameOffset); + ok(!memcmp(p1, p2, rc_cfg->dwLanguageNameSize), "LanguageName doesn't match\n"); + + p1 = offset_to_data(rc_cfg, rc_cfg->dwTypeNameMainOffset); + p2 = offset_to_data(info, info->dwTypeNameMainOffset); + ok(!memcmp(p1, p2, rc_cfg->dwTypeNameMainSize), "TypeNameMain doesn't match\n"); + + p1 = offset_to_data(rc_cfg, rc_cfg->dwTypeIDMainOffset); + p2 = offset_to_data(info, info->dwTypeIDMainOffset); + ok(rc_cfg->dwTypeIDMainSize == info->dwTypeIDMainSize * sizeof(DWORD), "dwTypeIDMainSize %#08lx != %08lx\n", + rc_cfg->dwTypeIDMainSize, info->dwTypeIDMainSize); + ok(!memcmp(p1, p2, rc_cfg->dwTypeIDMainSize), "TypeIDMain doesn't match\n"); + + p1 = offset_to_data(rc_cfg, rc_cfg->dwTypeIDMUIOffset); + p2 = offset_to_data(info, info->dwTypeIDMUIOffset); + ok(rc_cfg->dwTypeIDMUISize == info->dwTypeIDMUISize * sizeof(DWORD), "dwTypeIDMUISize %#08lx != %08lx\n", + rc_cfg->dwTypeIDMUISize, info->dwTypeIDMUISize); + ok(!memcmp(p1, p2, rc_cfg->dwTypeIDMUISize), "TypeIDMUI doesn't match\n"); + + p1 = offset_to_data(rc_cfg, rc_cfg->dwTypeNameMUIOffset); + p2 = offset_to_data(info, info->dwTypeNameMUIOffset); + ok(!memcmp(p1, p2, rc_cfg->dwTypeNameMUISize), "TypeNameMUI doesn't match\n"); + + FreeLibrary(module); +} + START_TEST(resource) { DWORD i;
+ test_GetFileMUIInfo(); + DeleteFileA( filename ); update_missing_exe();