mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-04 18:26:19 +01:00
Merge branch 'g-win32-app-info-enhancements' into 'main'
GWin32AppInfo: Fixes for UWP (packaged) apps activation See merge request GNOME/glib!3167
This commit is contained in:
commit
d333b06644
@ -4880,81 +4880,68 @@ emit_launch_failed (GAppLaunchContext *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
typedef enum
|
||||||
g_win32_app_info_launch_uwp_internal (GWin32AppInfo *info,
|
|
||||||
gboolean for_files,
|
|
||||||
IShellItemArray *items,
|
|
||||||
GWin32AppInfoShellVerb *shverb,
|
|
||||||
GAppLaunchContext *launch_context,
|
|
||||||
GTask *from_task,
|
|
||||||
GError **error)
|
|
||||||
{
|
{
|
||||||
IApplicationActivationManager* paam = NULL;
|
/* PLAIN: just open the application, without arguments of any kind
|
||||||
gboolean com_initialized = FALSE;
|
* corresponds to: LaunchActivatedEventArgs */
|
||||||
gboolean result = FALSE;
|
UWP_ACTIVATION_TYPE_PLAIN,
|
||||||
|
|
||||||
|
/* FILE: open the applications passing a set of files
|
||||||
|
* corresponds to: FileActivatedEventArgs */
|
||||||
|
UWP_ACTIVATION_TYPE_FILE,
|
||||||
|
|
||||||
|
/* PROTOCOL: open the application passing a URI which describe an
|
||||||
|
app activity
|
||||||
|
* corresponds to: ProtocolActivatedEventArgs */
|
||||||
|
UWP_ACTIVATION_TYPE_PROTOCOL,
|
||||||
|
} UwpActivationType;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
g_win32_app_info_launch_uwp_single (IApplicationActivationManager *app_activation_manager,
|
||||||
|
UwpActivationType activation_type,
|
||||||
|
IShellItemArray *items,
|
||||||
|
const wchar_t *verb,
|
||||||
|
GWin32AppInfo *info,
|
||||||
|
GAppLaunchContext *launch_context,
|
||||||
|
GTask *from_task,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
const wchar_t *canonical_name = (const wchar_t *) info->app->canonical_name;
|
||||||
DWORD process_id = 0;
|
DWORD process_id = 0;
|
||||||
HRESULT hr;
|
HRESULT hr = S_OK;
|
||||||
const wchar_t *app_canonical_name = (const wchar_t *) info->app->canonical_name;
|
|
||||||
|
|
||||||
/* ApplicationActivationManager threading model is both,
|
|
||||||
* prefer the multithreaded apartment type, as we don't
|
|
||||||
* need anything of the STA here. */
|
|
||||||
hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
|
||||||
if (SUCCEEDED (hr))
|
|
||||||
com_initialized = TRUE;
|
|
||||||
else if (hr != RPC_E_CHANGED_MODE)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Failed to initialize the COM support library for the thread: 0x%lx", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* It's best to instantiate ApplicationActivationManager out-of-proc,
|
|
||||||
* as documented on MSDN:
|
|
||||||
*
|
|
||||||
* An IApplicationActivationManager object creates a thread in its
|
|
||||||
* host process to serve any activated event arguments objects
|
|
||||||
* (LaunchActivatedEventArgs, FileActivatedEventArgs, and Protocol-
|
|
||||||
* ActivatedEventArgs) that are passed to the app. If the calling
|
|
||||||
* process is long-lived, you can create this object in-proc,
|
|
||||||
* based on the assumption that the event arguments will exist long
|
|
||||||
* enough for the target app to use them.
|
|
||||||
* However, if the calling process is spawned only to launch the
|
|
||||||
* target app, it should create the IApplicationActivationManager
|
|
||||||
* object out-of-process, by using CLSCTX_LOCAL_SERVER. This causes
|
|
||||||
* the object to be created in a Dllhost instance that automatically
|
|
||||||
* manages the object's lifetime based on outstanding references to
|
|
||||||
* the activated event argument objects.
|
|
||||||
*/
|
|
||||||
hr = CoCreateInstance (&CLSID_ApplicationActivationManager, NULL,
|
|
||||||
CLSCTX_LOCAL_SERVER,
|
|
||||||
&IID_IApplicationActivationManager, (void **) &paam);
|
|
||||||
if (FAILED (hr))
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Failed to create ApplicationActivationManager: 0x%lx", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit_launch_started (launch_context, info, from_task);
|
emit_launch_started (launch_context, info, from_task);
|
||||||
|
|
||||||
/* The Activate methods return a process identifier (PID), so we should consider
|
/* The Activate methods return a process identifier (PID), so we should consider
|
||||||
* those methods as potentially blocking */
|
* those methods as potentially blocking */
|
||||||
if (items == NULL)
|
|
||||||
hr = IApplicationActivationManager_ActivateApplication (paam,
|
switch (activation_type)
|
||||||
app_canonical_name,
|
{
|
||||||
NULL, AO_NONE,
|
case UWP_ACTIVATION_TYPE_PLAIN:
|
||||||
&process_id);
|
g_assert (items == NULL);
|
||||||
else if (for_files)
|
|
||||||
hr = IApplicationActivationManager_ActivateForFile (paam,
|
hr = IApplicationActivationManager_ActivateApplication (app_activation_manager,
|
||||||
app_canonical_name,
|
canonical_name,
|
||||||
items, shverb->verb_name,
|
NULL, AO_NONE,
|
||||||
&process_id);
|
&process_id);
|
||||||
else
|
break;
|
||||||
hr = IApplicationActivationManager_ActivateForProtocol (paam,
|
case UWP_ACTIVATION_TYPE_PROTOCOL:
|
||||||
app_canonical_name,
|
g_assert (items != NULL);
|
||||||
items,
|
|
||||||
&process_id);
|
hr = IApplicationActivationManager_ActivateForProtocol (app_activation_manager,
|
||||||
|
canonical_name,
|
||||||
|
items,
|
||||||
|
&process_id);
|
||||||
|
break;
|
||||||
|
case UWP_ACTIVATION_TYPE_FILE:
|
||||||
|
g_assert (items != NULL);
|
||||||
|
|
||||||
|
hr = IApplicationActivationManager_ActivateForFile (app_activation_manager,
|
||||||
|
canonical_name,
|
||||||
|
items, verb,
|
||||||
|
&process_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (FAILED (hr))
|
if (FAILED (hr))
|
||||||
{
|
{
|
||||||
@ -4964,9 +4951,10 @@ g_win32_app_info_launch_uwp_internal (GWin32AppInfo *info,
|
|||||||
|
|
||||||
emit_launch_failed (launch_context, info, from_task);
|
emit_launch_failed (launch_context, info, from_task);
|
||||||
|
|
||||||
goto cleanup;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else if (launch_context)
|
|
||||||
|
if (launch_context)
|
||||||
{
|
{
|
||||||
DWORD access_rights = 0;
|
DWORD access_rights = 0;
|
||||||
HANDLE process_handle = NULL;
|
HANDLE process_handle = NULL;
|
||||||
@ -5014,7 +5002,150 @@ g_win32_app_info_launch_uwp_internal (GWin32AppInfo *info,
|
|||||||
g_spawn_close_pid ((GPid) process_handle);
|
g_spawn_close_pid ((GPid) process_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = TRUE;
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
g_win32_app_info_supports_files (GAppInfo *appinfo);
|
||||||
|
|
||||||
|
static IShellItemArray *
|
||||||
|
make_item_array (gboolean for_files,
|
||||||
|
GList *objs,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
static inline GList
|
||||||
|
make_single_entry_list (gpointer data)
|
||||||
|
{
|
||||||
|
GList l = { NULL, NULL, NULL };
|
||||||
|
l.data = data;
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
g_win32_app_info_launch_uwp_internal (GWin32AppInfo *info,
|
||||||
|
gboolean for_files,
|
||||||
|
GList *objs, /* (element-type file_or_uri) */
|
||||||
|
GWin32AppInfoShellVerb *shverb,
|
||||||
|
GAppLaunchContext *launch_context,
|
||||||
|
GTask *from_task,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
IApplicationActivationManager *paam = NULL;
|
||||||
|
gboolean com_initialized = FALSE;
|
||||||
|
gboolean result = FALSE;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
/* ApplicationActivationManager threading model is both,
|
||||||
|
* prefer the multithreaded apartment type, as we don't
|
||||||
|
* need anything of the STA here. */
|
||||||
|
hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
||||||
|
if (SUCCEEDED (hr))
|
||||||
|
com_initialized = TRUE;
|
||||||
|
else if (hr != RPC_E_CHANGED_MODE)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Failed to initialize the COM support library for the thread: 0x%lx", hr);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It's best to instantiate ApplicationActivationManager out-of-proc,
|
||||||
|
* as documented on MSDN:
|
||||||
|
*
|
||||||
|
* An IApplicationActivationManager object creates a thread in its
|
||||||
|
* host process to serve any activated event arguments objects
|
||||||
|
* (LaunchActivatedEventArgs, FileActivatedEventArgs, and Protocol-
|
||||||
|
* ActivatedEventArgs) that are passed to the app. If the calling
|
||||||
|
* process is long-lived, you can create this object in-proc,
|
||||||
|
* based on the assumption that the event arguments will exist long
|
||||||
|
* enough for the target app to use them.
|
||||||
|
* However, if the calling process is spawned only to launch the
|
||||||
|
* target app, it should create the IApplicationActivationManager
|
||||||
|
* object out-of-process, by using CLSCTX_LOCAL_SERVER. This causes
|
||||||
|
* the object to be created in a Dllhost instance that automatically
|
||||||
|
* manages the object's lifetime based on outstanding references to
|
||||||
|
* the activated event argument objects.
|
||||||
|
*/
|
||||||
|
hr = CoCreateInstance (&CLSID_ApplicationActivationManager, NULL,
|
||||||
|
CLSCTX_LOCAL_SERVER,
|
||||||
|
&IID_IApplicationActivationManager, (void **) &paam);
|
||||||
|
if (FAILED (hr))
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Failed to create ApplicationActivationManager: 0x%lx", hr);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!objs)
|
||||||
|
{
|
||||||
|
result = g_win32_app_info_launch_uwp_single (paam, UWP_ACTIVATION_TYPE_PLAIN, NULL, NULL,
|
||||||
|
info, launch_context, from_task, error);
|
||||||
|
}
|
||||||
|
else if (for_files)
|
||||||
|
{
|
||||||
|
IShellItemArray *items = make_item_array (TRUE, objs, error);
|
||||||
|
|
||||||
|
if (!items)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
result = g_win32_app_info_launch_uwp_single (paam, UWP_ACTIVATION_TYPE_FILE, items,
|
||||||
|
shverb->verb_name,
|
||||||
|
info, launch_context, from_task, error);
|
||||||
|
|
||||||
|
IShellItemArray_Release (items);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gboolean supports_files;
|
||||||
|
gboolean supports_file_uris;
|
||||||
|
gboolean outcome = TRUE;
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
supports_files = g_win32_app_info_supports_files (G_APP_INFO (info));
|
||||||
|
supports_file_uris = info->app &&
|
||||||
|
info->app->supported_urls &&
|
||||||
|
g_hash_table_lookup (info->app->supported_urls, "file");
|
||||||
|
|
||||||
|
for (l = objs; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
file_or_uri *obj = (file_or_uri*) l->data;
|
||||||
|
GList single = make_single_entry_list (obj);
|
||||||
|
IShellItemArray *item = NULL;
|
||||||
|
UwpActivationType type;
|
||||||
|
|
||||||
|
/* Most UWP applications support opening files but do not support
|
||||||
|
* the file:// protocol in URI's. That's because the UWP platform
|
||||||
|
* has a specific activation for files (see FileActivatedEventArgs)
|
||||||
|
* which is different from protocol activation. Here we check for
|
||||||
|
* that. */
|
||||||
|
|
||||||
|
if (!supports_file_uris && supports_files && obj->file)
|
||||||
|
{
|
||||||
|
type = UWP_ACTIVATION_TYPE_FILE;
|
||||||
|
item = make_item_array (TRUE, &single, error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = UWP_ACTIVATION_TYPE_PROTOCOL;
|
||||||
|
item = make_item_array (FALSE, &single, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
outcome = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_win32_app_info_launch_uwp_single (paam, type,
|
||||||
|
item, shverb->verb_name, info,
|
||||||
|
launch_context, from_task, error))
|
||||||
|
outcome = FALSE;
|
||||||
|
|
||||||
|
IShellItemArray_Release (item);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = outcome;
|
||||||
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
|
||||||
@ -5036,9 +5167,8 @@ cleanup:
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
g_win32_app_info_launch_internal (GWin32AppInfo *info,
|
g_win32_app_info_launch_internal (GWin32AppInfo *info,
|
||||||
GList *objs, /* non-UWP only */
|
GList *objs, /* (element-type file_or_uri) */
|
||||||
gboolean for_files, /* UWP only */
|
gboolean for_files, /* UWP only */
|
||||||
IShellItemArray *items, /* UWP only */
|
|
||||||
GAppLaunchContext *launch_context,
|
GAppLaunchContext *launch_context,
|
||||||
GSpawnFlags spawn_flags,
|
GSpawnFlags spawn_flags,
|
||||||
GTask *from_task,
|
GTask *from_task,
|
||||||
@ -5083,7 +5213,7 @@ g_win32_app_info_launch_internal (GWin32AppInfo *info,
|
|||||||
if (info->app->is_uwp)
|
if (info->app->is_uwp)
|
||||||
return g_win32_app_info_launch_uwp_internal (info,
|
return g_win32_app_info_launch_uwp_internal (info,
|
||||||
for_files,
|
for_files,
|
||||||
items,
|
objs,
|
||||||
shverb,
|
shverb,
|
||||||
launch_context,
|
launch_context,
|
||||||
from_task,
|
from_task,
|
||||||
@ -5243,7 +5373,7 @@ g_win32_app_info_supports_files (GAppInfo *appinfo)
|
|||||||
|
|
||||||
static IShellItemArray *
|
static IShellItemArray *
|
||||||
make_item_array (gboolean for_files,
|
make_item_array (gboolean for_files,
|
||||||
GList *files_or_uris,
|
GList *objs, /* (element-type file_or_uri) */
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
ITEMIDLIST **item_ids;
|
ITEMIDLIST **item_ids;
|
||||||
@ -5253,19 +5383,20 @@ make_item_array (gboolean for_files,
|
|||||||
gsize i;
|
gsize i;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
count = g_list_length (files_or_uris);
|
count = g_list_length (objs);
|
||||||
|
|
||||||
items = NULL;
|
items = NULL;
|
||||||
item_ids = g_new (ITEMIDLIST*, count);
|
item_ids = g_new (ITEMIDLIST*, count);
|
||||||
|
|
||||||
for (i = 0, p = files_or_uris; p != NULL; p = p->next, i++)
|
for (i = 0, p = objs; p != NULL; p = p->next, i++)
|
||||||
{
|
{
|
||||||
|
file_or_uri *obj = (file_or_uri*) p->data;
|
||||||
wchar_t *file_or_uri_utf16;
|
wchar_t *file_or_uri_utf16;
|
||||||
|
|
||||||
if (!for_files)
|
if (!for_files)
|
||||||
file_or_uri_utf16 = g_utf8_to_utf16 ((gchar *) p->data, -1, NULL, NULL, error);
|
file_or_uri_utf16 = g_utf8_to_utf16 (obj->uri, -1, NULL, NULL, error);
|
||||||
else
|
else
|
||||||
file_or_uri_utf16 = g_utf8_to_utf16 (g_file_peek_path (G_FILE (p->data)), -1, NULL, NULL, error);
|
file_or_uri_utf16 = g_utf8_to_utf16 (obj->file, -1, NULL, NULL, error);
|
||||||
|
|
||||||
if (file_or_uri_utf16 == NULL)
|
if (file_or_uri_utf16 == NULL)
|
||||||
break;
|
break;
|
||||||
@ -5336,38 +5467,19 @@ make_item_array (gboolean for_files,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
g_win32_app_info_launch_uris_impl (GAppInfo *appinfo,
|
g_win32_app_info_launch_uris_impl (GAppInfo *appinfo,
|
||||||
GList *uris,
|
GList *uris, /* (element-type utf8) */
|
||||||
GAppLaunchContext *launch_context,
|
GAppLaunchContext *launch_context,
|
||||||
GTask *from_task,
|
GTask *from_task,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
gboolean do_files;
|
gboolean do_files;
|
||||||
GList *objs;
|
GList *objs = NULL;
|
||||||
GWin32AppInfo *info = G_WIN32_APP_INFO (appinfo);
|
GWin32AppInfo *info = G_WIN32_APP_INFO (appinfo);
|
||||||
|
gboolean is_uwp;
|
||||||
if (info->app != NULL && info->app->is_uwp)
|
|
||||||
{
|
|
||||||
IShellItemArray *items = NULL;
|
|
||||||
|
|
||||||
if (uris)
|
|
||||||
{
|
|
||||||
items = make_item_array (FALSE, uris, error);
|
|
||||||
if (items == NULL)
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = g_win32_app_info_launch_internal (info, NULL, FALSE, items, launch_context, 0, from_task, error);
|
|
||||||
|
|
||||||
if (items != NULL)
|
|
||||||
IShellItemArray_Release (items);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_files = g_win32_app_info_supports_files (appinfo);
|
do_files = g_win32_app_info_supports_files (appinfo);
|
||||||
|
|
||||||
objs = NULL;
|
|
||||||
while (uris)
|
while (uris)
|
||||||
{
|
{
|
||||||
file_or_uri *obj;
|
file_or_uri *obj;
|
||||||
@ -5389,14 +5501,16 @@ g_win32_app_info_launch_uris_impl (GAppInfo *appinfo,
|
|||||||
objs = g_list_prepend (objs, obj);
|
objs = g_list_prepend (objs, obj);
|
||||||
uris = uris->next;
|
uris = uris->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
objs = g_list_reverse (objs);
|
objs = g_list_reverse (objs);
|
||||||
|
|
||||||
|
is_uwp = (info->app != NULL && info->app->is_uwp);
|
||||||
|
|
||||||
res = g_win32_app_info_launch_internal (info,
|
res = g_win32_app_info_launch_internal (info,
|
||||||
objs,
|
objs,
|
||||||
FALSE,
|
FALSE,
|
||||||
NULL,
|
|
||||||
launch_context,
|
launch_context,
|
||||||
|
is_uwp ?
|
||||||
|
0 :
|
||||||
G_SPAWN_SEARCH_PATH,
|
G_SPAWN_SEARCH_PATH,
|
||||||
from_task,
|
from_task,
|
||||||
error);
|
error);
|
||||||
@ -5491,37 +5605,18 @@ g_win32_app_info_should_show (GAppInfo *appinfo)
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
g_win32_app_info_launch (GAppInfo *appinfo,
|
g_win32_app_info_launch (GAppInfo *appinfo,
|
||||||
GList *files,
|
GList *files, /* (element-type GFile) */
|
||||||
GAppLaunchContext *launch_context,
|
GAppLaunchContext *launch_context,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
gboolean do_uris;
|
gboolean do_uris;
|
||||||
GList *objs;
|
GList *objs = NULL;
|
||||||
GWin32AppInfo *info = G_WIN32_APP_INFO (appinfo);
|
GWin32AppInfo *info = G_WIN32_APP_INFO (appinfo);
|
||||||
|
gboolean is_uwp;
|
||||||
if (info->app != NULL && info->app->is_uwp)
|
|
||||||
{
|
|
||||||
IShellItemArray *items = NULL;
|
|
||||||
|
|
||||||
if (files)
|
|
||||||
{
|
|
||||||
items = make_item_array (TRUE, files, error);
|
|
||||||
if (items == NULL)
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = g_win32_app_info_launch_internal (info, NULL, TRUE, items, launch_context, 0, NULL, error);
|
|
||||||
|
|
||||||
if (items != NULL)
|
|
||||||
IShellItemArray_Release (items);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_uris = g_win32_app_info_supports_uris (appinfo);
|
do_uris = g_win32_app_info_supports_uris (appinfo);
|
||||||
|
|
||||||
objs = NULL;
|
|
||||||
while (files)
|
while (files)
|
||||||
{
|
{
|
||||||
file_or_uri *obj;
|
file_or_uri *obj;
|
||||||
@ -5534,14 +5629,16 @@ g_win32_app_info_launch (GAppInfo *appinfo,
|
|||||||
objs = g_list_prepend (objs, obj);
|
objs = g_list_prepend (objs, obj);
|
||||||
files = files->next;
|
files = files->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
objs = g_list_reverse (objs);
|
objs = g_list_reverse (objs);
|
||||||
|
|
||||||
|
is_uwp = (info->app != NULL && info->app->is_uwp);
|
||||||
|
|
||||||
res = g_win32_app_info_launch_internal (info,
|
res = g_win32_app_info_launch_internal (info,
|
||||||
objs,
|
objs,
|
||||||
TRUE,
|
TRUE,
|
||||||
NULL,
|
|
||||||
launch_context,
|
launch_context,
|
||||||
|
is_uwp ?
|
||||||
|
0 :
|
||||||
G_SPAWN_SEARCH_PATH,
|
G_SPAWN_SEARCH_PATH,
|
||||||
NULL,
|
NULL,
|
||||||
error);
|
error);
|
||||||
|
Loading…
Reference in New Issue
Block a user