Hook up file/URI launching to ShellExecute
The idea here is to hook up the higher-level helpers to Windows's native ShellExecuteEx ()
and SHOpenWithDialog ()
APIs, which (in my limited understanding) are the moral equivalent of the Freedesktop OpenURI portal (though largely implemented in-process) — high-level system APIs to open the given file or URI in the appropriate app.
The advantages this has over using the win32 implementation of g_app_info_launch_default_for_uri ()
:
- the implementation here is fairly simple;
- it doesn't involve trying to grok the registry for app / file type
registrations (at least not inside GLib/GTK side, the implementations
of
ShellExecuteEx
/SHOpenWithDialog
presumably do that internally); - it doesn't require convoluted formatting / escaping of invocation
command lines that
GWin32AppInfo
/gspawn-win32
has to do otherwise (again, presumably the Windows libraries implement this internally); - it's certain to end up opening the file/URI the same way other apps in the system would;
- it can/will open the native system UI for picking an app in case there
are multiple options (or when so requested programmatically with the
always-ask
flag), or if there is no app installed that can handle the URI scheme / file type; - it lets us pass the parent window handle, much like the portal APIs; presumably Windows would use this for positioning the picking UI, or placing the launched app's window;
- presumably, this will properly elevate privileges with a User Access
Control (UAC) prompt if the app being launched requires administrator
access; this presumably is impossible with the
wspawn*
APIs thatgspawn-win32
uses; - this has a much better chance to work properly with the win32 app isolation (AppContainer) technology.
I have tested this on Windows 10 and 11, with various files and URLs, including files that have whitespace and non-ASCII characters in their names, and specifically characters which don't fit into Windows's own idea of single-byte encoding. g_file_get_path ()
returns the path encoded in UTF-8 (not the Windows single-byte encoding), and we convert that to UTF-16 and pass to the W
versions of Windows APIs, so all the characters are preserved.
I put the whole thing into a background thread and passed SEE_MASK_NOASYNC
to ShellExecuteEx ()
to prevent it from doing its own asynchrony; this felt like the right thing to do.
I put this into GTK instead of GIO because:
-
g_app_info_launch_default_for_uri ()
is aboutGAppInfo
after all, launching the default app for a file type is one feature of the larger framework of collecting and exposing knowledge about apps and file types; - we have to pass the HWND;
- GTK is also the layer where the xdg-portal backend is hooked up.
That being said, it should be possible to lower this down to GIO if desired.
@lb90 mentions some drawbacks of using ShellExecute ()
in glib!2760 (comment 1497800). Regarding an error dialog being shown by Windows on errors, that doesn't sound very problematic to me — if anything, perhaps it's actually useful. I have no idea about COM and the implications for COM initialization, but it seems to be working nicely at least in the GTK Demo.
Related to: glib#2088 (closed) glib#292 glib!2760 (merged)