From a22a15dc5a1b383f0be74f6a4da8510412c61dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Sun, 26 Jan 2020 23:28:19 +0000 Subject: [PATCH 1/2] GWin32RegistryKey: add MUI capabilities to get_value() An extra argument to g_win32_registry_key_get_value_w() and g_win32_registry_key_get_value() indicates that RegLoadMUIStringW() should be used instead of RegQueryValueExW(). It only works on strings, and automatically resolves resource strings (the ones that start with "@"). The extra argument is needed to find resource DLLs that are only specified by their relative name. --- gio/gwin32appinfo.c | 20 +++ gio/gwin32registrykey.c | 310 +++++++++++++++++++++++++++++++++++++--- gio/gwin32registrykey.h | 12 +- glib.supp | 10 ++ 4 files changed, 334 insertions(+), 18 deletions(-) diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c index 446d88e52..829e8c481 100644 --- a/gio/gwin32appinfo.c +++ b/gio/gwin32appinfo.c @@ -601,6 +601,7 @@ read_handler_icon (GWin32RegistryKey *proxy_key, gchar *default_value; if (g_win32_registry_key_get_value (icon_key, + NULL, TRUE, "", &default_type, @@ -763,6 +764,7 @@ follow_class_chain_to_handler (const gunichar2 *program_id, if (key != NULL) { got_value = g_win32_registry_key_get_value_w (key, + NULL, TRUE, L"", &val_type, @@ -799,6 +801,7 @@ follow_class_chain_to_handler (const gunichar2 *program_id, return FALSE; got_value = g_win32_registry_key_get_value_w (key, + NULL, TRUE, L"", &val_type, @@ -826,6 +829,7 @@ follow_class_chain_to_handler (const gunichar2 *program_id, } got_value = g_win32_registry_key_get_value_w (key, + NULL, TRUE, L"", &val_type, @@ -890,6 +894,7 @@ get_url_association (const gunichar2 *schema) schema_rec = g_hash_table_lookup (urls, schema_folded); if (!g_win32_registry_key_get_value_w (user_choice, + NULL, TRUE, L"Progid", &val_type, @@ -1054,6 +1059,7 @@ get_file_ext (const gunichar2 *ext) if (user_choice != NULL) { if (g_win32_registry_key_get_value_w (user_choice, + NULL, TRUE, L"Progid", &val_type, @@ -1336,6 +1342,7 @@ collect_capable_apps_from_clients (GPtrArray *capable_apps, continue; if (g_win32_registry_key_get_value_w (system_client_type, + NULL, TRUE, L"", &default_type, @@ -1591,6 +1598,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea shell_open_command = NULL; success = g_win32_registry_key_get_value_w (shell_open_command_key, + NULL, TRUE, L"", &vtype, @@ -1655,6 +1663,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea fallback_friendly_name = NULL; success = g_win32_registry_key_get_value_w (appkey, + NULL, TRUE, L"", &vtype, @@ -1678,6 +1687,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea friendly_name = NULL; success = g_win32_registry_key_get_value_w (capabilities, + NULL, TRUE, L"LocalizedString", &vtype, @@ -1703,6 +1713,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea description = NULL; success = g_win32_registry_key_get_value_w (capabilities, + NULL, TRUE, L"ApplicationDescription", &vtype, @@ -1731,6 +1742,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea if (default_icon_key != NULL) { success = g_win32_registry_key_get_value_w (default_icon_key, + NULL, TRUE, L"", &vtype, @@ -1747,6 +1759,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea if (icon_source == NULL) { success = g_win32_registry_key_get_value_w (capabilities, + NULL, TRUE, L"ApplicationIcon", &vtype, @@ -1767,6 +1780,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea narrow_application_name = NULL; success = g_win32_registry_key_get_value_w (capabilities, + NULL, TRUE, L"ApplicationName", &vtype, @@ -2218,6 +2232,7 @@ read_exeapps (void) if (shell_open_command_key != NULL) { success = g_win32_registry_key_get_value_w (shell_open_command_key, + NULL, TRUE, L"", &vtype, @@ -2237,6 +2252,7 @@ read_exeapps (void) friendly_app_name = NULL; success = g_win32_registry_key_get_value_w (incapable_app, + NULL, TRUE, L"FriendlyAppName", &vtype, @@ -2251,6 +2267,7 @@ read_exeapps (void) no_open_with = FALSE; success = g_win32_registry_key_get_value_w (incapable_app, + NULL, TRUE, L"NoOpenWith", &vtype, @@ -2272,6 +2289,7 @@ read_exeapps (void) { success = g_win32_registry_key_get_value_w (default_icon_key, + NULL, TRUE, L"", &vtype, @@ -2590,6 +2608,7 @@ read_class_url (GWin32RegistryKey *classes_root, return; success = g_win32_registry_key_get_value_w (class_key, + NULL, TRUE, L"URL Protocol", &vtype, @@ -3980,6 +3999,7 @@ get_appath_for_exe (gunichar2 *exe_basename) return NULL; got_value = g_win32_registry_key_get_value_w (apppath_key, + NULL, TRUE, L"Path", &val_type, diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c index c19fede4e..e37953f9a 100644 --- a/gio/gwin32registrykey.c +++ b/gio/gwin32registrykey.c @@ -1838,9 +1838,117 @@ g_win32_registry_key_get_path_w (GWin32RegistryKey *key) return key->priv->absolute_path_w; } +/** + * g_win32_registry_get_os_dirs_w: + * + * Returns a list of directories for DLL lookups. + * Can be used with g_win32_registry_key_get_value_w(). + * + * Returns: (array zero-terminated=1) (transfer none): a %NULL-terminated array of UTF-16 strings. + * + * Since: 2.66 + */ +const gunichar2 * const * +g_win32_registry_get_os_dirs_w (void) +{ + static gunichar2 **mui_os_dirs = NULL; + + if (g_once_init_enter (&mui_os_dirs)) + { + gunichar2 **new_mui_os_dirs; + gunichar2 *system32 = NULL; + gunichar2 *syswow64 = NULL; + UINT buffer_size; + gsize array_index = 0; + + buffer_size = GetSystemWow64DirectoryW (NULL, 0); + + if (buffer_size > 0) + { + UINT copied; + syswow64 = g_malloc (buffer_size * sizeof (gunichar2)); + copied = GetSystemWow64DirectoryW (syswow64, buffer_size); + if (copied <= 0) + g_clear_pointer (&syswow64, g_free); + } + + buffer_size = GetSystemDirectoryW (NULL, 0); + + if (buffer_size > 0) + { + UINT copied; + system32 = g_malloc (buffer_size * sizeof (gunichar2)); + copied = GetSystemDirectoryW (system32, buffer_size); + if (copied <= 0) + g_clear_pointer (&system32, g_free); + } + + new_mui_os_dirs = g_new0 (gunichar2 *, 3); + + if (system32 != NULL) + new_mui_os_dirs[array_index++] = system32; + + if (syswow64 != NULL) + new_mui_os_dirs[array_index++] = syswow64; + + new_mui_os_dirs[array_index++] = NULL; + + g_once_init_leave (&mui_os_dirs, new_mui_os_dirs); + } + + return (const gunichar2 * const *) mui_os_dirs; +} + +/** + * g_win32_registry_get_os_dirs: + * + * Returns a list of directories for DLL lookups. + * Can be used with g_win32_registry_key_get_value(). + * + * Returns: (array zero-terminated=1) (transfer none): a %NULL-terminated array of UTF-8 strings. + * + * Since: 2.66 + */ +const gchar * const * +g_win32_registry_get_os_dirs (void) +{ + static gchar **mui_os_dirs = NULL; + + if (g_once_init_enter (&mui_os_dirs)) + { + gchar **new_mui_os_dirs; + gsize array_index; + gsize new_array_index; + const gunichar2 * const *mui_os_dirs_utf16 = g_win32_registry_get_os_dirs_w (); + + for (array_index = 0; mui_os_dirs_utf16[array_index] != NULL; array_index++) + ; + + new_mui_os_dirs = g_new0 (gchar *, array_index + 1); + + for (array_index = 0, new_array_index = 0; + mui_os_dirs_utf16[array_index] != NULL; + array_index++) + { + new_mui_os_dirs[new_array_index] = g_utf16_to_utf8 (mui_os_dirs_utf16[array_index], + -1, NULL, NULL, NULL); + if (new_mui_os_dirs[new_array_index] != NULL) + new_array_index += 1; + } + + g_once_init_leave (&mui_os_dirs, new_mui_os_dirs); + } + + return (const gchar * const *) mui_os_dirs; +} + /** * g_win32_registry_key_get_value: * @key: (in) (transfer none): a #GWin32RegistryKey + * @mui_dll_dirs: (in) (transfer none) (array zero-terminated=1) (optional): a %NULL-terminated + * array of directory names where the OS + * should look for a DLL indicated in a MUI string, if the + * DLL path in the string is not absolute * @auto_expand: (in) %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR * to G_WIN32_REGISTRY_VALUE_STR. * @value_name: (in) (transfer none): name of the value to get (in UTF-8). @@ -1854,12 +1962,32 @@ g_win32_registry_key_get_path_w (GWin32RegistryKey *key) * Get data from a value of a key. String data is guaranteed to be * appropriately terminated and will be in UTF-8. * + * When not %NULL, @mui_dll_dirs indicates that `RegLoadMUIStringW()` API + * should be used instead of the usual `RegQueryValueExW()`. This implies + * that the value being queried is of type `REG_SZ` or `REG_EXPAND_SZ` (if it is not, the function + * falls back to `RegQueryValueExW()`), and that this string must undergo special processing + * (see [`SHLoadIndirectString()` documentation](https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-shloadindirectstring) for an explanation on what + * kinds of strings are processed) to get the result. + * + * If no specific MUI DLL directories need to be used, pass + * the return value of g_win32_registry_get_os_dirs() as @mui_dll_dirs + * (as an bonus, the value from g_win32_registry_get_os_dirs() + * does not add any extra UTF8->UTF16 conversion overhead). + * + * @auto_expand works with @mui_dll_dirs, but only affects the processed + * string, making it somewhat useless. The unprocessed string is always expanded + * internally, if its type is `REG_EXPAND_SZ` - there is no need to enable + * @auto_expand for this to work. + * + * The API for this function changed in GLib 2.66 to add the @mui_dll_dirs argument. + * * Returns: %TRUE on success, %FALSE on failure. * - * Since: 2.46 + * Since: 2.66 **/ gboolean g_win32_registry_key_get_value (GWin32RegistryKey *key, + const gchar * const *mui_dll_dirs, gboolean auto_expand, const gchar *value_name, GWin32RegistryValueType *value_type, @@ -1874,6 +2002,9 @@ g_win32_registry_key_get_value (GWin32RegistryKey *key, gchar *value_data_u8; gsize value_data_u8_len; gboolean result; + gsize mui_dll_dirs_count; + gunichar2 **mui_dll_dirs_utf16; + const gchar * const *mui_os_dirs; g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE); g_return_val_if_fail (value_name != NULL, FALSE); @@ -1889,7 +2020,39 @@ g_win32_registry_key_get_value (GWin32RegistryKey *key, if (value_name_w == NULL) return FALSE; + mui_dll_dirs_utf16 = NULL; + mui_os_dirs = g_win32_registry_get_os_dirs (); + + if (mui_dll_dirs != NULL && + mui_dll_dirs != mui_os_dirs) + { + gsize mui_dll_dirs_index; + + mui_dll_dirs_count = g_strv_length ((gchar **) mui_dll_dirs); + + if (mui_dll_dirs_count > 0) + { + mui_dll_dirs_utf16 = g_new0 (gunichar2 *, mui_dll_dirs_count + 1); + + for (mui_dll_dirs_count = 0, mui_dll_dirs_index = 0; + mui_dll_dirs[mui_dll_dirs_index] != NULL; + mui_dll_dirs_index++) + { + mui_dll_dirs_utf16[mui_dll_dirs_count] = g_utf8_to_utf16 (mui_dll_dirs[mui_dll_dirs_index], + -1, NULL, NULL, NULL); + if (mui_dll_dirs_utf16[mui_dll_dirs_count] != NULL) + mui_dll_dirs_count += 1; + } + } + } + else if (mui_dll_dirs != NULL && + mui_dll_dirs == mui_os_dirs) + { + mui_dll_dirs_utf16 = (gunichar2 **) g_win32_registry_get_os_dirs_w (); + } + result = g_win32_registry_key_get_value_w (key, + (const gunichar2 * const *) mui_dll_dirs_utf16, auto_expand, value_name_w, &value_type_g, @@ -1898,6 +2061,14 @@ g_win32_registry_key_get_value (GWin32RegistryKey *key, error); g_free (value_name_w); + if (mui_dll_dirs_utf16 != NULL && + mui_dll_dirs != mui_os_dirs) + { + gsize array_index; + for (array_index = 0; mui_dll_dirs_utf16[array_index] != NULL; array_index++) + g_free (mui_dll_dirs_utf16[array_index]); + g_free (mui_dll_dirs_utf16); + } if (!result) return FALSE; @@ -1944,9 +2115,98 @@ g_win32_registry_key_get_value (GWin32RegistryKey *key, return TRUE; } +/* A wrapper that calls either RegQueryValueExW() or + * RegLoadMUIStringW() depending on the value of the + * last argument. + * Apart from the extra argument, the function behaves + * just like RegQueryValueExW(), with a few caveats. + */ +static LSTATUS +MuiRegQueryValueExW (HKEY hKey, + LPCWSTR lpValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData, + const gunichar2 * const *mui_dll_dirs) +{ + gsize dir_index; + LSTATUS result = ERROR_PATH_NOT_FOUND; + DWORD bufsize; + DWORD data_size; + PVOID old_value; + + if (mui_dll_dirs == NULL) + return RegQueryValueExW (hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); + + bufsize = 0; + + if (lpcbData != NULL) + bufsize = *lpcbData; + + if (mui_dll_dirs[0] != NULL) + { + /* Optimization: check that the value actually exists, + * before we start trying different mui dll dirs + */ + result = RegQueryValueExW (hKey, lpValueName, NULL, NULL, NULL, 0); + + if (result == ERROR_FILE_NOT_FOUND) + return result; + } + + Wow64DisableWow64FsRedirection (&old_value); + + /* Try with NULL dir first */ + result = RegLoadMUIStringW (hKey, + lpValueName, + (wchar_t *) lpData, + bufsize, + &data_size, + 0, + NULL); + + /* Not a MUI value, load normally */ + if (result == ERROR_INVALID_DATA) + { + Wow64RevertWow64FsRedirection (old_value); + + return RegQueryValueExW (hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); + } + + for (dir_index = 0; + result == ERROR_FILE_NOT_FOUND && + mui_dll_dirs[dir_index] != NULL; + dir_index++) + result = RegLoadMUIStringW (hKey, + lpValueName, + (wchar_t *) lpData, + bufsize, + &data_size, + 0, + mui_dll_dirs[dir_index]); + + Wow64RevertWow64FsRedirection (old_value); + + if (lpcbData != NULL && + result == ERROR_MORE_DATA) + *lpcbData = data_size; + + if (lpType != NULL && + result != ERROR_INVALID_DATA && + result != ERROR_FILE_NOT_FOUND) + *lpType = REG_SZ; + + return result; +} + /** * g_win32_registry_key_get_value_w: * @key: (in) (transfer none): a #GWin32RegistryKey + * @mui_dll_dirs: (in) (transfer none) (array zero-terminated=1) (optional): a %NULL-terminated + * array of directory names where the OS + * should look for a DLL indicated in a MUI string, if the + * DLL path in the string is not absolute * @auto_expand: (in) %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR * to G_WIN32_REGISTRY_VALUE_STR. * @value_name: (in) (transfer none): name of the value to get (in UTF-16). @@ -1957,8 +2217,6 @@ g_win32_registry_key_get_value (GWin32RegistryKey *key, * by @value_data. * @error: (nullable): a pointer to %NULL #GError, or %NULL * - * Get data from a value of a key. - * * Get data from a value of a key. String data is guaranteed to be * appropriately terminated and will be in UTF-16. * @@ -1968,12 +2226,30 @@ g_win32_registry_key_get_value (GWin32RegistryKey *key, * termination cannot be checked and fixed unless the data is retreived * too. * + * When not %NULL, @mui_dll_dirs indicates that `RegLoadMUIStringW()` API + * should be used instead of the usual `RegQueryValueExW()`. This implies + * that the value being queried is of type `REG_SZ` or `REG_EXPAND_SZ` (if it is not, the function + * falls back to `RegQueryValueExW()`), and that this string must undergo special processing + * (see [`SHLoadIndirectString()` documentation](https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-shloadindirectstring) for an explanation on what + * kinds of strings are processed) to get the result. + * + * If no specific MUI DLL directories need to be used, pass + * the return value of g_win32_registry_get_os_dirs_w() as @mui_dll_dirs. + * + * @auto_expand works with @mui_dll_dirs, but only affects the processed + * string, making it somewhat useless. The unprocessed string is always expanded + * internally, if its type is `REG_EXPAND_SZ` - there is no need to enable + * @auto_expand for this to work. + * + * The API for this function changed in GLib 2.66 to add the @mui_dll_dirs argument. + * * Returns: %TRUE on success, %FALSE on failure. * - * Since: 2.46 + * Since: 2.66 **/ gboolean g_win32_registry_key_get_value_w (GWin32RegistryKey *key, + const gunichar2 * const *mui_dll_dirs, gboolean auto_expand, const gunichar2 *value_name, GWin32RegistryValueType *value_type, @@ -2000,12 +2276,13 @@ g_win32_registry_key_get_value_w (GWin32RegistryKey *key, value_data_size != NULL, FALSE); req_value_data_size = 0; - status = RegQueryValueExW (key->priv->handle, - value_name, - NULL, - &value_type_w, - NULL, - &req_value_data_size); + status = MuiRegQueryValueExW (key->priv->handle, + value_name, + NULL, + &value_type_w, + NULL, + &req_value_data_size, + mui_dll_dirs); if (status != ERROR_MORE_DATA && status != ERROR_SUCCESS) { @@ -2032,12 +2309,13 @@ g_win32_registry_key_get_value_w (GWin32RegistryKey *key, req_value_data = g_malloc (req_value_data_size + sizeof (gunichar2) * 2); req_value_data_size2 = req_value_data_size; - status = RegQueryValueExW (key->priv->handle, - value_name, - NULL, - &value_type_w2, - (gpointer) req_value_data, - &req_value_data_size2); + status = MuiRegQueryValueExW (key->priv->handle, + value_name, + NULL, + &value_type_w2, + (gpointer) req_value_data, + &req_value_data_size2, + mui_dll_dirs); if (status != ERROR_SUCCESS) { diff --git a/gio/gwin32registrykey.h b/gio/gwin32registrykey.h index 52ccd5c0f..28b57a843 100644 --- a/gio/gwin32registrykey.h +++ b/gio/gwin32registrykey.h @@ -239,8 +239,9 @@ gboolean g_win32_registry_value_iter_get_data_w (GWin32RegistryValu gsize *value_data_size, GError **error); -GLIB_AVAILABLE_IN_2_46 +GLIB_AVAILABLE_IN_2_66 gboolean g_win32_registry_key_get_value (GWin32RegistryKey *key, + const gchar * const *mui_dll_dirs, gboolean auto_expand, const gchar *value_name, GWin32RegistryValueType *value_type, @@ -248,8 +249,9 @@ gboolean g_win32_registry_key_get_value (GWin32RegistryKey gsize *value_data_size, GError **error); -GLIB_AVAILABLE_IN_2_46 +GLIB_AVAILABLE_IN_2_66 gboolean g_win32_registry_key_get_value_w (GWin32RegistryKey *key, + const gunichar2 * const *mui_dll_dirs, gboolean auto_expand, const gunichar2 *value_name, GWin32RegistryValueType *value_type, @@ -276,6 +278,12 @@ gboolean g_win32_registry_key_has_changed (GWin32RegistryKey GLIB_AVAILABLE_IN_2_46 void g_win32_registry_key_erase_change_indicator (GWin32RegistryKey *key); +GLIB_AVAILABLE_IN_2_66 +const gunichar2 * const *g_win32_registry_get_os_dirs_w (void); + +GLIB_AVAILABLE_IN_2_66 +const gchar * const *g_win32_registry_get_os_dirs (void); + G_END_DECLS #endif /* G_PLATFORM_WIN32 */ diff --git a/glib.supp b/glib.supp index a59a9b905..83c30f9b1 100644 --- a/glib.supp +++ b/glib.supp @@ -887,6 +887,16 @@ fun:g_dbus_error_quark } +# g_win32_registry_get_os_dirs_w*() caches an array of strings that is allocated only once. +{ + g_win32_registry_get_os_dirs + Memcheck:Leak + match-leak-kinds:reachable,definite + fun:malloc + ... + fun:g_win32_registry_get_os_dirs* +} + # Thread-private data allocated once per thread { g_private_set_alloc0 From f77a6a1626854da338f85a787a9ccb93829a21f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Sun, 26 Jan 2020 23:42:31 +0000 Subject: [PATCH 2/2] GWin32AppInfo: Drop read_resource_string(), use GWin32RegistryKey Now GWin32RegistryKey can internally do the same thing that read_resource_string() does, and more. --- gio/gwin32appinfo.c | 92 +++-------------------------------------- gio/gwin32registrykey.c | 35 ++++++++++------ 2 files changed, 28 insertions(+), 99 deletions(-) diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c index 829e8c481..ec3e2b70c 100644 --- a/gio/gwin32appinfo.c +++ b/gio/gwin32appinfo.c @@ -497,80 +497,6 @@ static GWin32RegistryKey *classes_root_key; */ #include "giowin32-private.c" -static gunichar2 * -read_resource_string (gunichar2 *res) -{ - gunichar2 *id_str; - gunichar2 *id_str_end; - gunichar2 *filename_str; - unsigned long id; - HMODULE resource_module; - gunichar2 *buffer; - int string_length; - int buffer_length; - - if (res == NULL || res[0] != L'@') - return res; - - id_str = wcsrchr (res, L'-'); - - if (id_str == NULL || id_str[-1] != L',') - return res; - - id_str += 1; - - id = wcstoul (id_str, &id_str_end, 10); - - if (id_str_end == id_str || id_str_end[0] != L'\0' || id == ULONG_MAX) - return res; - - filename_str = &res[1]; - id_str[-2] = L'\0'; - - resource_module = LoadLibraryExW (filename_str, - 0, - LOAD_LIBRARY_AS_DATAFILE | - LOAD_LIBRARY_AS_IMAGE_RESOURCE); - - g_free (res); - - if (resource_module == NULL) - return NULL; - - buffer_length = 256; - string_length = buffer_length - 1; - - while (TRUE) - { - buffer = g_malloc (buffer_length * sizeof (gunichar2)); - string_length = LoadStringW (resource_module, id, buffer, buffer_length); - - if (string_length != 0 && string_length == buffer_length - 1) - { - g_free (buffer); - buffer_length *= 2; - } - else - { - if (string_length == 0) - g_clear_pointer (&buffer, g_free); - - break; - } - } - - FreeLibrary (resource_module); - - if (buffer) - { - gunichar2 *result = g_wcsdup (buffer, -1); - g_free (buffer); - return result; - } - - return NULL; -} - static void read_handler_icon (GWin32RegistryKey *proxy_key, GWin32RegistryKey *program_key, @@ -1687,7 +1613,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea friendly_name = NULL; success = g_win32_registry_key_get_value_w (capabilities, - NULL, + g_win32_registry_get_os_dirs_w (), TRUE, L"LocalizedString", &vtype, @@ -1695,11 +1621,9 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea NULL, NULL); - if (success && (vtype != G_WIN32_REGISTRY_VALUE_STR || friendly_name[0] != L'@')) + if (success && vtype != G_WIN32_REGISTRY_VALUE_STR) g_clear_pointer (&friendly_name, g_free); - friendly_name = read_resource_string (friendly_name); - if (friendly_name && app->localized_pretty_name == NULL) { app->localized_pretty_name = g_wcsdup (friendly_name, -1); @@ -1713,7 +1637,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea description = NULL; success = g_win32_registry_key_get_value_w (capabilities, - NULL, + g_win32_registry_get_os_dirs_w (), TRUE, L"ApplicationDescription", &vtype, @@ -1724,8 +1648,6 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea if (success && vtype != G_WIN32_REGISTRY_VALUE_STR) g_clear_pointer (&description, g_free); - description = read_resource_string (description); - if (description && app->description == NULL) { app->description = g_wcsdup (description, -1); @@ -1780,7 +1702,7 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea narrow_application_name = NULL; success = g_win32_registry_key_get_value_w (capabilities, - NULL, + g_win32_registry_get_os_dirs_w (), TRUE, L"ApplicationName", &vtype, @@ -1791,8 +1713,6 @@ read_capable_app (gunichar2 *input_app_key_path, gboolean user_specific, gboolea if (success && vtype != G_WIN32_REGISTRY_VALUE_STR) g_clear_pointer (&narrow_application_name, g_free); - narrow_application_name = read_resource_string (narrow_application_name); - /* TODO: do something with the narrow name. Maybe make a kind of sub-app? * Narrow name is a more precise name of the application in given context. * I.e. Thunderbird's name is "Thunderbird", whereas its narrow name is @@ -2252,7 +2172,7 @@ read_exeapps (void) friendly_app_name = NULL; success = g_win32_registry_key_get_value_w (incapable_app, - NULL, + g_win32_registry_get_os_dirs_w (), TRUE, L"FriendlyAppName", &vtype, @@ -2263,8 +2183,6 @@ read_exeapps (void) if (success && vtype != G_WIN32_REGISTRY_VALUE_STR) g_clear_pointer (&friendly_app_name, g_free); - friendly_app_name = read_resource_string (friendly_app_name); - no_open_with = FALSE; success = g_win32_registry_key_get_value_w (incapable_app, NULL, diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c index e37953f9a..9e6dd2ba9 100644 --- a/gio/gwin32registrykey.c +++ b/gio/gwin32registrykey.c @@ -1934,6 +1934,8 @@ g_win32_registry_get_os_dirs (void) -1, NULL, NULL, NULL); if (new_mui_os_dirs[new_array_index] != NULL) new_array_index += 1; + else + g_critical ("Failed to convert to a system directory #%zu to UTF-8", array_index); } g_once_init_leave (&mui_os_dirs, new_mui_os_dirs); @@ -2026,23 +2028,32 @@ g_win32_registry_key_get_value (GWin32RegistryKey *key, if (mui_dll_dirs != NULL && mui_dll_dirs != mui_os_dirs) { - gsize mui_dll_dirs_index; + gsize i; mui_dll_dirs_count = g_strv_length ((gchar **) mui_dll_dirs); + mui_dll_dirs_utf16 = g_new0 (gunichar2 *, mui_dll_dirs_count + 1); - if (mui_dll_dirs_count > 0) + for (i = 0; mui_dll_dirs[i] != NULL; i++) { - mui_dll_dirs_utf16 = g_new0 (gunichar2 *, mui_dll_dirs_count + 1); + mui_dll_dirs_utf16[i] = g_utf8_to_utf16 (mui_dll_dirs[i], -1, NULL, NULL, error); - for (mui_dll_dirs_count = 0, mui_dll_dirs_index = 0; - mui_dll_dirs[mui_dll_dirs_index] != NULL; - mui_dll_dirs_index++) - { - mui_dll_dirs_utf16[mui_dll_dirs_count] = g_utf8_to_utf16 (mui_dll_dirs[mui_dll_dirs_index], - -1, NULL, NULL, NULL); - if (mui_dll_dirs_utf16[mui_dll_dirs_count] != NULL) - mui_dll_dirs_count += 1; - } + if (mui_dll_dirs_utf16[i] == NULL) + break; + } + + if (mui_dll_dirs[i] != NULL) + { + g_prefix_error (error, + "A mui_dll_dirs string #%zu `%s' failed to convert: ", + i, mui_dll_dirs[i]); + + for (i = 0; i < mui_dll_dirs_count; i++) + g_free (mui_dll_dirs_utf16[i]); + + g_free (mui_dll_dirs_utf16); + g_free (value_name_w); + + return FALSE; } } else if (mui_dll_dirs != NULL &&