From: Piotr Caban piotr@codeweavers.com
--- dlls/kernelbase/locale.c | 212 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 209 insertions(+), 3 deletions(-)
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index 568f34d8979..b0515b4fb4f 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -5719,15 +5719,221 @@ done: }
+#define MUI_SIGNATURE 0xfecdfecd +struct mui_resource +{ + DWORD signature; + DWORD size; + DWORD version; + DWORD path_type; + DWORD file_type; + DWORD system_attributes; + DWORD fallback_location; + BYTE service_checksum[16]; + BYTE checksum[16]; + DWORD unk1[2]; + DWORD mui_path_off; + DWORD mui_path_size; + DWORD unk2[2]; + DWORD ln_type_name_off; + DWORD ln_type_name_size; + DWORD ln_type_id_off; + DWORD ln_type_id_size; + DWORD mui_type_name_off; + DWORD mui_type_name_size; + DWORD mui_type_id_off; + DWORD mui_type_id_size; + DWORD lang_off; + DWORD lang_size; + DWORD fallback_lang_off; + DWORD fallback_lang_size; +}; + + +static BOOL validate_mui_resource(struct mui_resource *mui, DWORD size) +{ + if (size >= sizeof(DWORD) && mui->signature != MUI_SIGNATURE) + { + SetLastError(ERROR_MUI_INVALID_RC_CONFIG); + return FALSE; + } + + size = min( size, mui->size ); + if (size < sizeof(*mui) || + mui->ln_type_name_off >= size || mui->ln_type_name_size > size - mui->ln_type_name_off || + mui->ln_type_id_off >= size || mui->ln_type_id_size > size - mui->ln_type_id_off || + mui->mui_type_name_off >= size || mui->mui_type_name_size > size - mui->mui_type_name_off || + mui->mui_type_id_off >= size || mui->mui_type_id_size > size - mui->mui_type_id_off || + mui->lang_off >= size || mui->lang_size > size - mui->lang_off || + mui->fallback_lang_off >= size || mui->fallback_lang_size > size - mui->fallback_lang_off) + { + SetLastError(ERROR_BAD_EXE_FORMAT); + return FALSE; + } + return TRUE; +} + + /****************************************************************************** * GetFileMUIInfo (kernelbase.@) */ BOOL WINAPI /* DECLSPEC_HOTPATCH */ GetFileMUIInfo( DWORD flags, const WCHAR *path, FILEMUIINFO *info, DWORD *size ) { - FIXME( "stub: %lu, %s, %p, %p\n", flags, debugstr_w(path), info, size ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + DWORD off, mui_size, type = MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL; + struct mui_resource *mui = NULL; + HMODULE hmod; + HRSRC hrsrc; + + TRACE( "%lu, %s, %p, %p\n", flags, debugstr_w(path), info, size ); + + if (!path || !size || (*size && !info) || + (info && (*size < sizeof(*info) || info->dwSize != *size || + info->dwVersion != MUI_FILEINFO_VERSION))) + { + if (size) *size = 0; + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (!flags) flags = MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM; + + hmod = LoadLibraryExW( path, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE ); + if (!hmod) return FALSE; + + hrsrc = FindResourceW( hmod, MAKEINTRESOURCEW(1), L"MUI" ); + if (hrsrc) + { + mui = LockResource( LoadResource(hmod, hrsrc) ); + if (mui) mui_size = SizeofResource( hmod, hrsrc ); + if (!mui || !validate_mui_resource( mui, mui_size )) + { + FreeLibrary( hmod ); + return FALSE; + } + if (mui->file_type & (MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN >> 1)) + type = MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN; + else if (mui->file_type & (MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI >> 1)) + type = MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI; + } + if (type == MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL) + { + FreeLibrary( hmod ); + + if (!info) + { + *size = sizeof(*info); + return TRUE; + } + if (info->dwSize < sizeof(*info)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + memset( info, 0, sizeof(*info) ); + info->dwSize = *size; + info->dwVersion = MUI_FILEINFO_VERSION; + if (flags & MUI_QUERY_TYPE) info->dwFileType = type; + return TRUE; + } + + off = offsetof(FILEMUIINFO, abBuffer); + if (flags & MUI_QUERY_LANGUAGE_NAME) + { + off += type == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN ? + mui->fallback_lang_size : mui->lang_size; + } + if (flags & MUI_QUERY_RESOURCE_TYPES) + { + if (type == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN) + off += mui->ln_type_name_size + mui->ln_type_id_size; + off += mui->mui_type_name_size + mui->mui_type_id_size; + } + if (off < sizeof(*info)) off = sizeof(*info); + + if (!info || info->dwSize < off) + { + FreeLibrary( hmod ); + *size = off; + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + off = 0; + memset( info, 0, sizeof(*info) ); + info->dwSize = *size; + info->dwVersion = MUI_FILEINFO_VERSION; + if (flags & MUI_QUERY_TYPE) info->dwFileType = type; + if (flags & MUI_QUERY_CHECKSUM) + { + memcpy( info->pChecksum, mui->checksum, sizeof(info->pChecksum) ); + memcpy( info->pServiceChecksum, mui->service_checksum, sizeof(info->pServiceChecksum) ); + } + if (flags & MUI_QUERY_LANGUAGE_NAME) + { + if (type == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN && mui->fallback_lang_off) + { + info->dwLanguageNameOffset = offsetof(FILEMUIINFO, abBuffer); + memcpy(info->abBuffer, ((BYTE *)mui) + mui->fallback_lang_off, + mui->fallback_lang_size); + off += mui->fallback_lang_size; + } + if (type == MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI && mui->lang_off) + { + info->dwLanguageNameOffset = offsetof(FILEMUIINFO, abBuffer); + memcpy(info->abBuffer, ((BYTE *)mui) + mui->lang_off, mui->lang_size); + off += mui->lang_size; + } + } + if (flags & MUI_QUERY_RESOURCE_TYPES && type & MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN) + { + if (mui->ln_type_id_size && mui->ln_type_id_off) + { + info->dwTypeIDMainSize = mui->ln_type_id_size / sizeof(DWORD); + info->dwTypeIDMainOffset = offsetof(FILEMUIINFO, abBuffer[off]); + memcpy(info->abBuffer + off, ((BYTE *)mui) + mui->ln_type_id_off, mui->ln_type_id_size); + off += mui->ln_type_id_size; + } + if (mui->ln_type_name_off) + { + info->dwTypeNameMainOffset = offsetof(FILEMUIINFO, abBuffer[off]); + memcpy(info->abBuffer + off, ((BYTE *)mui) + mui->ln_type_name_off, mui->ln_type_name_size); + off += mui->ln_type_name_size; + } + if (mui->mui_type_id_size && mui->mui_type_id_off) + { + info->dwTypeIDMUISize = mui->mui_type_id_size / sizeof(DWORD); + info->dwTypeIDMUIOffset = offsetof(FILEMUIINFO, abBuffer[off]); + memcpy(info->abBuffer + off, ((BYTE *)mui) + mui->mui_type_id_off, mui->mui_type_id_size); + off += mui->mui_type_id_size; + } + if (mui->mui_type_name_off) + { + info->dwTypeNameMUIOffset = offsetof(FILEMUIINFO, abBuffer[off]); + memcpy(info->abBuffer + off, ((BYTE *)mui) + mui->mui_type_name_off, mui->mui_type_name_size); + off += mui->mui_type_name_size; + } + } + else if(flags & MUI_QUERY_RESOURCE_TYPES) + { + if (mui->ln_type_id_size && mui->ln_type_id_off) + { + info->dwTypeIDMUISize = mui->ln_type_id_size / sizeof(DWORD); + info->dwTypeIDMUIOffset = offsetof(FILEMUIINFO, abBuffer[off]); + memcpy(info->abBuffer + off, ((BYTE *)mui) + mui->ln_type_id_off, mui->ln_type_id_size); + off += mui->ln_type_id_size; + } + if (mui->ln_type_name_off) + { + info->dwTypeNameMUIOffset = offsetof(FILEMUIINFO, abBuffer[off]); + memcpy(info->abBuffer + off, ((BYTE *)mui) + mui->ln_type_name_off, mui->ln_type_name_size); + off += mui->ln_type_name_size; + } + } + + FreeLibrary( hmod ); + return TRUE; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/kernel32/tests/resource.c | 244 +++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+)
diff --git a/dlls/kernel32/tests/resource.c b/dlls/kernel32/tests/resource.c index 6c5bc99c0c5..9dfbd5ae4b0 100644 --- a/dlls/kernel32/tests/resource.c +++ b/dlls/kernel32/tests/resource.c @@ -520,6 +520,249 @@ static void test_internal_structure(void) ok( EndUpdateResourceW( res, TRUE ), "EndUpdateResourceW failed\n"); }
+static const struct +{ + IMAGE_DOS_HEADER dos; + IMAGE_NT_HEADERS nt; + IMAGE_SECTION_HEADER section; +} dll_image = +{ + { IMAGE_DOS_SIGNATURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, 0, 0, { 0 }, + sizeof(IMAGE_DOS_HEADER) }, + { + IMAGE_NT_SIGNATURE, /* Signature */ + { +#if defined __i386__ + IMAGE_FILE_MACHINE_I386, /* Machine */ +#elif defined __x86_64__ + IMAGE_FILE_MACHINE_AMD64, /* Machine */ +#elif defined __arm__ + IMAGE_FILE_MACHINE_ARMNT, /* Machine */ +#elif defined __aarch64__ + IMAGE_FILE_MACHINE_ARM64, /* Machine */ +#else +# error You must specify the machine type +#endif + 1, /* NumberOfSections */ + 0, /* TimeDateStamp */ + 0, /* PointerToSymbolTable */ + 0, /* NumberOfSymbols */ + sizeof(IMAGE_OPTIONAL_HEADER), /* SizeOfOptionalHeader */ + IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL /* Characteristics */ + }, + { IMAGE_NT_OPTIONAL_HDR_MAGIC, /* Magic */ + 1, /* MajorLinkerVersion */ + 0, /* MinorLinkerVersion */ + 0, /* SizeOfCode */ + 0, /* SizeOfInitializedData */ + 0, /* SizeOfUninitializedData */ + 0, /* AddressOfEntryPoint */ + 0x1000, /* BaseOfCode */ +#ifndef _WIN64 + 0, /* BaseOfData */ +#endif + 0x10000000, /* ImageBase */ + 0x1000, /* SectionAlignment */ + 0x1000, /* FileAlignment */ + 4, /* MajorOperatingSystemVersion */ + 0, /* MinorOperatingSystemVersion */ + 1, /* MajorImageVersion */ + 0, /* MinorImageVersion */ + 4, /* MajorSubsystemVersion */ + 0, /* MinorSubsystemVersion */ + 0, /* Win32VersionValue */ + 0x3000, /* SizeOfImage */ + sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS), + 0, /* CheckSum */ + IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */ + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT, /* DllCharacteristics */ + 0, /* SizeOfStackReserve */ + 0, /* SizeOfStackCommit */ + 0, /* SizeOfHeapReserve */ + 0, /* SizeOfHeapCommit */ + 0, /* LoaderFlags */ + IMAGE_FILE_RESOURCE_DIRECTORY + 1, /* NumberOfRvaAndSizes */ + { { 0 }, { 0 }, { 0x1000, 0x1000 } } /* DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */ + } + }, + { ".rsrc\0\0", { 0 }, 0x1000, 0x1000, 0, 0, 0, 0, 0, + IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ } +}; + +static void create_test_dll( const WCHAR *name ) +{ + DWORD dummy; + HANDLE handle = CreateFileW( name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 ); + + ok( handle != INVALID_HANDLE_VALUE, "failed to create file err %lu\n", GetLastError() ); + WriteFile( handle, &dll_image, sizeof(dll_image), &dummy, NULL ); + SetFilePointer( handle, dll_image.nt.OptionalHeader.SizeOfImage, NULL, FILE_BEGIN ); + SetEndOfFile( handle ); + CloseHandle( handle ); +} + +static struct mui_res +{ + DWORD signature; + DWORD size; + DWORD version; + DWORD path_type; + DWORD file_type; + DWORD system_attributes; + DWORD fallback_location; + BYTE service_checksum[16]; + BYTE checksum[16]; + DWORD unk1[2]; + DWORD mui_path_off; + DWORD mui_path_size; + DWORD unk2[2]; + DWORD ln_type_name_off; + DWORD ln_type_name_size; + DWORD ln_type_id_off; + DWORD ln_type_id_size; + DWORD mui_type_name_off; + DWORD mui_type_name_size; + DWORD mui_type_id_off; + DWORD mui_type_id_size; + DWORD lang_off; + DWORD lang_size; + DWORD fallback_lang_off; + DWORD fallback_lang_size; + WCHAR ln_type_names[8]; + DWORD ln_type_ids[1]; + WCHAR mui_type_names[8]; + DWORD mui_type_ids[1]; + WCHAR lang[8]; + WCHAR fallback_lang[8]; +} ln_mui_res = { + 0xfecdfecd, sizeof(ln_mui_res), 0x10000, 0, + MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN >> 1, + 0, 0, {'s','c'}, {'c'}, {0}, 0, 0, {0}, + offsetof(struct mui_res, ln_type_names), sizeof(L"MUI\0"), + offsetof(struct mui_res, ln_type_ids), sizeof(ln_mui_res.ln_type_ids), + offsetof(struct mui_res, mui_type_names), sizeof(L"MUI\0"), + offsetof(struct mui_res, mui_type_ids), sizeof(ln_mui_res.mui_type_ids), 0, 0, + offsetof(struct mui_res, fallback_lang), sizeof(L"en-US"), + {'M','U','I',0,0}, {RT_CURSOR}, {'M','U','I',0,0}, {RT_STRING}, {0}, {'e','n','-','U','S',0}, +}; + +static void test_mui(void) +{ + static const WCHAR ln_dll[] = L"test_mui.dll"; + static const BYTE zeros[16] = { 0 }; + BYTE buf[1024]; + FILEMUIINFO *info = (FILEMUIINFO *)buf; + const WCHAR *str; + DWORD size, *id; + HANDLE res; + BOOL r; + + size = 0; + r = GetFileMUIInfo( 0, ln_dll, NULL, &size); + ok( !r, "GetFileMUIInfo succeeded\n" ); + ok( GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError() = %ld\n", GetLastError() ); + + create_test_dll( ln_dll ); + + size = 0; + r = GetFileMUIInfo( 0, ln_dll, NULL, &size ); + ok( r, "GetFileMUIInfo failed: %ld\n", GetLastError() ); + ok( size == sizeof(*info), "unexpected size: %ld\n", size ); + + memset( buf, 0xfe, sizeof(buf) ); + size = sizeof(buf); + info->dwSize = sizeof(buf); + info->dwVersion = 0; + r = GetFileMUIInfo( 0, ln_dll, info, &size ); + ok( !r, "GetFileMUIInfo succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError() = %ld\n", GetLastError() ); + ok( !size, "size = %ld\n", size ); + + size = sizeof(buf); + info->dwVersion = MUI_FILEINFO_VERSION; + r = GetFileMUIInfo( 0, ln_dll, info, &size ); + ok( r, "GetFileMUIInfo failed: %ld\n", GetLastError() ); + ok( info->dwSize == sizeof(buf), "dwSize = %ld\n", info->dwSize ); + ok( info->dwVersion == MUI_FILEINFO_VERSION, "dwVersion = %ld\n", info->dwVersion ); + ok( info->dwFileType == MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL, "dwFileType = %ld\n", info->dwFileType ); + ok( !memcmp(info->pChecksum, zeros, sizeof(info->pChecksum)), "pChecksum = %s\n", + wine_dbgstr_an((char *)info->pChecksum, sizeof(info->pChecksum)) ); + ok( !memcmp(info->pServiceChecksum, zeros, sizeof(info->pServiceChecksum)), "pServiceChecksum = %s\n", + wine_dbgstr_an((char *)info->pServiceChecksum, sizeof(info->pServiceChecksum)) ); + ok( !info->dwLanguageNameOffset, "dwLanguageNameOffset = %ld\n", info->dwLanguageNameOffset ); + ok( !info->dwTypeIDMainSize, "dwTypeIDMainSize = %ld\n", info->dwTypeIDMainSize ); + ok( !info->dwTypeIDMainOffset, "dwTypeIDMainOffset = %ld\n", info->dwTypeIDMainOffset ); + ok( !info->dwTypeNameMainOffset, "dwTypeNameMainOffset = %ld\n", info->dwTypeNameMainOffset ); + ok( !info->dwTypeIDMUISize, "dwTypeIDMUISize = %ld\n", info->dwTypeIDMUISize ); + ok( !info->dwTypeIDMUIOffset, "dwTypeIDMUIOffset = %ld\n", info->dwTypeIDMUIOffset ); + ok( !info->dwTypeNameMUIOffset, "dwTypeNameMUIOffset = %ld\n", info->dwTypeNameMUIOffset ); + ok( !memcmp(info->abBuffer, zeros, sizeof(info->abBuffer)), "abBuffer = %s\n", + wine_dbgstr_an((char *)info->abBuffer, sizeof(info->abBuffer)) ); + + res = BeginUpdateResourceW( ln_dll, TRUE ); + ok( res != NULL, "BeginUpdateResourceW failed: %ld\n", GetLastError() ); + r = UpdateResourceW( res, L"MUI", MAKEINTRESOURCEW(1), 0, &ln_mui_res, 4 ); + ok( r, "UpdateResource failed: %ld\n", GetLastError() ); + ok( EndUpdateResourceW( res, FALSE ), "EndUpdateResourceW failed: %ld\n", GetLastError() ); + + size = 0; + r = GetFileMUIInfo( MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME + | MUI_QUERY_RESOURCE_TYPES, ln_dll, NULL, &size ); + ok( !r, "GetFileMUIInfo succeeded\n" ); + ok( GetLastError() == ERROR_BAD_EXE_FORMAT, "GetLastError() = %ld\n", GetLastError() ); + + res = BeginUpdateResourceW( ln_dll, TRUE ); + ok( res != NULL, "BeginUpdateResourceW failed: %ld\n", GetLastError() ); + r = UpdateResourceW( res, L"MUI", MAKEINTRESOURCEW(1), 0, &ln_mui_res, sizeof(ln_mui_res) ); + ok( r, "UpdateResource failed: %ld\n", GetLastError() ); + ok( EndUpdateResourceW( res, FALSE ), "EndUpdateResourceW failed: %ld\n", GetLastError() ); + + size = 0; + r = GetFileMUIInfo( MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME + | MUI_QUERY_RESOURCE_TYPES, ln_dll, NULL, &size ); + ok( !r, "GetFileMUIInfo succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() = %ld\n", GetLastError() ); + ok( size, "size was not set\n" ); + + memset( buf, 0xfe, sizeof(buf) ); + size = sizeof(buf); + info->dwSize = sizeof(buf); + info->dwVersion = MUI_FILEINFO_VERSION; + r = GetFileMUIInfo( MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME + | MUI_QUERY_RESOURCE_TYPES, ln_dll, info, &size ); + ok( r, "GetFileMUIInfo failed: %ld\n", GetLastError() ); + ok( info->dwSize == sizeof(buf), "dwSize = %ld\n", info->dwSize ); + ok( info->dwVersion == MUI_FILEINFO_VERSION, "dwVersion = %ld\n", info->dwVersion ); + ok( info->dwFileType == MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN, "dwFileType = %ld\n", info->dwFileType ); + ok( info->pChecksum[0] == 'c', "pChecksum = %s\n", + wine_dbgstr_an((char *)info->pChecksum, sizeof(info->pChecksum)) ); + ok( info->pServiceChecksum[0] == 's', "pServiceChecksum = %s\n", + wine_dbgstr_an((char *)info->pServiceChecksum, sizeof(info->pServiceChecksum)) ); + ok( info->dwLanguageNameOffset == 72, "dwLanguageNameOffset = %ld\n", info->dwLanguageNameOffset ); + str = (WCHAR *)(buf + info->dwLanguageNameOffset); + ok( !wcscmp(str, L"en-US"), "language name = %s\n", wine_dbgstr_w(str) ); + ok( info->dwTypeIDMainSize == 1, "dwTypeIDMainSize = %ld\n", info->dwTypeIDMainSize ); + ok( info->dwTypeIDMainOffset == 84, "dwTypeIDMainOffset = %ld\n", info->dwTypeIDMainOffset ); + id = (DWORD *)(buf + info->dwTypeIDMainOffset); + ok( id[0] == RT_CURSOR, "type ID main[0] = %ld\n", id[0] ); + ok( info->dwTypeNameMainOffset == 88, "dwTypeNameMainOffset = %ld\n", info->dwTypeNameMainOffset ); + str = (WCHAR *)(buf + info->dwTypeNameMainOffset); + ok( !wcscmp(str, L"MUI"), "type name main[0] = %s\n", wine_dbgstr_w(str) ); + str += wcslen(str) + 1; + ok( !str[0], "string list is not NULL terminated: %s\n", wine_dbgstr_w(str) ); + ok( info->dwTypeIDMUISize == 1, "dwTypeIDMUISize = %ld\n", info->dwTypeIDMUISize ); + ok( info->dwTypeIDMUIOffset == 98, "dwTypeIDMUIOffset = %ld\n", info->dwTypeIDMUIOffset ); + id = (DWORD *)(buf + info->dwTypeIDMUIOffset); + ok( id[0] == RT_STRING, "type ID MUI[0] = %ld\n", id[0] ); + ok( info->dwTypeNameMUIOffset == 102, "dwTypeNameMUIOffset = %ld\n", info->dwTypeNameMUIOffset ); + str = (WCHAR *)(buf + info->dwTypeNameMUIOffset); + ok( !wcscmp(str, L"MUI"), "type name MUI[0] = %s\n", wine_dbgstr_w(str) ); + str += wcslen(str) + 1; + ok( !str[0], "string list is not NULL terminated: %s\n", wine_dbgstr_w(str) ); + + DeleteFileW( ln_dll ); +} + START_TEST(resource) { DWORD i; @@ -552,4 +795,5 @@ START_TEST(resource) DeleteFileA( filename ); } test_find_resource(); + test_mui(); }
From: Piotr Caban piotr@codeweavers.com
--- dlls/kernel32/tests/resource.c | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
diff --git a/dlls/kernel32/tests/resource.c b/dlls/kernel32/tests/resource.c index 9dfbd5ae4b0..5f42d443eec 100644 --- a/dlls/kernel32/tests/resource.c +++ b/dlls/kernel32/tests/resource.c @@ -644,11 +644,20 @@ static struct mui_res offsetof(struct mui_res, mui_type_ids), sizeof(ln_mui_res.mui_type_ids), 0, 0, offsetof(struct mui_res, fallback_lang), sizeof(L"en-US"), {'M','U','I',0,0}, {RT_CURSOR}, {'M','U','I',0,0}, {RT_STRING}, {0}, {'e','n','-','U','S',0}, +}, en_mui_res = { + 0xfecdfecd, sizeof(ln_mui_res), 0x10000, 0, + MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI >> 1, + 0, 0, {'s','c'}, {'c'}, {0}, 0, 0, {0}, + offsetof(struct mui_res, ln_type_names), sizeof(L"MUI\0"), + offsetof(struct mui_res, ln_type_ids), sizeof(ln_mui_res.ln_type_ids), + 0, 0, 0, 0, offsetof(struct mui_res, lang), sizeof(L"en-US"), 0, 0, + {'M','U','I',0,0}, {RT_STRING}, {0}, {0}, {'e','n','-','U','S',0} };
static void test_mui(void) { static const WCHAR ln_dll[] = L"test_mui.dll"; + static const WCHAR en_dll[] = L"en-US\test_mui.dll.mui"; static const BYTE zeros[16] = { 0 }; BYTE buf[1024]; FILEMUIINFO *info = (FILEMUIINFO *)buf; @@ -663,6 +672,8 @@ static void test_mui(void) ok( GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError() = %ld\n", GetLastError() );
create_test_dll( ln_dll ); + CreateDirectoryW( L"en-US", NULL ); + create_test_dll( en_dll );
size = 0; r = GetFileMUIInfo( 0, ln_dll, NULL, &size ); @@ -760,7 +771,45 @@ static void test_mui(void) str += wcslen(str) + 1; ok( !str[0], "string list is not NULL terminated: %s\n", wine_dbgstr_w(str) );
+ res = BeginUpdateResourceW( en_dll, TRUE ); + ok( res != NULL, "BeginUpdateResourceW failed: %ld\n", GetLastError() ); + r = UpdateResourceW( res, L"MUI", MAKEINTRESOURCEW(1), 0, &en_mui_res, sizeof(en_mui_res) ); + ok( r, "UpdateResource failed: %ld\n", GetLastError() ); + ok( EndUpdateResourceW( res, FALSE ), "EndUpdateResourceW failed: %ld\n", GetLastError() ); + + memset( buf, 0xfe, sizeof(buf) ); + size = sizeof(buf); + info->dwSize = sizeof(buf); + info->dwVersion = MUI_FILEINFO_VERSION; + r = GetFileMUIInfo( MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM | MUI_QUERY_LANGUAGE_NAME + | MUI_QUERY_RESOURCE_TYPES, en_dll, info, &size ); + ok( r, "GetFileMUIInfo failed: %ld\n", GetLastError() ); + ok( info->dwSize == sizeof(buf), "dwSize = %ld\n", info->dwSize ); + ok( info->dwVersion == MUI_FILEINFO_VERSION, "dwVersion = %ld\n", info->dwVersion ); + ok( info->dwFileType == MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI, "dwFileType = %ld\n", info->dwFileType ); + ok( info->pChecksum[0] == 'c', "pChecksum = %s\n", + wine_dbgstr_an((char *)info->pChecksum, sizeof(info->pChecksum)) ); + ok( info->pServiceChecksum[0] == 's', "pServiceChecksum = %s\n", + wine_dbgstr_an((char *)info->pServiceChecksum, sizeof(info->pServiceChecksum)) ); + ok( info->dwLanguageNameOffset == 72, "dwLanguageNameOffset = %ld\n", info->dwLanguageNameOffset ); + str = (WCHAR *)(buf + info->dwLanguageNameOffset); + ok( !wcscmp(str, L"en-US"), "language name = %s\n", wine_dbgstr_w(str) ); + ok( !info->dwTypeIDMainSize, "dwTypeIDMainSize = %ld\n", info->dwTypeIDMainSize ); + ok( !info->dwTypeIDMainOffset, "dwTypeIDMainOffset = %ld\n", info->dwTypeIDMainOffset ); + ok( !info->dwTypeNameMainOffset, "dwTypeNameMainOffset = %ld\n", info->dwTypeNameMainOffset ); + ok( info->dwTypeIDMUISize == 1, "dwTypeIDMUISize = %ld\n", info->dwTypeIDMUISize ); + ok( info->dwTypeIDMUIOffset == 84, "dwTypeIDMUIOffset = %ld\n", info->dwTypeIDMUIOffset ); + id = (DWORD *)(buf + info->dwTypeIDMUIOffset); + ok( id[0] == RT_STRING, "type ID MUI[0] = %ld\n", id[0] ); + ok( info->dwTypeNameMUIOffset == 88, "dwTypeNameMUIOffset = %ld\n", info->dwTypeNameMUIOffset ); + str = (WCHAR *)(buf + info->dwTypeNameMUIOffset); + ok( !wcscmp(str, L"MUI"), "type name MUI[0] = %s\n", wine_dbgstr_w(str) ); + str += wcslen(str) + 1; + ok( !str[0], "string list is not NULL terminated: %s\n", wine_dbgstr_w(str) ); + DeleteFileW( ln_dll ); + DeleteFileW( en_dll ); + RemoveDirectoryW( L"en-US" ); }
START_TEST(resource)
There was a previous attempt, that didn't receive any response:
https://www.winehq.org/mailman3/hyperkitty/list/wine-devel@winehq.org/thread...
https://www.winehq.org/mailman3/hyperkitty/list/wine-devel@winehq.org/thread...
On Fri Jun 14 14:08:18 2024 +0000, Dmitry Timoshkov wrote:
There was a previous attempt, that didn't receive any response: https://www.winehq.org/mailman3/hyperkitty/list/wine-devel@winehq.org/thread... https://www.winehq.org/mailman3/hyperkitty/list/wine-devel@winehq.org/thread...
I didn't try running your code but from a quick look I don't see anything missing in my implementation. There are some things missing in you patches (like e.g. handling of language resource files, dwFileType is set incorrectly). The biggest difference is in tests - I think it's better to test the function on generated file.
FWIW test failure looks unrelated.
On Fri Jun 14 14:08:18 2024 +0000, Piotr Caban wrote:
I didn't try running your code but from a quick look I don't see anything missing in my implementation. There are some things missing in you patches (like e.g. handling of language resource files, dwFileType is set incorrectly). The biggest difference is in tests - I think it's better to test the function on generated file.
Missing things are a pretty minor detail, the patches could be improved if desired, for instance by sending improvements on top of existing patches instead of a completely new implementation. I'm mostly wanted to point out to a previous submission that was obviosuly ignored for unknown reasons.