From: Mark Harmstone Subject: [PATCH 2/2] kernel32: Implement GetFileMUIInfo. Message-Id: <555E63C9.5050106@burntcomma.com> Date: Fri, 22 May 2015 00:01:29 +0100 --- dlls/kernel32/locale.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 208 insertions(+), 3 deletions(-) diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index bf4ace5..ac79f2a 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -149,6 +149,35 @@ struct locale_name UINT codepage; /* codepage corresponding to charset */ }; +struct mui_header +{ + DWORD signature; /* always 0xfecdfecd */ + DWORD size; /* size of whole MUI blob */ + DWORD version; /* equals 0x10000 */ + DWORD reserved1; /* equals 0 */ + DWORD type; /* 0x11 for language-neutral file, 0x10 for MUI file */ + DWORD reserved2; /* equals 0 */ + DWORD fallback_location; /* fallback location */ + BYTE service_checksum[16]; /* service checksum */ + BYTE checksum[16]; /* checksum */ + BYTE padding[24]; + DWORD main_type_names_off; /* offset to language-neutral type names list */ + DWORD main_type_names_size; /* size of language-neutral type names list */ + DWORD main_type_ids_off; /* offset to language-neutral type IDs list */ + DWORD main_type_ids_size; /* size of language-neutral type IDs list */ + DWORD mui_type_names_off; /* offset to MUI type names list */ + DWORD mui_type_names_size; /* size of MUI type names list */ + DWORD mui_type_ids_off; /* offset to MUI type IDs list */ + DWORD mui_type_ids_size; /* size of MUI type IDs list */ + DWORD reserved3; /* equals 0 */ + DWORD reserved4; /* equals 0 */ + DWORD fallback_lang_off; /* offset to fallback language */ + DWORD fallback_lang_size; /* size of fallback language */ +}; + +#define MUI_TYPE_LANGUAGE_NETURAL 0x11 +#define MUI_TYPE_MUI 0x10 + /* locale ids corresponding to the various Unix locale parameters */ static LCID lcid_LC_COLLATE; static LCID lcid_LC_CTYPE; @@ -5328,8 +5357,184 @@ BOOL WINAPI GetFileMUIPath(DWORD flags, PCWSTR filepath, PWSTR language, PULONG BOOL WINAPI GetFileMUIInfo(DWORD flags, PCWSTR path, FILEMUIINFO *info, DWORD *size) { - FIXME("stub: %u, %s, %p, %p\n", flags, debugstr_w(path), info, size); + HMODULE mod; + HRSRC rsrc; + struct mui_header* data; + BOOL ret = FALSE; + DWORD bufsize, offset; - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + static const WCHAR muiW[] = {'M','U','I',0}; + + TRACE("%u, %s, %p, %p\n", flags, debugstr_w(path), info, size); + + if (!path) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!size) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (flags == 0) + flags = MUI_QUERY_TYPE | MUI_QUERY_CHECKSUM; + + mod = LoadLibraryExW(path, NULL, LOAD_LIBRARY_AS_DATAFILE); + + if (!mod) { + WARN("LoadLibraryEx failed for %s\n", debugstr_w(path)); + + if (GetLastError() == ERROR_MOD_NOT_FOUND) + SetLastError(ERROR_FILE_NOT_FOUND); + + return FALSE; + } + + if (!info) { + if (flags & (MUI_QUERY_LANGUAGE_NAME | MUI_QUERY_RESOURCE_TYPES)) { + /* reproduce bug in Windows */ + SetLastError(ERROR_INSUFFICIENT_BUFFER); + } else { + *size = sizeof(FILEMUIINFO); + ret = TRUE; + } + goto exit; + } + + rsrc = FindResourceW(mod, MAKEINTRESOURCEW(1), muiW); + + if (!rsrc) { + info->dwFileType = MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL; + ret = TRUE; + goto exit; + } + + data = LoadResource(mod, rsrc); + + if (!data) { + WARN("failed to load MUI resource\n"); + info->dwFileType = MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL; + ret = TRUE; + goto exit; + } + + if (data->signature != 0xfecdfecd) { + WARN("invalid MUI signature\n"); + SetLastError(ERROR_MUI_INVALID_RC_CONFIG); + goto exit; + } + + if (info->dwSize < sizeof(FILEMUIINFO)) { + WARN("dwSize value was smaller than expected\n"); + *size = 0; + SetLastError(ERROR_INVALID_PARAMETER); + goto exit; + } + + if (flags & MUI_QUERY_TYPE) { + if (data->type == MUI_TYPE_LANGUAGE_NETURAL) + info->dwFileType = MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN; + else if (data->type == MUI_TYPE_MUI) + info->dwFileType = MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI; + else + info->dwFileType = MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL; + } + + if (data->type != MUI_TYPE_LANGUAGE_NETURAL && data->type != MUI_TYPE_MUI) + goto exit; + + if (flags & MUI_QUERY_CHECKSUM) { + memcpy(info->pServiceChecksum, data->service_checksum, sizeof(info->pServiceChecksum)); + memcpy(info->pChecksum, data->checksum, sizeof(info->pChecksum)); + } + + offset = 0; + bufsize = info->dwSize - offsetof(FILEMUIINFO, abBuffer); + + if (flags & MUI_QUERY_RESOURCE_TYPES) { + info->dwTypeIDMainSize = 0; + info->dwTypeIDMainOffset = 0; + info->dwTypeNameMainOffset = 0; + info->dwTypeIDMUISize = 0; + info->dwTypeIDMUIOffset = 0; + info->dwTypeNameMUIOffset = 0; + } + + if (flags & MUI_QUERY_LANGUAGE_NAME) { + info->dwLanguageNameOffset = 0; + + if (data->fallback_lang_off != 0 && data->fallback_lang_size != 0) { + if (offset + data->fallback_lang_size <= bufsize) { + memcpy(&info->abBuffer[offset], (BYTE*)data + data->fallback_lang_off, data->fallback_lang_size); + info->dwLanguageNameOffset = offsetof(FILEMUIINFO, abBuffer) + offset; + offset += data->fallback_lang_size; + } else { + WARN("buffer was too small\n"); + SetLastError(ERROR_INSUFFICIENT_BUFFER); + goto exit; + } + } + } + + if (flags & MUI_QUERY_RESOURCE_TYPES) { + if (data->mui_type_names_off != 0 && data->mui_type_names_size != 0) { + if (offset + data->mui_type_names_size <= bufsize) { + memcpy(&info->abBuffer[offset], (BYTE*)data + data->mui_type_names_off, data->mui_type_names_size); + info->dwTypeNameMUIOffset = offsetof(FILEMUIINFO, abBuffer) + offset; + offset += data->mui_type_names_size; + } else { + WARN("buffer was too small\n"); + SetLastError(ERROR_INSUFFICIENT_BUFFER); + goto exit; + } + } + + if (data->mui_type_ids_off != 0 && data->mui_type_ids_size != 0) { + if (offset + data->mui_type_ids_size <= bufsize) { + memcpy(&info->abBuffer[offset], (BYTE*)data + data->mui_type_ids_off, data->mui_type_ids_size); + info->dwTypeIDMUIOffset = offsetof(FILEMUIINFO, abBuffer) + offset; + info->dwTypeIDMUISize = data->mui_type_ids_size / sizeof(DWORD); + offset += data->mui_type_ids_size; + } else { + WARN("buffer was too small\n"); + SetLastError(ERROR_INSUFFICIENT_BUFFER); + goto exit; + } + } + + if (data->type == MUI_TYPE_LANGUAGE_NETURAL) { + if (data->main_type_names_off != 0 && data->main_type_names_size != 0) { + if (offset + data->main_type_names_size <= bufsize) { + memcpy(&info->abBuffer[offset], (BYTE*)data + data->main_type_names_off, data->main_type_names_size); + info->dwTypeNameMainOffset = offsetof(FILEMUIINFO, abBuffer) + offset; + offset += data->main_type_names_size; + } else { + WARN("buffer was too small\n"); + SetLastError(ERROR_INSUFFICIENT_BUFFER); + goto exit; + } + } + + if (data->main_type_ids_off != 0 && data->main_type_ids_size != 0) { + if (offset + data->main_type_ids_size <= bufsize) { + memcpy(&info->abBuffer[offset], (BYTE*)data + data->main_type_ids_off, data->main_type_ids_size); + info->dwTypeIDMainOffset = offsetof(FILEMUIINFO, abBuffer) + offset; + info->dwTypeIDMainSize = data->main_type_ids_size / sizeof(DWORD); + offset += data->main_type_ids_size; + } else { + WARN("buffer was too small\n"); + SetLastError(ERROR_INSUFFICIENT_BUFFER); + goto exit; + } + } + } + } + + ret = TRUE; + +exit: + FreeLibrary(mod); + + return ret; }