GWin32AppInfo: Support getting information about UWP apps

This commit is contained in:
Руслан Ижбулатов 2020-06-04 15:13:33 +00:00
parent e9b09911f6
commit 720b51032c
3 changed files with 487 additions and 38 deletions

View File

@ -181,7 +181,10 @@ struct _GWin32AppInfoHandler {
/* Usually a class name in HKCR */
gunichar2 *handler_id;
/* Registry object obtained by opening @handler_id. Can be used to watch this handler. */
/* Registry object obtained by opening @handler_id.
* Can be used to watch this handler.
* May be %NULL (for fake handlers that we made up).
*/
GWin32RegistryKey *key;
/* @handler_id, in UTF-8, folded */
@ -267,6 +270,7 @@ struct _GWin32AppInfoApplication {
* key path for the application.
* For applications tracked by executable name this is the
* basename of the executable.
* For UWP apps this is the AppUserModelID.
* For fake applications this is the full filename of the
* executable (as far as it can be inferred from a command line,
* meaning that it can also be a basename, if that's
@ -333,13 +337,8 @@ struct _GWin32AppInfoApplication {
* browser) */
gboolean default_app;
/* At the moment we do not support getting UWP application info
* from the OS. That is, if a file extension is associated with
* a UWP app, we can launch it, but we can't read a list of
* UWP apps and see which extensions are associated with each one
* of them.
* That is why there's no uwp_aumid field here.
*/
/* Set to TRUE for UWP applications */
gboolean is_uwp;
};
#define G_TYPE_WIN32_APPINFO_URL_SCHEMA (g_win32_appinfo_url_schema_get_type ())
@ -637,6 +636,9 @@ static GWin32RegistryKey *classes_root_key;
*/
#include "giowin32-private.c"
/* for g_win32_package_parser_enum_packages() */
#include "gwin32packageparser.h"
static void
read_handler_icon (GWin32RegistryKey *key,
GIcon **icon_out)
@ -791,6 +793,20 @@ static void handler_add_verb (gpointer ha
gboolean verb_is_preferred,
gboolean invent_new_verb_name);
static void process_uwp_verbs (GList *verbs,
const reg_verb *preferred_verb,
const gunichar2 *path_to_progid,
const gunichar2 *progid,
gboolean autoprefer_first_verb,
GWin32AppInfoHandler *handler_rec,
GWin32AppInfoApplication *app);
static void uwp_handler_add_verb (GWin32AppInfoHandler *handler_rec,
GWin32AppInfoApplication *app,
const gunichar2 *verb,
const gchar *verb_displayname,
gboolean verb_is_preferred);
/* output_size is in *bytes*, not gunichar2s! */
static gboolean
build_registry_path (gunichar2 *output, gsize output_size, ...)
@ -881,6 +897,12 @@ _g_win32_registry_key_build_and_new_w (GError **error, ...)
* @verbshell_prefix is the subkey of @program_id_key
* that contains the verbs. It is "Shell" initially,
* but grows with recursive invocations (for subcommands).
* @is_uwp points to a boolean, which
* indicates whether the function is being called for a UWP app.
* It might be switched from %TRUE to %FALSE on return,
* if the application turns out to not to be UWP on closer inspection.
* If the application is already known not to be UWP before the
* call, this pointer can be %NULL instead.
* Returns TRUE on success, FALSE on failure.
*/
static gboolean
@ -888,7 +910,8 @@ get_verbs (GWin32RegistryKey *program_id_key,
const reg_verb **preferred_verb,
GList **verbs,
const gunichar2 *verbname_prefix,
const gunichar2 *verbshell_prefix)
const gunichar2 *verbshell_prefix,
gboolean *is_uwp)
{
GWin32RegistrySubkeyIter iter;
GWin32RegistryKey *key;
@ -953,7 +976,8 @@ get_verbs (GWin32RegistryKey *program_id_key,
* Essentially, we're flattening the command tree into a list.
*/
has_subcommands = FALSE;
if (g_win32_registry_key_get_value_w (subkey,
if ((is_uwp == NULL || !(*is_uwp)) && /* Assume UWP apps don't have subcommands */
g_win32_registry_key_get_value_w (subkey,
NULL,
TRUE,
L"Subcommands",
@ -963,6 +987,7 @@ get_verbs (GWin32RegistryKey *program_id_key,
NULL) &&
subc_type == G_WIN32_REGISTRY_VALUE_STR)
{
gboolean dummy = FALSE;
gunichar2 *new_nameprefix = g_malloc ((verbname_prefix_len + name_len + 1 + 1) * sizeof (gunichar2));
gunichar2 *new_shellprefix = g_malloc ((verbshell_prefix_len + 1 + name_len + 1 + shell_len + 1) * sizeof (gunichar2));
memcpy (&new_shellprefix[0], verbshell_prefix, verbshell_prefix_len * sizeof (gunichar2));
@ -976,16 +1001,38 @@ get_verbs (GWin32RegistryKey *program_id_key,
memcpy (&new_nameprefix[verbname_prefix_len], name, (name_len) * sizeof (gunichar2));
new_nameprefix[verbname_prefix_len + name_len] = L'\\';
new_nameprefix[verbname_prefix_len + name_len + 1] = 0;
has_subcommands = get_verbs (program_id_key, &tmp, verbs, new_nameprefix, new_shellprefix);
has_subcommands = get_verbs (program_id_key, &tmp, verbs, new_nameprefix, new_shellprefix, &dummy);
g_free (new_shellprefix);
g_free (new_nameprefix);
}
g_clear_object (&subkey);
/* Presence of subcommands means that this key itself is not a command-key */
if (has_subcommands)
continue;
{
g_clear_object (&subkey);
continue;
}
if (is_uwp != NULL && *is_uwp &&
!g_win32_registry_key_get_value_w (subkey,
NULL,
TRUE,
L"ActivatableClassId",
&subc_type,
NULL,
NULL,
NULL))
{
/* We expected a UWP app, but it lacks ActivatableClassId
* on a verb, which means that it does not behave like
* a UWP app should (msedge being an example - it's UWP,
* but has its own launchable exe file and a simple ID),
* so we have to treat it like a normal app.
*/
*is_uwp = FALSE;
}
g_clear_object (&subkey);
/* We don't look at the command sub-key and its value (the actual command line) here.
* We save the registry path instead, and use it later in process_verbs_commands().
@ -1073,6 +1120,7 @@ get_url_association (const gunichar2 *program_id,
gchar *handler_id_u8;
gchar *handler_id_u8_folded;
gunichar2 *uwp_aumid;
gboolean is_uwp;
GWin32RegistryKey *handler_key;
if ((handler_id = decide_which_id_to_use (program_id,
@ -1082,22 +1130,22 @@ get_url_association (const gunichar2 *program_id,
&uwp_aumid)) == NULL)
return;
if (uwp_aumid != NULL)
{
verbs = NULL;
preferred_verb = NULL;
}
else if (!get_verbs (handler_key, &preferred_verb, &verbs, L"", L"Shell"))
is_uwp = uwp_aumid != NULL;
if (!get_verbs (handler_key, &preferred_verb, &verbs, L"", L"Shell", &is_uwp))
{
g_clear_pointer (&handler_id, g_free);
g_clear_pointer (&handler_id_u8, g_free);
g_clear_pointer (&handler_id_u8_folded, g_free);
g_clear_object (&handler_key);
/* and uwp_aumid is already NULL */
g_clear_pointer (&uwp_aumid, g_free);
return;
}
if (!is_uwp && uwp_aumid != NULL)
g_clear_pointer (&uwp_aumid, g_free);
schema_rec = get_schema_object (schema,
schema_u8,
schema_u8_folded);
@ -1121,7 +1169,6 @@ get_url_association (const gunichar2 *program_id,
g_strdup (schema_rec->schema_u8_folded),
g_object_ref (handler_rec));
/* UWP apps get their verbs elsewhere */
if (uwp_aumid == NULL)
process_verbs_commands (g_steal_pointer (&verbs),
preferred_verb,
@ -1131,6 +1178,15 @@ get_url_association (const gunichar2 *program_id,
handler_add_verb,
handler_rec,
app);
else
process_uwp_verbs (g_steal_pointer (&verbs),
preferred_verb,
HKCR,
handler_id,
TRUE,
handler_rec,
app);
g_clear_pointer (&handler_id_u8, g_free);
g_clear_pointer (&handler_id_u8_folded, g_free);
@ -1157,6 +1213,7 @@ get_file_ext (const gunichar2 *program_id,
gchar *handler_id_u8;
gchar *handler_id_u8_folded;
gunichar2 *uwp_aumid;
gboolean is_uwp;
GWin32RegistryKey *handler_key;
GWin32AppInfoFileExtension *file_extn;
gchar *file_extension_u8;
@ -1183,12 +1240,9 @@ get_file_ext (const gunichar2 *program_id,
return;
}
if (uwp_aumid != NULL)
{
verbs = NULL;
preferred_verb = NULL;
}
else if (!get_verbs (handler_key, &preferred_verb, &verbs, L"", L"Shell"))
is_uwp = uwp_aumid != NULL;
if (!get_verbs (handler_key, &preferred_verb, &verbs, L"", L"Shell", &is_uwp))
{
g_clear_pointer (&handler_id, g_free);
g_clear_pointer (&handler_id_u8, g_free);
@ -1196,11 +1250,14 @@ get_file_ext (const gunichar2 *program_id,
g_clear_object (&handler_key);
g_clear_pointer (&file_extension_u8, g_free);
g_clear_pointer (&file_extension_u8_folded, g_free);
/* and uwp_aumid is already NULL */
g_clear_pointer (&uwp_aumid, g_free);
return;
}
if (!is_uwp && uwp_aumid != NULL)
g_clear_pointer (&uwp_aumid, g_free);
file_extn = get_ext_object (file_extension, file_extension_u8, file_extension_u8_folded);
handler_rec = get_handler_object (handler_id_u8_folded,
@ -1224,7 +1281,6 @@ get_file_ext (const gunichar2 *program_id,
g_clear_pointer (&file_extension_u8_folded, g_free);
g_clear_object (&handler_key);
/* UWP apps get their verbs elsewhere */
if (uwp_aumid == NULL)
process_verbs_commands (g_steal_pointer (&verbs),
preferred_verb,
@ -1234,6 +1290,14 @@ get_file_ext (const gunichar2 *program_id,
handler_add_verb,
handler_rec,
app);
else
process_uwp_verbs (g_steal_pointer (&verbs),
preferred_verb,
HKCR,
handler_id,
TRUE,
handler_rec,
app);
g_clear_pointer (&handler_id, g_free);
g_clear_pointer (&handler_id_u8, g_free);
@ -1505,6 +1569,75 @@ process_verbs_commands (GList *verbs,
g_list_free_full (verbs, reg_verb_free);
}
static void
process_uwp_verbs (GList *verbs,
const reg_verb *preferred_verb,
const gunichar2 *path_to_progid,
const gunichar2 *progid,
gboolean autoprefer_first_verb,
GWin32AppInfoHandler *handler_rec,
GWin32AppInfoApplication *app)
{
GList *i;
g_assert (verbs != NULL);
for (i = verbs; i; i = i->next)
{
const reg_verb *verb = (const reg_verb *) i->data;
GWin32RegistryKey *key;
gboolean got_value;
GWin32RegistryValueType val_type;
gunichar2 *acid;
gsize acid_len;
key = _g_win32_registry_key_build_and_new_w (NULL, path_to_progid, progid,
L"\\", verb->shellpath, NULL);
if (key == NULL)
{
g_debug ("%S%S\\%S does not exist",
path_to_progid, progid, verb->shellpath);
continue;
}
got_value = g_win32_registry_key_get_value_w (key,
g_win32_registry_get_os_dirs_w (),
TRUE,
L"ActivatableClassId",
&val_type,
(void **) &acid,
&acid_len,
NULL);
if (got_value &&
val_type == G_WIN32_REGISTRY_VALUE_STR &&
acid_len > sizeof (gunichar2))
{
/* TODO: default value of a shell subkey, if not empty,
* migh contain something like @{Some.Identifier_1234.456.678.789_some_words?ms-resource://Arbitrary.Path/Pointing/Somewhere}
* and it might be possible to turn it into a nice displayname.
*/
uwp_handler_add_verb (handler_rec,
app,
verb->name,
NULL,
(preferred_verb && _wcsicmp (verb->name, preferred_verb->name) == 0) ||
(!preferred_verb && autoprefer_first_verb && i == verbs));
}
else
{
g_debug ("%S%S\\%S does not have an ActivatableClassId string value",
path_to_progid, progid, verb->shellpath);
}
g_clear_pointer (&acid, g_free);
g_clear_object (&key);
}
g_list_free_full (verbs, reg_verb_free);
}
/* Looks up a schema object identified by
* @schema_u8_folded in the urls hash table.
* If such object doesn't exist,
@ -1552,12 +1685,14 @@ get_handler_object (const gchar *handler_id_u8_folded,
return handler_rec;
handler_rec = g_object_new (G_TYPE_WIN32_APPINFO_HANDLER, NULL);
handler_rec->key = g_object_ref (handler_key);
if (handler_key)
handler_rec->key = g_object_ref (handler_key);
handler_rec->handler_id = g_wcsdup (handler_id, -1);
handler_rec->handler_id_folded = g_strdup (handler_id_u8_folded);
if (uwp_aumid)
handler_rec->uwp_aumid = g_wcsdup (uwp_aumid, -1);
read_handler_icon (handler_key, &handler_rec->icon);
if (handler_key)
read_handler_icon (handler_key, &handler_rec->icon);
g_hash_table_insert (handlers, g_strdup (handler_id_u8_folded), handler_rec);
return handler_rec;
@ -1727,6 +1862,75 @@ app_add_verb (gpointer handler_data1,
g_ptr_array_insert (app_rec->verbs, 0, shverb);
}
static void
uwp_app_add_verb (GWin32AppInfoApplication *app_rec,
const gunichar2 *verb,
const gchar *verb_displayname)
{
GWin32AppInfoShellVerb *shverb;
_verb_lookup (app_rec->verbs, verb, &shverb);
if (shverb != NULL)
return;
shverb = g_object_new (G_TYPE_WIN32_APPINFO_SHELL_VERB, NULL);
shverb->verb_name = g_wcsdup (verb, -1);
shverb->app = g_object_ref (app_rec);
shverb->verb_displayname = g_strdup (verb_displayname);
shverb->is_uwp = TRUE;
/* Strictly speaking, this is unnecessary, but
* let's make it clear that UWP verbs have no
* commands and executables.
*/
shverb->command = NULL;
shverb->command_utf8 = NULL;
shverb->executable = NULL;
shverb->executable_basename = NULL;
shverb->executable_folded = NULL;
shverb->dll_function = NULL;
g_ptr_array_add (app_rec->verbs, shverb);
}
static void
uwp_handler_add_verb (GWin32AppInfoHandler *handler_rec,
GWin32AppInfoApplication *app,
const gunichar2 *verb,
const gchar *verb_displayname,
gboolean verb_is_preferred)
{
GWin32AppInfoShellVerb *shverb;
_verb_lookup (handler_rec->verbs, verb, &shverb);
if (shverb != NULL)
return;
shverb = g_object_new (G_TYPE_WIN32_APPINFO_SHELL_VERB, NULL);
shverb->verb_name = g_wcsdup (verb, -1);
shverb->verb_displayname = g_strdup (verb_displayname);
shverb->is_uwp = TRUE;
if (app)
shverb->app = g_object_ref (app);
shverb->command = NULL;
shverb->command_utf8 = NULL;
shverb->executable = NULL;
shverb->executable_basename = NULL;
shverb->executable_folded = NULL;
shverb->dll_function = NULL;
if (!verb_is_preferred)
g_ptr_array_add (handler_rec->verbs, shverb);
else
g_ptr_array_insert (handler_rec->verbs, 0, shverb);
}
/* Looks up a file extension object identified by
* @ext_u8_folded in the extensions hash table.
* If such object doesn't exist,
@ -1990,7 +2194,8 @@ get_app_object (GHashTable *app_hashmap,
const gchar *canonical_name_u8,
const gchar *canonical_name_folded,
gboolean user_specific,
gboolean default_app)
gboolean default_app,
gboolean is_uwp)
{
GWin32AppInfoApplication *app;
@ -2006,6 +2211,7 @@ get_app_object (GHashTable *app_hashmap,
app->no_open_with = FALSE;
app->user_specific = user_specific;
app->default_app = default_app;
app->is_uwp = is_uwp;
g_hash_table_insert (app_hashmap,
g_strdup (canonical_name_folded),
app);
@ -2055,7 +2261,7 @@ read_capable_app (const gunichar2 *app_key_path,
&app_key_path_u8_folded) ||
(appkey = g_win32_registry_key_new_w (app_key_path, NULL)) == NULL ||
(capabilities = g_win32_registry_key_get_child_w (appkey, L"Capabilities", NULL)) == NULL ||
!get_verbs (capabilities, &preferred_verb, &verbs, L"", L"Shell"))
!get_verbs (capabilities, &preferred_verb, &verbs, L"", L"Shell", NULL))
{
g_clear_pointer (&canonical_name_u8, g_free);
g_clear_pointer (&canonical_name_folded, g_free);
@ -2071,7 +2277,8 @@ read_capable_app (const gunichar2 *app_key_path,
canonical_name_u8,
canonical_name_folded,
user_specific,
default_app);
default_app,
FALSE);
process_verbs_commands (g_steal_pointer (&verbs),
preferred_verb,
@ -2419,7 +2626,7 @@ read_incapable_app (GWin32RegistryKey *incapable_app,
GIcon *icon = NULL;
GWin32RegistryKey *supported_key;
if (!get_verbs (incapable_app, &preferred_verb, &verbs, L"", L"Shell"))
if (!get_verbs (incapable_app, &preferred_verb, &verbs, L"", L"Shell", NULL))
return;
app = get_app_object (apps_by_exe,
@ -2427,6 +2634,7 @@ read_incapable_app (GWin32RegistryKey *incapable_app,
app_exe_basename_u8,
app_exe_basename_u8_folded,
FALSE,
FALSE,
FALSE);
process_verbs_commands (g_steal_pointer (&verbs),
@ -2864,6 +3072,9 @@ link_handlers_to_unregistered_apps (void)
GWin32AppInfoShellVerb *app_verb;
gsize ai;
if (app->is_uwp)
continue;
for (ai = 0; ai < app->verbs->len; ai++)
{
GWin32PrivateStat app_verb_exec_info;
@ -2914,6 +3125,9 @@ link_handlers_to_unregistered_apps (void)
(gpointer *) &appexe_fld_basename,
(gpointer *) &app))
{
if (app->is_uwp)
continue;
/* Use basename because apps_by_exe only has basenames */
if (g_strcmp0 (handler_exe_basename, appexe_fld_basename) != 0)
continue;
@ -2982,6 +3196,7 @@ link_handlers_to_fake_apps (void)
handler_verb->executable,
handler_verb->executable_folded,
FALSE,
FALSE,
FALSE);
g_clear_pointer (&exename_utf16, g_free);
handler_verb->app = g_object_ref (app);
@ -3032,6 +3247,7 @@ link_handlers_to_fake_apps (void)
handler_verb->command_utf8,
command_utf8_folded,
FALSE,
FALSE,
FALSE);
g_clear_pointer (&command_utf8_folded, g_free);
handler_verb->app = g_object_ref (app);
@ -3052,6 +3268,222 @@ link_handlers_to_fake_apps (void)
}
}
static GWin32AppInfoHandler *
find_uwp_handler_for_ext (GWin32AppInfoFileExtension *file_extn,
const gunichar2 *app_user_model_id)
{
GHashTableIter handler_iter;
gchar *handler_id_fld;
GWin32AppInfoHandler *handler;
g_hash_table_iter_init (&handler_iter, file_extn->handlers);
while (g_hash_table_iter_next (&handler_iter,
(gpointer *) &handler_id_fld,
(gpointer *) &handler))
{
if (handler->uwp_aumid == NULL)
continue;
if (_wcsicmp (handler->uwp_aumid, app_user_model_id) == 0)
return handler;
}
return NULL;
}
static GWin32AppInfoHandler *
find_uwp_handler_for_schema (GWin32AppInfoURLSchema *schema,
const gunichar2 *app_user_model_id)
{
GHashTableIter handler_iter;
gchar *handler_id_fld;
GWin32AppInfoHandler *handler;
g_hash_table_iter_init (&handler_iter, schema->handlers);
while (g_hash_table_iter_next (&handler_iter,
(gpointer *) &handler_id_fld,
(gpointer *) &handler))
{
if (handler->uwp_aumid == NULL)
continue;
if (_wcsicmp (handler->uwp_aumid, app_user_model_id) == 0)
return handler;
}
return NULL;
}
static gboolean
uwp_package_cb (gpointer user_data,
const gunichar2 *full_package_name,
const gunichar2 *package_name,
const gunichar2 *app_user_model_id,
gboolean show_in_applist,
GPtrArray *supported_extgroups,
GPtrArray *supported_protocols)
{
gint i, i_verb, i_ext;
gint extensions_considered;
GWin32AppInfoApplication *app;
gchar *app_user_model_id_u8;
gchar *app_user_model_id_u8_folded;
GHashTableIter iter;
GWin32AppInfoHandler *ext;
if (!g_utf16_to_utf8_and_fold (app_user_model_id,
-1,
&app_user_model_id_u8,
&app_user_model_id_u8_folded))
return TRUE;
app = get_app_object (apps_by_id,
app_user_model_id,
app_user_model_id_u8,
app_user_model_id_u8_folded,
TRUE,
FALSE,
TRUE);
extensions_considered = 0;
for (i = 0; i < supported_extgroups->len; i++)
{
GWin32PackageExtGroup *grp = (GWin32PackageExtGroup *) g_ptr_array_index (supported_extgroups, i);
extensions_considered += grp->extensions->len;
for (i_ext = 0; i_ext < grp->extensions->len; i_ext++)
{
wchar_t *ext = (wchar_t *) g_ptr_array_index (grp->extensions, i_ext);
gchar *ext_u8;
gchar *ext_u8_folded;
GWin32AppInfoFileExtension *file_extn;
GWin32AppInfoHandler *handler_rec;
if (!g_utf16_to_utf8_and_fold (ext,
-1,
&ext_u8,
&ext_u8_folded))
continue;
file_extn = get_ext_object (ext, ext_u8, ext_u8_folded);
g_free (ext_u8);
handler_rec = find_uwp_handler_for_ext (file_extn, app_user_model_id);
if (handler_rec == NULL)
{
/* Use AppUserModelId as the ID of the new fake handler */
handler_rec = get_handler_object (app_user_model_id_u8_folded,
NULL,
app_user_model_id,
app_user_model_id);
g_hash_table_insert (file_extn->handlers,
g_strdup (app_user_model_id_u8_folded),
g_object_ref (handler_rec));
}
/* This is somewhat wasteful, but for 100% correct handling
* we need to remember which extensions (handlers) support
* which verbs, and each handler gets its own copy of the
* verb object, since our design is handler-centric,
* not verb-centric. The app also gets a list of verbs,
* but without handlers it would have no idea which
* verbs can be used with which extensions.
*/
for (i_verb = 0; i_verb < grp->verbs->len; i_verb++)
{
wchar_t *verb = NULL;
verb = (wchar_t *) g_ptr_array_index (grp->verbs, i_verb);
/* *_add_verb() functions are no-ops when a verb already exists,
* so we're free to call them as many times as we want.
*/
uwp_handler_add_verb (handler_rec,
app,
verb,
NULL,
FALSE);
}
g_hash_table_insert (app->supported_exts,
g_steal_pointer (&ext_u8_folded),
g_object_ref (handler_rec));
}
}
g_hash_table_iter_init (&iter, app->supported_exts);
/* Pile up all handler verbs into the app too,
* for cases when we don't have a ref to a handler.
*/
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &ext))
{
gint i_hverb;
if (!ext)
continue;
for (i_hverb = 0; i_hverb < ext->verbs->len; i_hverb++)
{
GWin32AppInfoShellVerb *handler_verb;
handler_verb = _verb_idx (ext->verbs, i_hverb);
uwp_app_add_verb (app, handler_verb->verb_name, handler_verb->verb_displayname);
if (handler_verb->app == NULL && handler_verb->is_uwp)
handler_verb->app = g_object_ref (app);
}
}
if (app->verbs->len == 0 && extensions_considered > 0)
g_warning ("Unexpectedly, UWP app `%S' (AUMId `%s') supports %d extensions but has no verbs",
full_package_name, app_user_model_id_u8, extensions_considered);
for (i = 0; i < supported_protocols->len; i++)
{
wchar_t *proto = (wchar_t *) g_ptr_array_index (supported_protocols, i);
gchar *proto_u8;
gchar *proto_u8_folded;
GWin32AppInfoURLSchema *schema_rec;
GWin32AppInfoHandler *handler_rec;
if (!g_utf16_to_utf8_and_fold (proto,
-1,
&proto_u8,
&proto_u8_folded))
continue;
schema_rec = get_schema_object (proto,
proto_u8,
proto_u8_folded);
g_free (proto_u8);
handler_rec = find_uwp_handler_for_schema (schema_rec, app_user_model_id);
if (handler_rec == NULL)
{
/* Use AppUserModelId as the ID of the new fake handler */
handler_rec = get_handler_object (app_user_model_id_u8_folded,
NULL,
app_user_model_id,
app_user_model_id);
/* UWP URL handlers do not need any verbs */
g_hash_table_insert (schema_rec->handlers,
g_strdup (app_user_model_id_u8_folded),
g_object_ref (handler_rec));
}
g_hash_table_insert (app->supported_urls,
g_steal_pointer (&proto_u8_folded),
g_object_ref (handler_rec));
}
g_free (app_user_model_id_u8);
g_free (app_user_model_id_u8_folded);
return TRUE;
}
static void
update_registry_data (void)
@ -3063,7 +3495,8 @@ update_registry_data (void)
GWin32RegistryKey *url_associations;
GWin32RegistryKey *file_exts;
GWin32RegistryKey *classes_root;
DWORD collect_start, collect_end, alloc_end, capable_end, url_end, ext_end, exeapp_end, classes_end, postproc_end;
DWORD collect_start, collect_end, alloc_end, capable_end, url_end, ext_end, exeapp_end, classes_end, uwp_end, postproc_end;
GError *error = NULL;
url_associations =
g_win32_registry_key_new_w (L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations",
@ -3133,6 +3566,14 @@ update_registry_data (void)
exeapp_end = GetTickCount ();
read_classes (classes_root);
classes_end = GetTickCount ();
if (!g_win32_package_parser_enum_packages (uwp_package_cb, NULL, &error))
{
g_debug ("Unable to get UWP apps: %s", error->message);
g_clear_error (&error);
}
uwp_end = GetTickCount ();
link_handlers_to_unregistered_apps ();
link_handlers_to_fake_apps ();
postproc_end = GetTickCount ();
@ -3144,6 +3585,7 @@ update_registry_data (void)
"Reading extension assocs: %lums\n"
"Reading exe-only apps:...... %lums\n"
"Reading classes: %lums\n"
"Reading UWP apps: %lums\n"
"Postprocessing:..............%lums\n"
"TOTAL: %lums",
collect_end - collect_start,
@ -3153,7 +3595,8 @@ update_registry_data (void)
ext_end - url_end,
exeapp_end - ext_end,
classes_end - exeapp_end,
postproc_end - classes_end,
uwp_end - classes_end,
postproc_end - uwp_end,
postproc_end - collect_start);
g_clear_object (&classes_root);

View File

@ -430,6 +430,8 @@ else
cc.find_library('dnsapi'),
iphlpapi_dep,
winsock2]
platform_deps += uwp_gio_deps
win32_sources += files(
'gwin32registrykey.c',
'gwin32mount.c',
@ -437,6 +439,7 @@ else
'gwin32inputstream.c',
'gwin32outputstream.c',
'gwin32file-sync-stream.c',
'gwin32packageparser.c',
'gwin32networkmonitor.c',
'gwin32networkmonitor.h',
'gwin32notificationbackend.c',

View File

@ -466,9 +466,12 @@ if host_system == 'windows'
glib_conf.set('G_WINAPI_ONLY_APP', true)
# We require Windows 10+ on WinRT
glib_conf.set('_WIN32_WINNT', '0x0A00')
uwp_gio_deps = [cc.find_library('shcore'),
cc.find_library('runtimeobject')]
else
# We require Windows 7+ on Win32
glib_conf.set('_WIN32_WINNT', '0x0601')
uwp_gio_deps = []
endif
endif