forked from msys2/MINGW-packages
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
glib2: backport some Windows improvements
Fixes msys2#9154
- Loading branch information
Showing
3 changed files
with
279 additions
and
1 deletion.
There are no files selected for viewing
190 changes: 190 additions & 0 deletions
190
mingw-w64-glib2/0003-GWin32Mount-Don-t-use-SHGetFileInfoW-for-icons.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
From d1c542254fe44bdd6ad43574adb571222465b126 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?= <lrn1986@gmail.com> | ||
Date: Tue, 30 Mar 2021 19:39:20 +0000 | ||
Subject: [PATCH 1/2] GWin32Mount: Don't use SHGetFileInfoW() for icons | ||
|
||
This function can cause significant delays when the mounted volume | ||
is disconnected or just weird. Use IExtractIconW::GetIconLocation() | ||
instead. | ||
|
||
Theoretically, this should require COM to be initialized, but in my tests | ||
this code worked just fine without calling CoInitializeEx(). | ||
--- | ||
gio/gwin32mount.c | 141 ++++++++++++++++++++++++++++++++++++++++++++-- | ||
1 file changed, 136 insertions(+), 5 deletions(-) | ||
|
||
diff --git a/gio/gwin32mount.c b/gio/gwin32mount.c | ||
index 83d8695a1..6388beb11 100644 | ||
--- a/gio/gwin32mount.c | ||
+++ b/gio/gwin32mount.c | ||
@@ -25,7 +25,47 @@ | ||
|
||
#include <string.h> | ||
#define WIN32_MEAN_AND_LEAN | ||
+#define COBJMACROS | ||
#include <windows.h> | ||
+#include <shlobj.h> | ||
+#include <shlwapi.h> | ||
+ | ||
+/* At the moment of writing IExtractIconW interface in Mingw-w64 | ||
+ * is missing IUnknown members in its vtable. Use our own | ||
+ * fixed declaration for now. | ||
+ */ | ||
+#undef INTERFACE | ||
+#define INTERFACE IMyExtractIconW | ||
+DECLARE_INTERFACE_(IMyExtractIconW,IUnknown) | ||
+{ | ||
+ /*** IUnknown methods ***/ | ||
+ STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; | ||
+ STDMETHOD_(ULONG,AddRef)(THIS) PURE; | ||
+ STDMETHOD_(ULONG,Release)(THIS) PURE; | ||
+ /*** IMyExtractIconW methods ***/ | ||
+ STDMETHOD(GetIconLocation)(THIS_ UINT uFlags, LPWSTR pszIconFile, UINT cchMax, int *piIndex, PUINT pwFlags) PURE; | ||
+ STDMETHOD(Extract)(THIS_ LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) PURE; | ||
+}; | ||
+#undef INTERFACE | ||
+ | ||
+#if !defined(__cplusplus) || defined(CINTERFACE) | ||
+/*** IUnknown methods ***/ | ||
+#define IMyExtractIconW_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) | ||
+#define IMyExtractIconW_AddRef(p) (p)->lpVtbl->AddRef(p) | ||
+#define IMyExtractIconW_Release(p) (p)->lpVtbl->Release(p) | ||
+/*** IMyExtractIconW methods ***/ | ||
+#define IMyExtractIconW_GetIconLocation(p,a,b,c,d,e) (p)->lpVtbl->GetIconLocation(p,a,b,c,d,e) | ||
+#define IMyExtractIconW_Extract(p,a,b,c,d,e) (p)->lpVtbl->Extract(p,a,b,c,d,e) | ||
+#else | ||
+/*** IUnknown methods ***/ | ||
+#define IMyExtractIconW_QueryInterface(p,a,b) (p)->QueryInterface(a,b) | ||
+#define IMyExtractIconW_AddRef(p) (p)->AddRef() | ||
+#define IMyExtractIconW_Release(p) (p)->Release() | ||
+/*** IMyExtractIconW methods ***/ | ||
+#define IMyExtractIconW_GetIconLocation(p,a,b,c,d,e) (p)->GetIconLocation(p,a,b,c,d,e) | ||
+#define IMyExtractIconW_Extract(p,a,b,c,d,e) (p)->Extract(p,a,b,c,d,e) | ||
+#endif | ||
+ | ||
|
||
#include <glib.h> | ||
#include "gwin32volumemonitor.h" | ||
@@ -210,6 +250,92 @@ _win32_drive_type_to_icon (int type, gboolean use_symbolic) | ||
} | ||
} | ||
|
||
+/* mount_path doesn't need to end with a path separator. | ||
+ mount_path must use backslashes as path separators, not slashes. | ||
+ IShellFolder::ParseDisplayName() takes non-const string as input, | ||
+ so mount_path can't be a const string. | ||
+ result_name and result_index must not be NULL. | ||
+ Returns TRUE when result_name is set (free with g_free), | ||
+ FALSE otherwise. | ||
+ */ | ||
+static gboolean | ||
+get_icon_name_index (wchar_t *mount_path, | ||
+ wchar_t **result_name, | ||
+ int *result_index) | ||
+{ | ||
+ IShellFolder *desktop; | ||
+ PIDLIST_RELATIVE volume; | ||
+ IShellFolder *volume_parent; | ||
+ PCUITEMID_CHILD volume_relative; | ||
+ IMyExtractIconW *eicon; | ||
+ int icon_index; | ||
+ UINT icon_flags; | ||
+ wchar_t *name_buffer; | ||
+ gsize name_buffer_size; | ||
+ gsize arbitrary_reasonable_limit = 5000; | ||
+ gboolean result = FALSE; | ||
+ | ||
+ *result_name = NULL; | ||
+ | ||
+ /* Get the desktop folder object reference */ | ||
+ if (!SUCCEEDED (SHGetDesktopFolder (&desktop))) | ||
+ return FALSE; | ||
+ | ||
+ /* Construct the volume IDList relative to desktop */ | ||
+ if (SUCCEEDED (IShellFolder_ParseDisplayName (desktop, NULL, NULL, mount_path, NULL, &volume, NULL))) | ||
+ { | ||
+ /* Get the parent of the volume (transfer-full) and the IDList relative to parent (transfer-none) */ | ||
+ if (SUCCEEDED (SHBindToParent (volume, &IID_IShellFolder, (void **) &volume_parent, &volume_relative))) | ||
+ { | ||
+ /* Get a reference to IExtractIcon object for the volume */ | ||
+ if (SUCCEEDED (IShellFolder_GetUIObjectOf (volume_parent, NULL, 1, (LPCITEMIDLIST *) &volume_relative, &IID_IExtractIconW, NULL, (void **) &eicon))) | ||
+ { | ||
+ gboolean keep_going = TRUE; | ||
+ name_buffer = NULL; | ||
+ name_buffer_size = MAX_PATH / 2; | ||
+ while (keep_going) | ||
+ { | ||
+ name_buffer_size *= 2; | ||
+ name_buffer = g_renew (wchar_t, name_buffer, name_buffer_size); | ||
+ name_buffer[name_buffer_size - 1] = 0x1; /* sentinel */ | ||
+ keep_going = FALSE; | ||
+ | ||
+ /* Try to get the icon location */ | ||
+ if (SUCCEEDED (IMyExtractIconW_GetIconLocation (eicon, GIL_FORSHELL, name_buffer, name_buffer_size, &icon_index, &icon_flags))) | ||
+ { | ||
+ if (name_buffer[name_buffer_size - 1] != 0x1) | ||
+ { | ||
+ if (name_buffer_size < arbitrary_reasonable_limit) | ||
+ { | ||
+ /* Buffer was too small, keep going */ | ||
+ keep_going = TRUE; | ||
+ continue; | ||
+ } | ||
+ /* Else stop trying */ | ||
+ } | ||
+ /* name_buffer might not contain a name */ | ||
+ else if ((icon_flags & GIL_NOTFILENAME) != GIL_NOTFILENAME) | ||
+ { | ||
+ *result_name = g_steal_pointer (&name_buffer); | ||
+ *result_index = icon_index; | ||
+ result = TRUE; | ||
+ } | ||
+ } | ||
+ } | ||
+ | ||
+ g_free (name_buffer); | ||
+ IMyExtractIconW_Release (eicon); | ||
+ } | ||
+ IShellFolder_Release (volume_parent); | ||
+ } | ||
+ CoTaskMemFree (volume); | ||
+ } | ||
+ | ||
+ IShellFolder_Release (desktop); | ||
+ | ||
+ return result; | ||
+} | ||
+ | ||
static GIcon * | ||
g_win32_mount_get_icon (GMount *mount) | ||
{ | ||
@@ -220,15 +346,20 @@ g_win32_mount_get_icon (GMount *mount) | ||
/* lazy creation */ | ||
if (!win32_mount->icon) | ||
{ | ||
- SHFILEINFOW shfi; | ||
+ wchar_t *icon_path; | ||
+ int icon_index; | ||
+ wchar_t *p; | ||
wchar_t *wfn = g_utf8_to_utf16 (win32_mount->mount_path, -1, NULL, NULL, NULL); | ||
|
||
- if (SHGetFileInfoW (wfn, 0, &shfi, sizeof (shfi), SHGFI_ICONLOCATION)) | ||
+ for (p = wfn; p != NULL && *p != 0; p++) | ||
+ if (*p == L'/') | ||
+ *p = L'\\'; | ||
+ | ||
+ if (get_icon_name_index (wfn, &icon_path, &icon_index)) | ||
{ | ||
- gchar *name = g_utf16_to_utf8 (shfi.szDisplayName, -1, NULL, NULL, NULL); | ||
- gchar *id = g_strdup_printf ("%s,%i", name, shfi.iIcon); | ||
+ gchar *id = g_strdup_printf ("%S,%i", icon_path, icon_index); | ||
+ g_free (icon_path); | ||
win32_mount->icon = g_themed_icon_new (id); | ||
- g_free (name); | ||
g_free (id); | ||
} | ||
else | ||
-- | ||
2.32.0 | ||
|
79 changes: 79 additions & 0 deletions
79
mingw-w64-glib2/0004-GWin32Mount-Don-t-use-SHGetFileInfoW-for-mount-displ.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
From cb994350c427b8c5e514ecb26fd036d889cfd839 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?= <lrn1986@gmail.com> | ||
Date: Tue, 30 Mar 2021 20:27:25 +0000 | ||
Subject: [PATCH 2/2] GWin32Mount: Don't use SHGetFileInfoW() for mount | ||
displaynames | ||
|
||
This function can create long delays when used on disconnected | ||
or just weird volumes. Use IShellFolder::GetDisplayNameOf() instead. | ||
|
||
Fixes #2096 | ||
--- | ||
gio/gwin32mount.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- | ||
1 file changed, 42 insertions(+), 4 deletions(-) | ||
|
||
diff --git a/gio/gwin32mount.c b/gio/gwin32mount.c | ||
index 6388beb11..f5be8adfa 100644 | ||
--- a/gio/gwin32mount.c | ||
+++ b/gio/gwin32mount.c | ||
@@ -143,14 +143,52 @@ g_win32_mount_init (GWin32Mount *win32_mount) | ||
{ | ||
} | ||
|
||
+/* wdrive doesn't need to end with a path separator. | ||
+ wdrive must use backslashes as path separators, not slashes. | ||
+ IShellFolder::ParseDisplayName() takes non-const string as input, | ||
+ so wdrive can't be a const string. | ||
+ Returns the name on success (free with g_free), | ||
+ NULL otherwise. | ||
+ */ | ||
+static gchar * | ||
+get_mount_display_name (gunichar2 *wdrive) | ||
+{ | ||
+ IShellFolder *desktop; | ||
+ PIDLIST_RELATIVE volume; | ||
+ STRRET volume_name; | ||
+ gchar *result = NULL; | ||
+ | ||
+ /* Get the desktop folder object reference */ | ||
+ if (!SUCCEEDED (SHGetDesktopFolder (&desktop))) | ||
+ return result; | ||
+ | ||
+ if (SUCCEEDED (IShellFolder_ParseDisplayName (desktop, NULL, NULL, wdrive, NULL, &volume, NULL))) | ||
+ { | ||
+ volume_name.uType = STRRET_WSTR; | ||
+ | ||
+ if (SUCCEEDED (IShellFolder_GetDisplayNameOf (desktop, volume, SHGDN_FORADDRESSBAR, &volume_name))) | ||
+ { | ||
+ wchar_t *volume_name_wchar; | ||
+ | ||
+ if (SUCCEEDED (StrRetToStrW (&volume_name, volume, &volume_name_wchar))) | ||
+ { | ||
+ result = g_utf16_to_utf8 (volume_name_wchar, -1, NULL, NULL, NULL); | ||
+ CoTaskMemFree (volume_name_wchar); | ||
+ } | ||
+ } | ||
+ CoTaskMemFree (volume); | ||
+ } | ||
+ | ||
+ IShellFolder_Release (desktop); | ||
+ | ||
+ return result; | ||
+} | ||
+ | ||
static gchar * | ||
_win32_get_displayname (const char *drive) | ||
{ | ||
gunichar2 *wdrive = g_utf8_to_utf16 (drive, -1, NULL, NULL, NULL); | ||
- gchar *name = NULL; | ||
- SHFILEINFOW sfi; | ||
- if (SHGetFileInfoW(wdrive, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME)) | ||
- name = g_utf16_to_utf8 (sfi.szDisplayName, -1, NULL, NULL, NULL); | ||
+ gchar *name = get_mount_display_name (wdrive); | ||
|
||
g_free (wdrive); | ||
return name ? name : g_strdup (drive); | ||
-- | ||
2.32.0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters