Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/kernel32/tests/resource.c | 7 ++ dlls/kernelbase/locale.c | 145 ++++++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 3 deletions(-)
diff --git a/dlls/kernel32/tests/resource.c b/dlls/kernel32/tests/resource.c index 626645a8979..f8a49990e6b 100644 --- a/dlls/kernel32/tests/resource.c +++ b/dlls/kernel32/tests/resource.c @@ -617,6 +617,7 @@ static void test_GetFileMUIInfo(void) ret = GetFileMUIInfo(0, path, info, &size); ok(!ret, "GetFileMUIInfo should fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + todo_wine ok(!size, "got %lu\n", size); ok(info->dwSize == sizeof(*info), "got %lu\n", info->dwSize); ok(!info->dwVersion, "got %08lx\n", info->dwVersion); @@ -653,7 +654,9 @@ static void test_GetFileMUIInfo(void) full_size = 0; SetLastError(0xdeadbeef); ret = GetFileMUIInfo(MUI_QUERY_ALL, path, NULL, &full_size); + todo_wine ok(!ret, "GetFileMUIInfo should fail\n"); + todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError());
memset(buf, 0, sizeof(buf)); @@ -666,7 +669,9 @@ static void test_GetFileMUIInfo(void) ok(!ret, "GetFileMUIInfo should fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); ok(info->dwVersion == 0, "got %08lx\n", info->dwVersion); + todo_wine ok(info->dwFileType == 0, "got %08lx\n", info->dwFileType); + todo_wine ok(!memcmp(info->abBuffer, zero, 8), "got %.8s\n", info->abBuffer);
memset(buf, 0, sizeof(buf)); @@ -700,8 +705,10 @@ static void test_GetFileMUIInfo(void) ret = GetFileMUIInfo(MUI_QUERY_ALL, path, info, &size); ok(!ret, "GetFileMUIInfo should fail\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError()); + todo_wine ok(size == 0, "got %08lx\n", size); ok(info->dwVersion == 0, "got %08lx\n", info->dwVersion); + todo_wine ok(info->dwFileType == 0, "got %08lx\n", info->dwFileType); ok(!memcmp(info->abBuffer, zero, 8), "got %.8s\n", info->abBuffer);
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index 0c20c858a7a..19c4707cec8 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -5699,15 +5699,154 @@ done: }
+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; + /****************************************************************************** * 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; + HMODULE module; + HRSRC rsrc; + MUI_RC_CONFIG *rc_cfg; + DWORD rc_size; + + TRACE( "(%08lx,%s,%p,%p)\n", flags, debugstr_w(path), info, size ); + + if (!size) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (info) + { + if (*size < sizeof(FILEMUIINFO)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + if (*size != info->dwSize || !info->dwVersion) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + } + else if (*size) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + module = LoadLibraryExW( path, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE ); + if (!module) return FALSE; + + rsrc = FindResourceW( module, MAKEINTRESOURCEW(1), L"MUI" ); + if (!rsrc) + { + FreeLibrary( module ); + return FALSE; + } + + rc_cfg = LockResource( LoadResource( module, rsrc ) ); + + rc_size = sizeof(*info); + if (flags & MUI_QUERY_RESOURCE_TYPES) + { + rc_size += rc_cfg->dwTypeNameMainSize; + rc_size += rc_cfg->dwTypeIDMainSize; + rc_size += rc_cfg->dwTypeNameMUISize; + rc_size += rc_cfg->dwTypeIDMUISize; + } + if (flags & MUI_QUERY_LANGUAGE_NAME) + rc_size += rc_cfg->dwLanguageNameSize; + + if (info) + { + char *p = (char *)(info + 1); + DWORD offset = sizeof(*info); + + memset( (char *)info + 8, 0, *size - 8 ); /* keep original dwSize/dwVersion */ + + if (flags & MUI_QUERY_TYPE) + info->dwFileType = rc_cfg->dwFileType; + + if (flags & MUI_QUERY_CHECKSUM) + { + memcpy( info->pChecksum, rc_cfg->pChecksum, sizeof(info->pChecksum) ); + memcpy( info->pServiceChecksum, rc_cfg->pServiceChecksum, sizeof(info->pServiceChecksum) ); + } + + if (*size < rc_size) + { + FreeLibrary( module ); + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + if (flags & MUI_QUERY_RESOURCE_TYPES) + { + info->dwTypeNameMainOffset = offset; + memcpy( p, (char *)rc_cfg + rc_cfg->dwTypeNameMainOffset, rc_cfg->dwTypeNameMainSize ); + p += rc_cfg->dwTypeNameMainSize; + offset += rc_cfg->dwTypeNameMainSize; + + info->dwTypeIDMainOffset = offset; + info->dwTypeIDMainSize = rc_cfg->dwTypeIDMainSize / sizeof(DWORD); + memcpy( p, (char *)rc_cfg + rc_cfg->dwTypeIDMainOffset, rc_cfg->dwTypeIDMainSize ); + p += rc_cfg->dwTypeIDMainSize; + offset += rc_cfg->dwTypeIDMainSize; + + info->dwTypeNameMUIOffset = offset; + memcpy( p, (char *)rc_cfg + rc_cfg->dwTypeNameMUIOffset, rc_cfg->dwTypeNameMUISize ); + p += rc_cfg->dwTypeNameMUISize; + offset += rc_cfg->dwTypeNameMUISize; + + info->dwTypeIDMUIOffset = offset; + info->dwTypeIDMUISize = rc_cfg->dwTypeIDMUISize / sizeof(DWORD); + memcpy( p, (char *)rc_cfg + rc_cfg->dwTypeIDMUIOffset, rc_cfg->dwTypeIDMUISize ); + p += rc_cfg->dwTypeIDMUISize; + offset += rc_cfg->dwTypeIDMUISize; + } + + if (flags & MUI_QUERY_LANGUAGE_NAME) + { + info->dwLanguageNameOffset = offset; + memcpy( p, (char *)rc_cfg + rc_cfg->dwLanguageNameOffset, rc_cfg->dwLanguageNameSize ); + } + } + else + *size = rc_size; + + FreeLibrary( module ); + + return TRUE; }