2007-11-26 17:13:05 +01:00
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright ( C ) 2006 - 2007 Red Hat , Inc .
2014-08-29 10:53:35 +02:00
* Copyright ( C ) 2014 Р у с л а н И ж б у л а т о в
2007-11-26 17:13:05 +01:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2017-05-27 18:21:30 +02:00
* version 2.1 of the License , or ( at your option ) any later version .
2007-11-26 17:13:05 +01:00
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General
2014-01-23 12:58:29 +01:00
* Public License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2007-11-26 17:13:05 +01:00
*
2014-08-29 10:53:35 +02:00
* Authors : Alexander Larsson < alexl @ redhat . com >
* Р у с л а н И ж б у л а т о в < lrn1986 @ gmail . com >
2007-11-26 17:13:05 +01:00
*/
2008-06-22 17:10:51 +02:00
# include "config.h"
2007-11-26 17:13:05 +01:00
# include <string.h>
2012-07-04 03:14:41 +02:00
# include "gcontenttype.h"
2007-11-26 17:13:05 +01:00
# include "gwin32appinfo.h"
2008-07-02 03:52:37 +02:00
# include "gappinfo.h"
2007-11-26 17:13:05 +01:00
# include "gioerror.h"
2007-12-08 13:01:06 +01:00
# include "gfile.h"
2007-11-26 17:13:05 +01:00
# include <glib/gstdio.h>
# include "glibintl.h"
2014-08-29 10:53:35 +02:00
# include <gio/gwin32registrykey.h>
2007-11-26 17:13:05 +01:00
# include <windows.h>
2014-08-29 10:53:35 +02:00
/* We need to watch 8 places:
* 0 ) HKEY_CURRENT_USER \ \ Software \ \ Microsoft \ \ Windows \ \ Shell \ \ Associations \ \ UrlAssociations
* ( anything below that key )
* On change : re - enumerate subkeys , read their values .
* 1 ) HKEY_CURRENT_USER \ \ Software \ \ Microsoft \ \ Windows \ \ CurrentVersion \ \ Explorer \ \ FileExts
* ( anything below that key )
* On change : re - enumerate subkeys
* 2 ) HKEY_CURRENT_USER \ \ Software \ \ Clients ( anything below that key )
* On change : re - read the whole hierarchy of handlers
* 3 ) HKEY_LOCAL_MACHINE \ \ Software \ \ Clients ( anything below that key )
* On change : re - read the whole hierarchy of handlers
* 4 ) HKEY_LOCAL_MACHINE \ \ Software \ \ RegisteredApplications ( values of that key )
* On change : re - read the value list of registered applications
* 5 ) HKEY_CURRENT_USER \ \ Software \ \ RegisteredApplications ( values of that key )
* On change : re - read the value list of registered applications
* 6 ) HKEY_CLASSES_ROOT \ \ Applications ( anything below that key )
* On change : re - read the whole hierarchy of apps
* 7 ) HKEY_CLASSES_ROOT ( only its subkeys )
* On change : re - enumerate subkeys , try to filter out wrong names .
*
*/
typedef struct _GWin32AppInfoURLSchema GWin32AppInfoURLSchema ;
typedef struct _GWin32AppInfoFileExtension GWin32AppInfoFileExtension ;
typedef struct _GWin32AppInfoHandler GWin32AppInfoHandler ;
typedef struct _GWin32AppInfoApplication GWin32AppInfoApplication ;
typedef struct _GWin32AppInfoURLSchemaClass GWin32AppInfoURLSchemaClass ;
typedef struct _GWin32AppInfoFileExtensionClass GWin32AppInfoFileExtensionClass ;
typedef struct _GWin32AppInfoHandlerClass GWin32AppInfoHandlerClass ;
typedef struct _GWin32AppInfoApplicationClass GWin32AppInfoApplicationClass ;
struct _GWin32AppInfoURLSchemaClass
{
GObjectClass parent_class ;
} ;
struct _GWin32AppInfoFileExtensionClass
{
GObjectClass parent_class ;
} ;
struct _GWin32AppInfoHandlerClass
{
GObjectClass parent_class ;
} ;
struct _GWin32AppInfoApplicationClass
{
GObjectClass parent_class ;
} ;
struct _GWin32AppInfoURLSchema {
GObject parent_instance ;
/* url schema (stuff before ':') */
gunichar2 * schema ;
/* url schema (stuff before ':'), in UTF-8 */
gchar * schema_u8 ;
/* url schema (stuff before ':'), in UTF-8, folded */
gchar * schema_folded ;
/* Handler currently selected for this schema */
GWin32AppInfoHandler * chosen_handler ;
/* Maps folded handler IDs -> to other handlers for this schema */
GHashTable * handlers ;
} ;
struct _GWin32AppInfoHandler {
GObject parent_instance ;
/* Class name in HKCR */
gunichar2 * handler_id ;
/* Handler registry key (HKCR\\handler_id). Can be used to watch this handler. */
GWin32RegistryKey * key ;
/* Class name in HKCR, UTF-8, folded */
gchar * handler_id_folded ;
/* shell/open/command default value for the class named by class_id */
gunichar2 * handler_command ;
/* If handler_id class has no command, it might point to another class */
gunichar2 * proxy_id ;
/* Proxy registry key (HKCR\\proxy_id). Can be used to watch handler's proxy. */
GWin32RegistryKey * proxy_key ;
/* shell/open/command default value for the class named by proxy_id */
gunichar2 * proxy_command ;
/* Executable of the program (for matching, in folded form; UTF-8) */
gchar * executable_folded ;
/* Executable of the program (UTF-8) */
gchar * executable ;
/* Pointer to a location within @executable */
gchar * executable_basename ;
2019-11-29 17:48:32 +01:00
/* If not NULL, then @executable and its derived fields contain the name
* of a DLL file ( without the name of the function that rundll32 . exe should
* invoke ) , and this field contains the name of the function to be invoked .
* The application is then invoked as ' rundll32 . exe " dll_path " , dll_function other_arguments . . . ' .
*/
gchar * dll_function ;
2014-08-29 10:53:35 +02:00
/* Icon of the application for this handler */
GIcon * icon ;
/* The application that is linked to this handler. */
GWin32AppInfoApplication * app ;
} ;
struct _GWin32AppInfoFileExtension {
GObject parent_instance ;
/* File extension (with leading '.') */
gunichar2 * extension ;
/* File extension (with leading '.'), in UTF-8 */
gchar * extension_u8 ;
/* handler currently selected for this extension */
GWin32AppInfoHandler * chosen_handler ;
/* Maps folded handler IDs -> to other handlers for this extension */
GHashTable * handlers ;
/* Maps folded app exename -> to apps that support this extension.
* ONLY for apps that are not reachable via handlers ( i . e . apps from
* the HKCR / Applications , which have no handlers ) . */
GHashTable * other_apps ;
} ;
struct _GWin32AppInfoApplication {
GObject parent_instance ;
/* Canonical name (used for key names). Can be NULL. */
gunichar2 * canonical_name ;
/* Canonical name (used for key names), in UTF-8. Can be NULL. */
gchar * canonical_name_u8 ;
/* Canonical name (used for key names), in UTF-8, folded. Can be NULL. */
gchar * canonical_name_folded ;
/* Human-readable name in English. Can be NULL */
gunichar2 * pretty_name ;
/* Human-readable name in English, UTF-8. Can be NULL */
gchar * pretty_name_u8 ;
/* Human-readable name in user's language. Can be NULL */
gunichar2 * localized_pretty_name ;
/* Human-readable name in user's language, UTF-8. Can be NULL */
gchar * localized_pretty_name_u8 ;
/* Description, could be in user's language. Can be NULL */
gunichar2 * description ;
/* Description, could be in user's language, UTF-8. Can be NULL */
gchar * description_u8 ;
/* shell/open/command for the application. Can be NULL (see executable). */
gunichar2 * command ;
/* shell/open/command for the application. Can be NULL (see executable). */
gchar * command_u8 ;
/* Executable of the program (for matching, in folded form;
* UTF - 8 ) . Never NULL . */
gchar * executable_folded ;
/* Executable of the program (UTF-8). Never NULL. */
gchar * executable ;
/* Pointer to a location within @executable */
gchar * executable_basename ;
2019-11-29 17:48:32 +01:00
/* If not NULL, then @executable and its derived fields contain the name
* of a DLL file ( without the name of the function that rundll32 . exe should
* invoke ) , and this field contains the name of the function to be invoked .
* The application is then invoked as ' rundll32 . exe " dll_path " , dll_function other_arguments . . . ' .
*/
gchar * dll_function ;
2014-08-29 10:53:35 +02:00
/* Explicitly supported URLs, hashmap from map-owned gchar ptr (schema,
* UTF - 8 , folded ) - > a GWin32AppInfoHandler
* Schema can be used as a key in the urls hashmap .
*/
GHashTable * supported_urls ;
/* Explicitly supported extensions, hashmap from map-owned gchar ptr
* ( . extension , UTF - 8 , folded ) - > a GWin32AppInfoHandler
* Extension can be used as a key in the extensions hashmap .
*/
GHashTable * supported_exts ;
/* Icon of the application (remember, handler can have its own icon too) */
GIcon * icon ;
/* Set to TRUE to prevent this app from appearing in lists of apps for
* opening files . This will not prevent it from appearing in lists of apps
* just for running , or lists of apps for opening exts / urls for which this
* app reports explicit support .
*/
gboolean no_open_with ;
/* Set to TRUE for applications from HKEY_CURRENT_USER.
* Give them priority over applications from HKEY_LOCAL_MACHINE , when all
* other things are equal .
*/
gboolean user_specific ;
/* Set to TRUE for applications that are machine-wide defaults (i.e. default
* browser ) */
gboolean default_app ;
} ;
# define G_TYPE_WIN32_APPINFO_URL_SCHEMA (g_win32_appinfo_url_schema_get_type ())
# define G_WIN32_APPINFO_URL_SCHEMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_APPINFO_URL_SCHEMA, GWin32AppInfoURLSchema))
# define G_TYPE_WIN32_APPINFO_FILE_EXTENSION (g_win32_appinfo_file_extension_get_type ())
# define G_WIN32_APPINFO_FILE_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_APPINFO_FILE_EXTENSION, GWin32AppInfoFileExtension))
# define G_TYPE_WIN32_APPINFO_HANDLER (g_win32_appinfo_handler_get_type ())
# define G_WIN32_APPINFO_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_APPINFO_HANDLER, GWin32AppInfoHandler))
# define G_TYPE_WIN32_APPINFO_APPLICATION (g_win32_appinfo_application_get_type ())
# define G_WIN32_APPINFO_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WIN32_APPINFO_APPLICATION, GWin32AppInfoApplication))
GType g_win32_appinfo_url_schema_get_type ( void ) G_GNUC_CONST ;
GType g_win32_appinfo_file_extension_get_type ( void ) G_GNUC_CONST ;
GType g_win32_appinfo_handler_get_type ( void ) G_GNUC_CONST ;
GType g_win32_appinfo_application_get_type ( void ) G_GNUC_CONST ;
G_DEFINE_TYPE ( GWin32AppInfoURLSchema , g_win32_appinfo_url_schema , G_TYPE_OBJECT )
G_DEFINE_TYPE ( GWin32AppInfoFileExtension , g_win32_appinfo_file_extension , G_TYPE_OBJECT )
G_DEFINE_TYPE ( GWin32AppInfoHandler , g_win32_appinfo_handler , G_TYPE_OBJECT )
G_DEFINE_TYPE ( GWin32AppInfoApplication , g_win32_appinfo_application , G_TYPE_OBJECT )
static void
g_win32_appinfo_url_schema_dispose ( GObject * object )
{
GWin32AppInfoURLSchema * url = G_WIN32_APPINFO_URL_SCHEMA ( object ) ;
g_clear_pointer ( & url - > schema , g_free ) ;
g_clear_pointer ( & url - > schema_u8 , g_free ) ;
g_clear_pointer ( & url - > schema_folded , g_free ) ;
g_clear_object ( & url - > chosen_handler ) ;
g_clear_pointer ( & url - > handlers , g_hash_table_destroy ) ;
G_OBJECT_CLASS ( g_win32_appinfo_url_schema_parent_class ) - > dispose ( object ) ;
}
static void
g_win32_appinfo_handler_dispose ( GObject * object )
{
GWin32AppInfoHandler * handler = G_WIN32_APPINFO_HANDLER ( object ) ;
g_clear_pointer ( & handler - > handler_id , g_free ) ;
g_clear_pointer ( & handler - > handler_id_folded , g_free ) ;
g_clear_pointer ( & handler - > handler_command , g_free ) ;
g_clear_pointer ( & handler - > proxy_id , g_free ) ;
g_clear_pointer ( & handler - > proxy_command , g_free ) ;
g_clear_pointer ( & handler - > executable_folded , g_free ) ;
g_clear_pointer ( & handler - > executable , g_free ) ;
2019-11-29 17:48:32 +01:00
g_clear_pointer ( & handler - > dll_function , g_free ) ;
2014-08-29 10:53:35 +02:00
g_clear_object ( & handler - > key ) ;
g_clear_object ( & handler - > proxy_key ) ;
g_clear_object ( & handler - > icon ) ;
g_clear_object ( & handler - > app ) ;
G_OBJECT_CLASS ( g_win32_appinfo_handler_parent_class ) - > dispose ( object ) ;
}
static void
g_win32_appinfo_file_extension_dispose ( GObject * object )
{
GWin32AppInfoFileExtension * ext = G_WIN32_APPINFO_FILE_EXTENSION ( object ) ;
g_clear_pointer ( & ext - > extension , g_free ) ;
g_clear_pointer ( & ext - > extension_u8 , g_free ) ;
g_clear_object ( & ext - > chosen_handler ) ;
g_clear_pointer ( & ext - > handlers , g_hash_table_destroy ) ;
g_clear_pointer ( & ext - > other_apps , g_hash_table_destroy ) ;
G_OBJECT_CLASS ( g_win32_appinfo_file_extension_parent_class ) - > dispose ( object ) ;
}
static void
g_win32_appinfo_application_dispose ( GObject * object )
{
GWin32AppInfoApplication * app = G_WIN32_APPINFO_APPLICATION ( object ) ;
g_clear_pointer ( & app - > canonical_name_u8 , g_free ) ;
g_clear_pointer ( & app - > canonical_name_folded , g_free ) ;
g_clear_pointer ( & app - > canonical_name , g_free ) ;
g_clear_pointer ( & app - > pretty_name , g_free ) ;
g_clear_pointer ( & app - > localized_pretty_name , g_free ) ;
g_clear_pointer ( & app - > description , g_free ) ;
g_clear_pointer ( & app - > command , g_free ) ;
g_clear_pointer ( & app - > pretty_name_u8 , g_free ) ;
g_clear_pointer ( & app - > localized_pretty_name_u8 , g_free ) ;
g_clear_pointer ( & app - > description_u8 , g_free ) ;
g_clear_pointer ( & app - > command_u8 , g_free ) ;
g_clear_pointer ( & app - > executable_folded , g_free ) ;
g_clear_pointer ( & app - > executable , g_free ) ;
2019-11-29 17:48:32 +01:00
g_clear_pointer ( & app - > dll_function , g_free ) ;
2014-08-29 10:53:35 +02:00
g_clear_pointer ( & app - > supported_urls , g_hash_table_destroy ) ;
g_clear_pointer ( & app - > supported_exts , g_hash_table_destroy ) ;
g_clear_object ( & app - > icon ) ;
G_OBJECT_CLASS ( g_win32_appinfo_application_parent_class ) - > dispose ( object ) ;
}
static void
g_win32_appinfo_url_schema_class_init ( GWin32AppInfoURLSchemaClass * klass )
{
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
gobject_class - > dispose = g_win32_appinfo_url_schema_dispose ;
}
static void
g_win32_appinfo_file_extension_class_init ( GWin32AppInfoFileExtensionClass * klass )
{
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
gobject_class - > dispose = g_win32_appinfo_file_extension_dispose ;
}
static void
g_win32_appinfo_handler_class_init ( GWin32AppInfoHandlerClass * klass )
{
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
gobject_class - > dispose = g_win32_appinfo_handler_dispose ;
}
static void
g_win32_appinfo_application_class_init ( GWin32AppInfoApplicationClass * klass )
{
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
gobject_class - > dispose = g_win32_appinfo_application_dispose ;
}
static void
g_win32_appinfo_url_schema_init ( GWin32AppInfoURLSchema * self )
{
self - > handlers = g_hash_table_new_full ( g_str_hash ,
g_str_equal ,
g_free ,
g_object_unref ) ;
}
static void
g_win32_appinfo_file_extension_init ( GWin32AppInfoFileExtension * self )
{
self - > handlers = g_hash_table_new_full ( g_str_hash ,
g_str_equal ,
g_free ,
g_object_unref ) ;
self - > other_apps = g_hash_table_new_full ( g_str_hash ,
g_str_equal ,
g_free ,
g_object_unref ) ;
}
static void
g_win32_appinfo_handler_init ( GWin32AppInfoHandler * self )
{
}
static void
g_win32_appinfo_application_init ( GWin32AppInfoApplication * self )
{
self - > supported_urls = g_hash_table_new_full ( g_str_hash ,
g_str_equal ,
g_free ,
g_object_unref ) ;
self - > supported_exts = g_hash_table_new_full ( g_str_hash ,
g_str_equal ,
g_free ,
g_object_unref ) ;
}
G_LOCK_DEFINE_STATIC ( gio_win32_appinfo ) ;
/* Map of owned ".ext" (with '.', UTF-8, folded)
* to GWin32AppInfoFileExtension ptr
*/
static GHashTable * extensions = NULL ;
/* Map of owned "schema" (without ':', UTF-8, folded)
* to GWin32AppInfoURLSchema ptr
*/
static GHashTable * urls = NULL ;
/* Map of owned "appID" (UTF-8, folded) to
* GWin32AppInfoApplication ptr
*/
static GHashTable * apps_by_id = NULL ;
/* Map of owned "app.exe" (UTF-8, folded) to
* GWin32AppInfoApplication ptr .
* This map and its values are separate from apps_by_id . The fact that an app
* with known ID has the same executable [ base ] name as an app in this map does
* not mean that they are the same application .
*/
static GHashTable * apps_by_exe = NULL ;
/* Map of owned "handler id" (UTF-8, folded)
* to GWin32AppInfoHandler ptr
*/
static GHashTable * handlers = NULL ;
/* Watch this whole subtree */
static GWin32RegistryKey * url_associations_key ;
/* Watch this whole subtree */
static GWin32RegistryKey * file_exts_key ;
/* Watch this whole subtree */
static GWin32RegistryKey * user_clients_key ;
/* Watch this whole subtree */
static GWin32RegistryKey * system_clients_key ;
/* Watch this key */
static GWin32RegistryKey * user_registered_apps_key ;
/* Watch this key */
static GWin32RegistryKey * system_registered_apps_key ;
/* Watch this whole subtree */
static GWin32RegistryKey * applications_key ;
/* Watch this key */
static GWin32RegistryKey * classes_root_key ;
# define URL_ASSOCIATIONS L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\"
# define USER_CHOICE L"\\UserChoice"
# define OPEN_WITH_PROGIDS L"\\OpenWithProgids"
# define FILE_EXTS L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"
# define HKCR L"HKEY_CLASSES_ROOT\\"
# define HKCU L"HKEY_CURRENT_USER\\"
# define HKLM L"HKEY_LOCAL_MACHINE\\"
# define SHELL_OPEN_COMMAND L"\\shell\\open\\command"
# define REG_PATH_MAX 256
# define REG_PATH_MAX_SIZE (REG_PATH_MAX * sizeof (gunichar2))
2019-11-29 17:48:32 +01:00
/* for g_wcsdup(),
* _g_win32_extract_executable ( ) ,
* _g_win32_fixup_broken_microsoft_rundll_commandline ( )
*/
# include "giowin32-private.c"
2014-08-29 10:53:35 +02:00
static void
read_handler_icon ( GWin32RegistryKey * proxy_key ,
GWin32RegistryKey * program_key ,
GIcon * * icon_out )
{
gint counter ;
GWin32RegistryKey * key ;
* icon_out = NULL ;
for ( counter = 0 ; counter < 2 ; counter + + )
{
GWin32RegistryKey * icon_key ;
if ( counter = = 0 )
key = proxy_key ;
else
key = program_key ;
if ( ! key )
continue ;
icon_key = g_win32_registry_key_get_child_w ( key , L " DefaultIcon " , NULL ) ;
if ( icon_key ! = NULL )
{
GWin32RegistryValueType default_type ;
gchar * default_value ;
if ( g_win32_registry_key_get_value ( icon_key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
" " ,
& default_type ,
( gpointer * ) & default_value ,
NULL ,
NULL ) )
{
if ( default_type = = G_WIN32_REGISTRY_VALUE_STR | |
default_value [ 0 ] ! = ' \0 ' )
* icon_out = g_themed_icon_new ( default_value ) ;
g_clear_pointer ( & default_value , g_free ) ;
}
g_object_unref ( icon_key ) ;
}
if ( * icon_out )
break ;
}
}
static gboolean build_registry_path ( gunichar2 * output , gsize output_size , . . . ) G_GNUC_NULL_TERMINATED ;
static gboolean build_registry_pathv ( gunichar2 * output , gsize output_size , va_list components ) ;
static GWin32RegistryKey * _g_win32_registry_key_build_and_new_w ( GError * * error , . . . ) G_GNUC_NULL_TERMINATED ;
/* output_size is in *bytes*, not gunichar2s! */
static gboolean
build_registry_path ( gunichar2 * output , gsize output_size , . . . )
{
va_list ap ;
gboolean result ;
va_start ( ap , output_size ) ;
result = build_registry_pathv ( output , output_size , ap ) ;
va_end ( ap ) ;
return result ;
}
/* output_size is in *bytes*, not gunichar2s! */
static gboolean
build_registry_pathv ( gunichar2 * output , gsize output_size , va_list components )
{
va_list lentest ;
gunichar2 * p ;
gunichar2 * component ;
gsize length ;
if ( output = = NULL )
return FALSE ;
2015-05-17 13:42:55 +02:00
G_VA_COPY ( lentest , components ) ;
2014-08-29 10:53:35 +02:00
for ( length = 0 , component = va_arg ( lentest , gunichar2 * ) ;
component ! = NULL ;
component = va_arg ( lentest , gunichar2 * ) )
{
length + = wcslen ( component ) ;
}
va_end ( lentest ) ;
if ( ( length > = REG_PATH_MAX_SIZE ) | |
( length * sizeof ( gunichar2 ) > = output_size ) )
return FALSE ;
output [ 0 ] = L ' \0 ' ;
for ( p = output , component = va_arg ( components , gunichar2 * ) ;
component ! = NULL ;
component = va_arg ( components , gunichar2 * ) )
{
length = wcslen ( component ) ;
wcscat ( p , component ) ;
p + = length ;
}
return TRUE ;
}
static GWin32RegistryKey *
_g_win32_registry_key_build_and_new_w ( GError * * error , . . . )
{
va_list ap ;
gunichar2 key_path [ REG_PATH_MAX_SIZE + 1 ] ;
GWin32RegistryKey * key ;
va_start ( ap , error ) ;
key = NULL ;
if ( build_registry_pathv ( key_path , sizeof ( key_path ) , ap ) )
key = g_win32_registry_key_new_w ( key_path , error ) ;
va_end ( ap ) ;
return key ;
}
2019-11-29 17:48:32 +01:00
/* Slow and dirty validator for UTF-16 strings */
2014-08-29 10:53:35 +02:00
static gboolean
2019-11-29 17:48:32 +01:00
g_utf16_validate ( const gunichar2 * str ,
glong len )
2014-08-29 10:53:35 +02:00
{
2019-11-29 17:48:32 +01:00
gchar * tmp ;
2014-08-29 10:53:35 +02:00
2019-11-29 17:48:32 +01:00
if ( str = = NULL )
2014-08-29 10:53:35 +02:00
return FALSE ;
2019-11-29 17:48:32 +01:00
tmp = g_utf16_to_utf8 ( str , len , NULL , NULL , NULL ) ;
2014-08-29 10:53:35 +02:00
2019-11-29 17:48:32 +01:00
if ( tmp = = NULL )
return FALSE ;
2014-08-29 10:53:35 +02:00
2019-11-29 17:48:32 +01:00
g_free ( tmp ) ;
2014-08-29 10:53:35 +02:00
return TRUE ;
}
2019-11-29 17:48:32 +01:00
/* Does a UTF-16 validity check on *proxy_command and/or *program_command.
* Fails if that check doesn ' t pass .
*/
2014-08-29 10:53:35 +02:00
static gboolean
follow_class_chain_to_handler ( const gunichar2 * program_id ,
gsize program_id_size ,
gunichar2 * * program_command ,
GWin32RegistryKey * * program_key ,
gunichar2 * * proxy_id ,
gunichar2 * * proxy_command ,
GWin32RegistryKey * * proxy_key ,
gchar * * program_id_u8 ,
gchar * * program_id_folded )
{
GWin32RegistryKey * key ;
GWin32RegistryValueType val_type ;
gsize proxy_id_size ;
gboolean got_value ;
g_assert ( program_id & & program_command & & proxy_id & & proxy_command ) ;
* program_command = NULL ;
* proxy_id = NULL ;
* proxy_command = NULL ;
if ( program_key )
* program_key = NULL ;
if ( proxy_key )
* proxy_key = NULL ;
key = _g_win32_registry_key_build_and_new_w ( NULL , HKCR , program_id ,
SHELL_OPEN_COMMAND , NULL ) ;
if ( key ! = NULL )
{
got_value = g_win32_registry_key_get_value_w ( key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& val_type ,
( void * * ) program_command ,
NULL ,
NULL ) ;
if ( got_value & & val_type = = G_WIN32_REGISTRY_VALUE_STR )
{
2019-11-29 17:48:32 +01:00
if ( ( ( program_id_u8 ! = NULL | | program_id_folded ! = NULL ) & &
! g_utf16_to_utf8_and_fold ( program_id , - 1 , program_id_u8 , program_id_folded ) ) | |
! g_utf16_validate ( * program_command , - 1 ) )
2014-08-29 10:53:35 +02:00
{
g_object_unref ( key ) ;
g_free ( program_command ) ;
return FALSE ;
}
if ( program_key = = NULL )
g_object_unref ( key ) ;
else
* program_key = key ;
return TRUE ;
}
else if ( got_value )
g_clear_pointer ( program_command , g_free ) ;
g_object_unref ( key ) ;
}
key = _g_win32_registry_key_build_and_new_w ( NULL , HKCR , program_id , NULL ) ;
if ( key = = NULL )
return FALSE ;
got_value = g_win32_registry_key_get_value_w ( key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& val_type ,
( void * * ) proxy_id ,
& proxy_id_size ,
NULL ) ;
2019-11-29 17:48:32 +01:00
g_object_unref ( key ) ;
2014-08-29 10:53:35 +02:00
if ( ! got_value | |
( val_type ! = G_WIN32_REGISTRY_VALUE_STR ) )
{
g_clear_pointer ( proxy_id , g_free ) ;
2019-11-29 17:48:32 +01:00
2014-08-29 10:53:35 +02:00
return FALSE ;
}
key = _g_win32_registry_key_build_and_new_w ( NULL , HKCR , * proxy_id ,
SHELL_OPEN_COMMAND , NULL ) ;
if ( key = = NULL )
{
g_clear_pointer ( proxy_id , g_free ) ;
2019-11-29 17:48:32 +01:00
2014-08-29 10:53:35 +02:00
return FALSE ;
}
got_value = g_win32_registry_key_get_value_w ( key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& val_type ,
( void * * ) proxy_command ,
NULL ,
NULL ) ;
2019-11-29 17:48:32 +01:00
if ( proxy_key )
* proxy_key = key ;
else
g_object_unref ( key ) ;
2014-08-29 10:53:35 +02:00
if ( ! got_value | |
val_type ! = G_WIN32_REGISTRY_VALUE_STR | |
( ( program_id_u8 ! = NULL | | program_id_folded ! = NULL ) & &
2019-11-29 17:48:32 +01:00
! g_utf16_to_utf8_and_fold ( program_id , - 1 , program_id_u8 , program_id_folded ) ) | |
! g_utf16_validate ( * proxy_command , - 1 ) )
2014-08-29 10:53:35 +02:00
{
g_clear_pointer ( proxy_id , g_free ) ;
g_clear_pointer ( proxy_command , g_free ) ;
if ( proxy_key )
g_clear_object ( proxy_key ) ;
return FALSE ;
}
return TRUE ;
}
static void
get_url_association ( const gunichar2 * schema )
{
GWin32AppInfoURLSchema * schema_rec ;
GWin32AppInfoHandler * handler_rec ;
GWin32AppInfoHandler * handler_rec_in_url ;
gchar * schema_u8 ;
gchar * schema_folded ;
GWin32RegistryKey * user_choice ;
GWin32RegistryValueType val_type ;
gunichar2 * program_id ;
gsize program_id_size ;
gunichar2 * program_command ;
gunichar2 * proxy_id ;
gunichar2 * proxy_command ;
gchar * program_id_u8 ;
gchar * program_id_folded ;
GWin32RegistryKey * program_key ;
GWin32RegistryKey * proxy_key ;
user_choice = _g_win32_registry_key_build_and_new_w ( NULL , URL_ASSOCIATIONS ,
schema , USER_CHOICE ,
NULL ) ;
if ( user_choice = = NULL )
return ;
2019-11-29 17:48:32 +01:00
if ( ! g_utf16_to_utf8_and_fold ( schema , - 1 , & schema_u8 , & schema_folded ) )
2014-08-29 10:53:35 +02:00
{
g_object_unref ( user_choice ) ;
return ;
}
schema_rec = g_hash_table_lookup ( urls , schema_folded ) ;
if ( ! g_win32_registry_key_get_value_w ( user_choice ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " Progid " ,
& val_type ,
( void * * ) & program_id ,
& program_id_size ,
NULL ) )
{
g_free ( schema_u8 ) ;
g_free ( schema_folded ) ;
g_object_unref ( user_choice ) ;
return ;
}
if ( val_type ! = G_WIN32_REGISTRY_VALUE_STR )
{
g_free ( schema_u8 ) ;
g_free ( schema_folded ) ;
g_free ( program_id ) ;
g_object_unref ( user_choice ) ;
return ;
}
program_key = proxy_key = NULL ;
program_command = proxy_id = proxy_command = NULL ;
if ( ! follow_class_chain_to_handler ( program_id ,
program_id_size ,
& program_command ,
& program_key ,
& proxy_id ,
& proxy_command ,
& proxy_key ,
& program_id_u8 ,
& program_id_folded ) )
{
g_free ( schema_u8 ) ;
g_free ( schema_folded ) ;
g_free ( program_id ) ;
g_object_unref ( user_choice ) ;
return ;
}
handler_rec = g_hash_table_lookup ( handlers , program_id_folded ) ;
if ( handler_rec = = NULL )
{
handler_rec = g_object_new ( G_TYPE_WIN32_APPINFO_HANDLER , NULL ) ;
handler_rec - > proxy_key = proxy_key ;
handler_rec - > key = program_key ;
handler_rec - > handler_id = g_wcsdup ( program_id , program_id_size ) ;
handler_rec - > handler_id_folded =
g_strdup ( program_id_folded ) ;
handler_rec - > handler_command =
program_command ? g_wcsdup ( program_command , - 1 ) : NULL ;
handler_rec - > proxy_id = proxy_id ? g_wcsdup ( proxy_id , - 1 ) : NULL ;
handler_rec - > proxy_command =
proxy_command ? g_wcsdup ( proxy_command , - 1 ) : NULL ;
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( proxy_command ? proxy_command : program_command ,
& handler_rec - > executable ,
& handler_rec - > executable_basename ,
& handler_rec - > executable_folded ,
NULL ,
& handler_rec - > dll_function ) ;
if ( handler_rec - > dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( handler_rec - > handler_command ? handler_rec - > handler_command : handler_rec - > proxy_command ) ;
2014-08-29 10:53:35 +02:00
read_handler_icon ( proxy_key , program_key , & handler_rec - > icon ) ;
g_hash_table_insert ( handlers ,
g_strdup ( program_id_folded ) ,
handler_rec ) ;
}
else
{
g_clear_object ( & program_key ) ;
g_clear_object ( & proxy_key ) ;
}
if ( schema_rec = = NULL )
{
schema_rec = g_object_new ( G_TYPE_WIN32_APPINFO_URL_SCHEMA , NULL ) ;
schema_rec - > schema = g_wcsdup ( schema , - 1 ) ;
schema_rec - > schema_u8 = g_strdup ( schema_u8 ) ;
schema_rec - > schema_folded = g_strdup ( schema_folded ) ;
schema_rec - > chosen_handler = g_object_ref ( handler_rec ) ;
g_hash_table_insert ( urls , g_strdup ( schema_folded ) , schema_rec ) ;
}
if ( schema_rec - > chosen_handler = = NULL )
schema_rec - > chosen_handler = g_object_ref ( handler_rec ) ;
handler_rec_in_url = g_hash_table_lookup ( schema_rec - > handlers ,
program_id_folded ) ;
if ( handler_rec_in_url = = NULL & & schema_rec - > chosen_handler ! = handler_rec )
g_hash_table_insert ( schema_rec - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
g_free ( schema_u8 ) ;
g_free ( schema_folded ) ;
g_free ( program_id ) ;
g_free ( program_id_u8 ) ;
g_free ( program_id_folded ) ;
g_free ( program_command ) ;
g_free ( proxy_id ) ;
g_free ( proxy_command ) ;
g_object_unref ( user_choice ) ;
}
static void
get_file_ext ( const gunichar2 * ext )
{
GWin32AppInfoFileExtension * file_extn ;
gboolean file_ext_known ;
GWin32AppInfoHandler * handler_rec ;
GWin32AppInfoHandler * handler_rec_in_ext ;
gchar * ext_u8 ;
gchar * ext_folded ;
GWin32RegistryKey * user_choice ;
GWin32RegistryKey * open_with_progids ;
GWin32RegistryValueType val_type ;
gsize program_id_size ;
gboolean found_handler ;
gunichar2 * program_id ;
gunichar2 * proxy_id ;
gchar * program_id_u8 ;
gchar * program_id_folded ;
GWin32RegistryKey * program_key ;
GWin32RegistryKey * proxy_key ;
gunichar2 * program_command ;
gunichar2 * proxy_command ;
open_with_progids = _g_win32_registry_key_build_and_new_w ( NULL , FILE_EXTS ,
ext ,
OPEN_WITH_PROGIDS ,
NULL ) ;
user_choice = _g_win32_registry_key_build_and_new_w ( NULL , FILE_EXTS , ext ,
USER_CHOICE , NULL ) ;
if ( user_choice = = NULL & & open_with_progids = = NULL )
return ;
2019-11-29 17:48:32 +01:00
if ( ! g_utf16_to_utf8_and_fold ( ext , - 1 , & ext_u8 , & ext_folded ) )
2014-08-29 10:53:35 +02:00
{
g_clear_object ( & user_choice ) ;
g_clear_object ( & open_with_progids ) ;
return ;
}
file_extn = NULL ;
file_ext_known = g_hash_table_lookup_extended ( extensions ,
ext_folded ,
NULL ,
( void * * ) & file_extn ) ;
if ( ! file_ext_known )
file_extn = g_object_new ( G_TYPE_WIN32_APPINFO_FILE_EXTENSION , NULL ) ;
found_handler = FALSE ;
if ( user_choice ! = NULL )
{
if ( g_win32_registry_key_get_value_w ( user_choice ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " Progid " ,
& val_type ,
( void * * ) & program_id ,
& program_id_size ,
NULL ) )
{
program_key = proxy_key = NULL ;
if ( val_type = = G_WIN32_REGISTRY_VALUE_STR & &
follow_class_chain_to_handler ( program_id ,
program_id_size ,
& program_command ,
& program_key ,
& proxy_id ,
& proxy_command ,
& proxy_key ,
& program_id_u8 ,
& program_id_folded ) )
{
handler_rec = g_hash_table_lookup ( handlers ,
program_id_folded ) ;
if ( handler_rec = = NULL )
{
handler_rec = g_object_new ( G_TYPE_WIN32_APPINFO_HANDLER ,
NULL ) ;
handler_rec - > proxy_key = proxy_key ;
handler_rec - > key = program_key ;
handler_rec - > handler_id =
g_wcsdup ( program_id , program_id_size ) ;
handler_rec - > handler_id_folded =
g_strdup ( program_id_folded ) ;
handler_rec - > handler_command =
program_command ? g_wcsdup ( program_command , - 1 ) : NULL ;
handler_rec - > proxy_id =
proxy_id ? g_wcsdup ( proxy_id , - 1 ) : NULL ;
handler_rec - > proxy_command =
proxy_command ? g_wcsdup ( proxy_command , - 1 ) : NULL ;
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( proxy_command ? proxy_command : program_command ,
& handler_rec - > executable ,
& handler_rec - > executable_basename ,
& handler_rec - > executable_folded ,
NULL ,
& handler_rec - > dll_function ) ;
if ( handler_rec - > dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( handler_rec - > handler_command ? handler_rec - > handler_command : handler_rec - > proxy_command ) ;
2014-08-29 10:53:35 +02:00
read_handler_icon ( proxy_key ,
program_key ,
& handler_rec - > icon ) ;
g_hash_table_insert ( handlers ,
g_strdup ( program_id_folded ) ,
handler_rec ) ;
}
else
{
g_clear_object ( & program_key ) ;
g_clear_object ( & proxy_key ) ;
}
found_handler = TRUE ;
handler_rec_in_ext = g_hash_table_lookup ( file_extn - > handlers ,
program_id_folded ) ;
if ( file_extn - > chosen_handler = = NULL )
{
g_hash_table_insert ( file_extn - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
}
else if ( handler_rec_in_ext = = NULL )
{
if ( file_extn - > chosen_handler - > handler_id_folded & &
strcmp ( file_extn - > chosen_handler - > handler_id_folded ,
program_id_folded ) ! = 0 )
g_hash_table_insert ( file_extn - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
}
g_free ( program_id_u8 ) ;
g_free ( program_id_folded ) ;
g_free ( program_command ) ;
g_free ( proxy_id ) ;
g_free ( proxy_command ) ;
}
g_free ( program_id ) ;
}
g_object_unref ( user_choice ) ;
}
if ( open_with_progids ! = NULL )
{
GWin32RegistryValueIter iter ;
if ( g_win32_registry_value_iter_init ( & iter , open_with_progids , NULL ) )
{
gunichar2 * value_name ;
gunichar2 * value_data ;
gsize value_name_len ;
gsize value_data_size ;
GWin32RegistryValueType value_type ;
while ( g_win32_registry_value_iter_next ( & iter , TRUE , NULL ) )
{
gsize value_name_size ;
program_key = proxy_key = NULL ;
if ( ( ! g_win32_registry_value_iter_get_value_type ( & iter ,
& value_type ,
NULL ) ) | |
( ( val_type ! = G_WIN32_REGISTRY_VALUE_STR ) & &
( val_type ! = G_WIN32_REGISTRY_VALUE_EXPAND_STR ) ) | |
( ! g_win32_registry_value_iter_get_name_w ( & iter , & value_name ,
& value_name_len ,
NULL ) ) | |
( value_name_len < = 0 ) | |
( ! g_win32_registry_value_iter_get_data_w ( & iter , TRUE ,
( void * * ) & value_data ,
& value_data_size ,
NULL ) ) | |
( value_data_size < sizeof ( gunichar2 ) ) | |
( value_data [ 0 ] = = L ' \0 ' ) )
continue ;
value_name_size = sizeof ( gunichar2 ) * ( value_name_len + 1 ) ;
if ( ! follow_class_chain_to_handler ( value_name ,
value_name_size ,
& program_command ,
& program_key ,
& proxy_id ,
& proxy_command ,
& proxy_key ,
& program_id_u8 ,
& program_id_folded ) )
continue ;
handler_rec = g_hash_table_lookup ( handlers ,
program_id_folded ) ;
if ( handler_rec = = NULL )
{
handler_rec = g_object_new ( G_TYPE_WIN32_APPINFO_HANDLER , NULL ) ;
handler_rec - > proxy_key = proxy_key ;
handler_rec - > key = program_key ;
handler_rec - > handler_id =
g_wcsdup ( value_name , value_name_size ) ;
handler_rec - > handler_id_folded =
g_strdup ( program_id_folded ) ;
handler_rec - > handler_command =
program_command ? g_wcsdup ( program_command , - 1 ) : NULL ;
handler_rec - > proxy_id =
proxy_id ? g_wcsdup ( proxy_id , - 1 ) : NULL ;
handler_rec - > proxy_command =
proxy_command ? g_wcsdup ( proxy_command , - 1 ) : NULL ;
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( proxy_command ? proxy_command : program_command ,
& handler_rec - > executable ,
& handler_rec - > executable_basename ,
& handler_rec - > executable_folded ,
NULL ,
& handler_rec - > dll_function ) ;
if ( handler_rec - > dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( handler_rec - > handler_command ? handler_rec - > handler_command : handler_rec - > proxy_command ) ;
2014-08-29 10:53:35 +02:00
read_handler_icon ( proxy_key ,
program_key ,
& handler_rec - > icon ) ;
g_hash_table_insert ( handlers ,
g_strdup ( program_id_folded ) ,
handler_rec ) ;
}
else
{
g_clear_object ( & program_key ) ;
g_clear_object ( & proxy_key ) ;
}
found_handler = TRUE ;
handler_rec_in_ext = g_hash_table_lookup ( file_extn - > handlers ,
program_id_folded ) ;
if ( handler_rec_in_ext = = NULL )
{
if ( file_extn - > chosen_handler = = NULL )
g_hash_table_insert ( file_extn - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
else if ( file_extn - > chosen_handler - > handler_id_folded & &
strcmp ( file_extn - > chosen_handler - > handler_id_folded ,
program_id_folded ) ! = 0 )
g_hash_table_insert ( file_extn - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
}
g_free ( program_id_u8 ) ;
g_free ( program_id_folded ) ;
g_free ( program_command ) ;
g_free ( proxy_id ) ;
g_free ( proxy_command ) ;
}
g_win32_registry_value_iter_clear ( & iter ) ;
}
g_object_unref ( open_with_progids ) ;
}
if ( ! found_handler )
{
if ( ! file_ext_known )
g_object_unref ( file_extn ) ;
}
else if ( ! file_ext_known )
{
file_extn - > extension = g_wcsdup ( ext , - 1 ) ;
file_extn - > extension_u8 = g_strdup ( ext_u8 ) ;
g_hash_table_insert ( extensions , g_strdup ( ext_folded ) , file_extn ) ;
}
g_free ( ext_u8 ) ;
g_free ( ext_folded ) ;
}
static void
collect_capable_apps_from_clients ( GPtrArray * capable_apps ,
GPtrArray * priority_capable_apps ,
gboolean user_registry )
{
GWin32RegistryKey * clients ;
GWin32RegistrySubkeyIter clients_iter ;
gunichar2 * client_type_name ;
gsize client_type_name_len ;
if ( user_registry )
clients =
g_win32_registry_key_new_w ( L " HKEY_CURRENT_USER \\ Software \\ Clients " ,
NULL ) ;
else
clients =
g_win32_registry_key_new_w ( L " HKEY_LOCAL_MACHINE \\ Software \\ Clients " ,
NULL ) ;
if ( clients = = NULL )
return ;
if ( ! g_win32_registry_subkey_iter_init ( & clients_iter , clients , NULL ) )
{
g_object_unref ( clients ) ;
return ;
}
while ( g_win32_registry_subkey_iter_next ( & clients_iter , TRUE , NULL ) )
{
GWin32RegistrySubkeyIter subkey_iter ;
GWin32RegistryKey * system_client_type ;
GWin32RegistryValueType default_type ;
2019-01-07 11:25:46 +01:00
gunichar2 * default_value = NULL ;
2014-08-29 10:53:35 +02:00
gunichar2 * client_name ;
gsize client_name_len ;
if ( ! g_win32_registry_subkey_iter_get_name_w ( & clients_iter ,
& client_type_name ,
& client_type_name_len ,
NULL ) )
continue ;
system_client_type = g_win32_registry_key_get_child_w ( clients ,
client_type_name ,
NULL ) ;
if ( system_client_type = = NULL )
continue ;
if ( g_win32_registry_key_get_value_w ( system_client_type ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& default_type ,
( gpointer * ) & default_value ,
NULL ,
NULL ) )
{
if ( default_type ! = G_WIN32_REGISTRY_VALUE_STR | |
default_value [ 0 ] = = L ' \0 ' )
g_clear_pointer ( & default_value , g_free ) ;
}
if ( ! g_win32_registry_subkey_iter_init ( & subkey_iter ,
system_client_type ,
NULL ) )
{
g_clear_pointer ( & default_value , g_free ) ;
g_object_unref ( system_client_type ) ;
continue ;
}
while ( g_win32_registry_subkey_iter_next ( & subkey_iter , TRUE , NULL ) )
{
GWin32RegistryKey * system_client ;
GWin32RegistryKey * system_client_assoc ;
gboolean add ;
gunichar2 * keyname ;
if ( ! g_win32_registry_subkey_iter_get_name_w ( & subkey_iter ,
& client_name ,
& client_name_len ,
NULL ) )
continue ;
system_client = g_win32_registry_key_get_child_w ( system_client_type ,
client_name ,
NULL ) ;
if ( system_client = = NULL )
continue ;
add = FALSE ;
system_client_assoc = g_win32_registry_key_get_child_w ( system_client ,
L " Capabilities \\ FileAssociations " ,
NULL ) ;
if ( system_client_assoc ! = NULL )
{
add = TRUE ;
g_object_unref ( system_client_assoc ) ;
}
else
{
system_client_assoc = g_win32_registry_key_get_child_w ( system_client ,
L " Capabilities \\ UrlAssociations " ,
NULL ) ;
if ( system_client_assoc ! = NULL )
{
add = TRUE ;
g_object_unref ( system_client_assoc ) ;
}
}
if ( add )
{
keyname = g_wcsdup ( g_win32_registry_key_get_path_w ( system_client ) , - 1 ) ;
if ( default_value & & wcscmp ( default_value , client_name ) = = 0 )
g_ptr_array_add ( priority_capable_apps , keyname ) ;
else
g_ptr_array_add ( capable_apps , keyname ) ;
}
g_object_unref ( system_client ) ;
}
g_win32_registry_subkey_iter_clear ( & subkey_iter ) ;
g_clear_pointer ( & default_value , g_free ) ;
g_object_unref ( system_client_type ) ;
}
g_win32_registry_subkey_iter_clear ( & clients_iter ) ;
g_object_unref ( clients ) ;
}
static void
collect_capable_apps_from_registered_apps ( GPtrArray * capable_apps ,
gboolean user_registry )
{
GWin32RegistryValueIter iter ;
gunichar2 * value_data ;
gsize value_data_size ;
GWin32RegistryValueType value_type ;
GWin32RegistryKey * registered_apps ;
if ( user_registry )
registered_apps =
g_win32_registry_key_new_w ( L " HKEY_CURRENT_USER \\ Software \\ RegisteredApplications " ,
NULL ) ;
else
registered_apps =
g_win32_registry_key_new_w ( L " HKEY_LOCAL_MACHINE \\ Software \\ RegisteredApplications " ,
NULL ) ;
if ( ! registered_apps )
return ;
if ( ! g_win32_registry_value_iter_init ( & iter , registered_apps , NULL ) )
{
g_object_unref ( registered_apps ) ;
return ;
}
while ( g_win32_registry_value_iter_next ( & iter , TRUE , NULL ) )
{
gunichar2 possible_location [ REG_PATH_MAX_SIZE + 1 ] ;
GWin32RegistryKey * location = NULL ;
if ( ( ! g_win32_registry_value_iter_get_value_type ( & iter ,
& value_type ,
NULL ) ) | |
( value_type ! = G_WIN32_REGISTRY_VALUE_STR ) | |
( ! g_win32_registry_value_iter_get_data_w ( & iter , TRUE ,
( void * * ) & value_data ,
& value_data_size ,
NULL ) ) | |
( value_data_size < sizeof ( gunichar2 ) ) | |
( value_data [ 0 ] = = L ' \0 ' ) )
continue ;
if ( build_registry_path ( possible_location , sizeof ( possible_location ) ,
HKCU , value_data , NULL ) )
location = g_win32_registry_key_new_w ( possible_location , NULL ) ;
if ( location )
{
gunichar2 * p = wcsrchr ( possible_location , L ' \\ ' ) ;
if ( p )
* p = L ' \0 ' ;
g_ptr_array_add ( capable_apps , g_wcsdup ( possible_location , - 1 ) ) ;
g_object_unref ( location ) ;
continue ;
}
if ( ! build_registry_path ( possible_location , sizeof ( possible_location ) ,
user_registry ? HKCU : HKLM , value_data , NULL ) )
continue ;
location = g_win32_registry_key_new_w ( possible_location , NULL ) ;
if ( location )
{
gunichar2 * p = wcsrchr ( possible_location , L ' \\ ' ) ;
if ( p )
* p = L ' \0 ' ;
g_ptr_array_add ( capable_apps , g_wcsdup ( possible_location , - 1 ) ) ;
g_object_unref ( location ) ;
}
}
g_win32_registry_value_iter_clear ( & iter ) ;
g_object_unref ( registered_apps ) ;
}
static void
read_capable_app ( gunichar2 * input_app_key_path , gboolean user_specific , gboolean default_app )
{
GWin32AppInfoApplication * app ;
gunichar2 * app_key_path ;
gunichar2 * canonical_name ;
gchar * canonical_name_u8 ;
gchar * canonical_name_folded ;
GWin32RegistryKey * appkey ;
gunichar2 * fallback_friendly_name ;
GWin32RegistryValueType vtype ;
gboolean success ;
gunichar2 * friendly_name ;
gunichar2 * description ;
gunichar2 * narrow_application_name ;
gunichar2 * icon_source ;
GWin32RegistryKey * capabilities ;
GWin32RegistryKey * default_icon_key ;
GWin32RegistryKey * shell_open_command_key ;
gunichar2 * shell_open_command ;
gchar * app_executable ;
gchar * app_executable_basename ;
gchar * app_executable_folded ;
gchar * app_executable_folded_basename ;
2019-11-29 17:48:32 +01:00
gchar * app_dll_function ;
2014-08-29 10:53:35 +02:00
GWin32RegistryKey * associations ;
app_key_path = g_wcsdup ( input_app_key_path , - 1 ) ;
canonical_name = wcsrchr ( app_key_path , L ' \\ ' ) ;
if ( canonical_name = = NULL )
{
/* The key must have at least one '\\' */
g_free ( app_key_path ) ;
return ;
}
canonical_name + = 1 ;
2019-11-29 17:48:32 +01:00
if ( ! g_utf16_to_utf8_and_fold ( canonical_name , - 1 , & canonical_name_u8 , & canonical_name_folded ) )
2014-08-29 10:53:35 +02:00
{
g_free ( app_key_path ) ;
return ;
}
appkey = g_win32_registry_key_new_w ( app_key_path , NULL ) ;
if ( appkey = = NULL )
{
g_free ( canonical_name_u8 ) ;
g_free ( canonical_name_folded ) ;
g_free ( app_key_path ) ;
return ;
}
capabilities =
g_win32_registry_key_get_child_w ( appkey , L " Capabilities " , NULL ) ;
if ( capabilities = = NULL )
{
/* Must have capabilities */
g_free ( canonical_name_u8 ) ;
g_free ( canonical_name_folded ) ;
g_free ( app_key_path ) ;
return ;
}
shell_open_command_key =
g_win32_registry_key_get_child_w ( appkey ,
L " shell \\ open \\ command " ,
NULL ) ;
if ( shell_open_command_key = = NULL )
{
g_object_unref ( capabilities ) ;
g_free ( canonical_name_u8 ) ;
g_free ( canonical_name_folded ) ;
g_free ( app_key_path ) ;
g_object_unref ( appkey ) ;
return ;
}
shell_open_command = NULL ;
success = g_win32_registry_key_get_value_w ( shell_open_command_key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& vtype ,
( gpointer * ) & shell_open_command ,
NULL ,
NULL ) ;
2019-11-29 17:48:32 +01:00
if ( success & &
( vtype ! = G_WIN32_REGISTRY_VALUE_STR | |
! g_utf16_validate ( shell_open_command , - 1 ) ) )
2014-08-29 10:53:35 +02:00
{
/* Must have a command */
g_clear_pointer ( & shell_open_command , g_free ) ;
g_object_unref ( capabilities ) ;
g_free ( canonical_name_u8 ) ;
g_free ( canonical_name_folded ) ;
g_free ( app_key_path ) ;
g_object_unref ( appkey ) ;
return ;
}
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( shell_open_command ,
& app_executable ,
& app_executable_basename ,
& app_executable_folded ,
& app_executable_folded_basename ,
& app_dll_function ) ;
if ( app_dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( shell_open_command ) ;
2014-08-29 10:53:35 +02:00
app = g_hash_table_lookup ( apps_by_id , canonical_name_folded ) ;
if ( app = = NULL )
{
app = g_object_new ( G_TYPE_WIN32_APPINFO_APPLICATION , NULL ) ;
app - > canonical_name = g_wcsdup ( canonical_name , - 1 ) ;
app - > canonical_name_u8 = g_strdup ( canonical_name_u8 ) ;
app - > canonical_name_folded =
g_strdup ( canonical_name_folded ) ;
app - > command = g_wcsdup ( shell_open_command , - 1 ) ;
app - > command_u8 =
g_utf16_to_utf8 ( shell_open_command , - 1 , NULL , NULL , NULL ) ;
app - > executable = g_strdup ( app_executable ) ;
app - > executable_basename =
& app - > executable [ app_executable_basename - app_executable ] ;
app - > executable_folded =
g_strdup ( app_executable_folded ) ;
app - > no_open_with = FALSE ;
app - > user_specific = user_specific ;
app - > default_app = default_app ;
2019-11-29 17:48:32 +01:00
app - > dll_function = g_strdup ( app_dll_function ) ;
2014-08-29 10:53:35 +02:00
g_hash_table_insert ( apps_by_id ,
g_strdup ( canonical_name_folded ) ,
app ) ;
}
fallback_friendly_name = NULL ;
success = g_win32_registry_key_get_value_w ( appkey ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& vtype ,
( void * * ) & fallback_friendly_name ,
NULL ,
NULL ) ;
if ( success & & vtype ! = G_WIN32_REGISTRY_VALUE_STR )
g_clear_pointer ( & fallback_friendly_name , g_free ) ;
if ( fallback_friendly_name & & app - > pretty_name = = NULL )
{
app - > pretty_name = g_wcsdup ( fallback_friendly_name , - 1 ) ;
g_clear_pointer ( & app - > pretty_name_u8 , g_free ) ;
app - > pretty_name_u8 = g_utf16_to_utf8 ( fallback_friendly_name ,
- 1 ,
NULL ,
NULL ,
NULL ) ;
}
friendly_name = NULL ;
success = g_win32_registry_key_get_value_w ( capabilities ,
2020-01-27 00:42:31 +01:00
g_win32_registry_get_os_dirs_w ( ) ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " LocalizedString " ,
& vtype ,
( void * * ) & friendly_name ,
NULL ,
NULL ) ;
2020-01-27 00:42:31 +01:00
if ( success & & vtype ! = G_WIN32_REGISTRY_VALUE_STR )
2014-08-29 10:53:35 +02:00
g_clear_pointer ( & friendly_name , g_free ) ;
if ( friendly_name & & app - > localized_pretty_name = = NULL )
{
app - > localized_pretty_name = g_wcsdup ( friendly_name , - 1 ) ;
g_clear_pointer ( & app - > localized_pretty_name_u8 , g_free ) ;
app - > localized_pretty_name_u8 = g_utf16_to_utf8 ( friendly_name ,
- 1 ,
NULL ,
NULL ,
NULL ) ;
}
description = NULL ;
success = g_win32_registry_key_get_value_w ( capabilities ,
2020-01-27 00:42:31 +01:00
g_win32_registry_get_os_dirs_w ( ) ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " ApplicationDescription " ,
& vtype ,
( void * * ) & description ,
NULL ,
NULL ) ;
if ( success & & vtype ! = G_WIN32_REGISTRY_VALUE_STR )
g_clear_pointer ( & description , g_free ) ;
if ( description & & app - > description = = NULL )
{
app - > description = g_wcsdup ( description , - 1 ) ;
g_clear_pointer ( & app - > description_u8 , g_free ) ;
app - > description_u8 = g_utf16_to_utf8 ( description , - 1 , NULL , NULL , NULL ) ;
}
default_icon_key = g_win32_registry_key_get_child_w ( appkey ,
L " DefaultIcon " ,
NULL ) ;
icon_source = NULL ;
if ( default_icon_key ! = NULL )
{
success = g_win32_registry_key_get_value_w ( default_icon_key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& vtype ,
( void * * ) & icon_source ,
NULL ,
NULL ) ;
if ( success & & vtype ! = G_WIN32_REGISTRY_VALUE_STR )
g_clear_pointer ( & icon_source , g_free ) ;
g_object_unref ( default_icon_key ) ;
}
if ( icon_source = = NULL )
{
success = g_win32_registry_key_get_value_w ( capabilities ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " ApplicationIcon " ,
& vtype ,
( void * * ) & icon_source ,
NULL ,
NULL ) ;
if ( success & & vtype ! = G_WIN32_REGISTRY_VALUE_STR )
g_clear_pointer ( & icon_source , g_free ) ;
}
if ( icon_source & & app - > icon = = NULL )
{
gchar * name = g_utf16_to_utf8 ( icon_source , - 1 , NULL , NULL , NULL ) ;
app - > icon = g_themed_icon_new ( name ) ;
g_free ( name ) ;
}
narrow_application_name = NULL ;
success = g_win32_registry_key_get_value_w ( capabilities ,
2020-01-27 00:42:31 +01:00
g_win32_registry_get_os_dirs_w ( ) ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " ApplicationName " ,
& vtype ,
( void * * ) & narrow_application_name ,
NULL ,
NULL ) ;
if ( success & & vtype ! = G_WIN32_REGISTRY_VALUE_STR )
g_clear_pointer ( & narrow_application_name , g_free ) ;
/* 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
* " Thunderbird (news) " when registering it as a news client .
* Maybe we should consider applications with different narrow names as
* different applications altogether ?
*/
associations = g_win32_registry_key_get_child_w ( capabilities ,
L " FileAssociations " ,
NULL ) ;
if ( associations ! = NULL )
{
GWin32RegistryValueIter iter ;
if ( g_win32_registry_value_iter_init ( & iter , associations , NULL ) )
{
gunichar2 * file_extension ;
gunichar2 * extension_handler ;
gsize file_extension_len ;
gsize extension_handler_size ;
GWin32RegistryValueType value_type ;
while ( g_win32_registry_value_iter_next ( & iter , TRUE , NULL ) )
{
GWin32AppInfoHandler * handler_rec ;
GWin32AppInfoHandler * handler_rec_in_ext ;
GWin32AppInfoFileExtension * ext ;
gunichar2 * program_command ;
gunichar2 * proxy_id ;
gunichar2 * proxy_command ;
GWin32RegistryKey * program_key ;
GWin32RegistryKey * proxy_key ;
gchar * program_id_u8 ;
gchar * program_id_folded ;
gchar * file_extension_u8 ;
gchar * file_extension_folded ;
if ( ( ! g_win32_registry_value_iter_get_value_type ( & iter ,
& value_type ,
NULL ) ) | |
( value_type ! = G_WIN32_REGISTRY_VALUE_STR ) | |
( ! g_win32_registry_value_iter_get_name_w ( & iter ,
& file_extension ,
& file_extension_len ,
NULL ) ) | |
( file_extension_len < = 0 ) | |
( file_extension [ 0 ] ! = L ' . ' ) | |
( ! g_win32_registry_value_iter_get_data_w ( & iter , TRUE ,
( void * * ) & extension_handler ,
& extension_handler_size ,
NULL ) ) | |
( extension_handler_size < sizeof ( gunichar2 ) ) | |
( extension_handler [ 0 ] = = L ' \0 ' ) )
continue ;
if ( ! follow_class_chain_to_handler ( extension_handler ,
extension_handler_size ,
& program_command ,
& program_key ,
& proxy_id ,
& proxy_command ,
& proxy_key ,
& program_id_u8 ,
& program_id_folded ) )
continue ;
handler_rec = g_hash_table_lookup ( handlers ,
program_id_folded ) ;
if ( handler_rec = = NULL )
{
handler_rec = g_object_new ( G_TYPE_WIN32_APPINFO_HANDLER , NULL ) ;
handler_rec - > proxy_key = proxy_key ;
handler_rec - > key = program_key ;
handler_rec - > handler_id =
g_wcsdup ( extension_handler , extension_handler_size ) ;
handler_rec - > handler_id_folded =
g_strdup ( program_id_folded ) ;
handler_rec - > handler_command =
program_command ? g_wcsdup ( program_command , - 1 ) : NULL ;
handler_rec - > proxy_id =
proxy_id ? g_wcsdup ( proxy_id , - 1 ) : NULL ;
handler_rec - > proxy_command =
proxy_command ? g_wcsdup ( proxy_command , - 1 ) : NULL ;
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( proxy_command ? proxy_command : program_command ,
& handler_rec - > executable ,
& handler_rec - > executable_basename ,
& handler_rec - > executable_folded ,
NULL ,
& handler_rec - > dll_function ) ;
if ( handler_rec - > dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( handler_rec - > handler_command ? handler_rec - > handler_command : handler_rec - > proxy_command ) ;
2014-08-29 10:53:35 +02:00
read_handler_icon ( proxy_key ,
program_key ,
& handler_rec - > icon ) ;
g_hash_table_insert ( handlers ,
g_strdup ( program_id_folded ) ,
handler_rec ) ;
}
else
{
g_clear_object ( & program_key ) ;
g_clear_object ( & proxy_key ) ;
}
2019-11-29 17:48:32 +01:00
if ( g_utf16_to_utf8_and_fold ( file_extension ,
- 1 ,
& file_extension_u8 ,
& file_extension_folded ) )
2014-08-29 10:53:35 +02:00
{
ext = g_hash_table_lookup ( extensions ,
file_extension_folded ) ;
if ( ext = = NULL )
{
ext = g_object_new ( G_TYPE_WIN32_APPINFO_FILE_EXTENSION , NULL ) ;
ext - > extension = g_wcsdup ( file_extension , - 1 ) ;
ext - > extension_u8 = g_strdup ( file_extension_u8 ) ;
g_hash_table_insert ( extensions , g_strdup ( file_extension_folded ) , ext ) ;
}
handler_rec_in_ext =
g_hash_table_lookup ( ext - > handlers ,
program_id_folded ) ;
if ( handler_rec_in_ext = = NULL )
{
if ( ext - > chosen_handler = = NULL )
g_hash_table_insert ( ext - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
else if ( ext - > chosen_handler - > handler_id_folded & &
strcmp ( ext - > chosen_handler - > handler_id_folded ,
program_id_folded ) ! = 0 )
g_hash_table_insert ( ext - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
}
handler_rec_in_ext =
g_hash_table_lookup ( app - > supported_exts ,
file_extension_folded ) ;
if ( handler_rec_in_ext = = NULL )
g_hash_table_insert ( app - > supported_exts ,
g_strdup ( file_extension_folded ) ,
g_object_ref ( handler_rec ) ) ;
g_free ( file_extension_u8 ) ;
g_free ( file_extension_folded ) ;
}
g_free ( program_id_u8 ) ;
g_free ( program_id_folded ) ;
g_free ( program_command ) ;
g_free ( proxy_id ) ;
g_free ( proxy_command ) ;
}
g_win32_registry_value_iter_clear ( & iter ) ;
}
g_object_unref ( associations ) ;
}
associations = g_win32_registry_key_get_child_w ( capabilities , L " URLAssociations " , NULL ) ;
if ( associations ! = NULL )
{
GWin32RegistryValueIter iter ;
if ( g_win32_registry_value_iter_init ( & iter , associations , NULL ) )
{
gunichar2 * url_schema ;
gunichar2 * schema_handler ;
gsize url_schema_len ;
gsize schema_handler_size ;
GWin32RegistryValueType value_type ;
while ( g_win32_registry_value_iter_next ( & iter , TRUE , NULL ) )
{
GWin32AppInfoHandler * handler_rec ;
GWin32AppInfoHandler * handler_rec_in_url ;
GWin32AppInfoURLSchema * schema ;
gunichar2 * program_command ;
gunichar2 * proxy_id ;
gunichar2 * proxy_command ;
GWin32RegistryKey * program_key ;
GWin32RegistryKey * proxy_key ;
gchar * program_id_u8 ;
gchar * program_id_folded ;
gchar * schema_u8 ;
gchar * schema_folded ;
if ( ( ! g_win32_registry_value_iter_get_value_type ( & iter ,
& value_type ,
NULL ) ) | |
( ( value_type ! = G_WIN32_REGISTRY_VALUE_STR ) & &
( value_type ! = G_WIN32_REGISTRY_VALUE_EXPAND_STR ) ) | |
( ! g_win32_registry_value_iter_get_name_w ( & iter ,
& url_schema ,
& url_schema_len ,
NULL ) ) | |
( url_schema_len < = 0 ) | |
( url_schema [ 0 ] = = L ' \0 ' ) | |
( ! g_win32_registry_value_iter_get_data_w ( & iter , TRUE ,
( void * * ) & schema_handler ,
& schema_handler_size ,
NULL ) ) | |
( schema_handler_size < sizeof ( gunichar2 ) ) | |
( schema_handler [ 0 ] = = L ' \0 ' ) )
continue ;
if ( ! follow_class_chain_to_handler ( schema_handler ,
schema_handler_size ,
& program_command ,
& program_key ,
& proxy_id ,
& proxy_command ,
& proxy_key ,
& program_id_u8 ,
& program_id_folded ) )
continue ;
handler_rec = g_hash_table_lookup ( handlers , program_id_folded ) ;
if ( handler_rec = = NULL )
{
handler_rec = g_object_new ( G_TYPE_WIN32_APPINFO_HANDLER , NULL ) ;
handler_rec - > proxy_key = proxy_key ;
handler_rec - > key = program_key ;
handler_rec - > handler_id =
g_wcsdup ( schema_handler , schema_handler_size ) ;
handler_rec - > handler_id_folded =
g_strdup ( program_id_folded ) ;
handler_rec - > handler_command = program_command ?
g_wcsdup ( program_command , - 1 ) : NULL ;
handler_rec - > proxy_id =
proxy_id ? g_wcsdup ( proxy_id , - 1 ) : NULL ;
handler_rec - > proxy_command =
proxy_command ? g_wcsdup ( proxy_command , - 1 ) : NULL ;
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( proxy_command ? proxy_command : program_command ,
& handler_rec - > executable ,
& handler_rec - > executable_basename ,
& handler_rec - > executable_folded ,
NULL ,
& handler_rec - > dll_function ) ;
if ( handler_rec - > dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( handler_rec - > handler_command ? handler_rec - > handler_command : handler_rec - > proxy_command ) ;
2014-08-29 10:53:35 +02:00
read_handler_icon ( proxy_key ,
program_key ,
& handler_rec - > icon ) ;
g_hash_table_insert ( handlers ,
g_strdup ( program_id_folded ) ,
handler_rec ) ;
}
else
{
g_clear_object ( & program_key ) ;
g_clear_object ( & proxy_key ) ;
}
2019-11-29 17:48:32 +01:00
if ( g_utf16_to_utf8_and_fold ( url_schema ,
- 1 ,
& schema_u8 ,
& schema_folded ) )
2014-08-29 10:53:35 +02:00
{
schema = g_hash_table_lookup ( urls ,
schema_folded ) ;
if ( schema = = NULL )
{
schema = g_object_new ( G_TYPE_WIN32_APPINFO_URL_SCHEMA , NULL ) ;
schema - > schema = g_wcsdup ( url_schema , - 1 ) ;
schema - > schema_u8 = g_strdup ( schema_u8 ) ;
schema - > schema_folded =
g_strdup ( schema_folded ) ;
g_hash_table_insert ( urls ,
g_strdup ( schema_folded ) ,
schema ) ;
}
handler_rec_in_url =
g_hash_table_lookup ( schema - > handlers ,
program_id_folded ) ;
if ( handler_rec_in_url = = NULL )
g_hash_table_insert ( schema - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
handler_rec_in_url =
g_hash_table_lookup ( app - > supported_urls ,
schema_folded ) ;
if ( handler_rec_in_url = = NULL )
g_hash_table_insert ( app - > supported_urls ,
g_strdup ( schema_folded ) ,
g_object_ref ( handler_rec ) ) ;
g_free ( schema_u8 ) ;
g_free ( schema_folded ) ;
}
g_free ( program_id_u8 ) ;
g_free ( program_id_folded ) ;
g_free ( program_command ) ;
g_free ( proxy_id ) ;
g_free ( proxy_command ) ;
}
g_win32_registry_value_iter_clear ( & iter ) ;
}
g_object_unref ( associations ) ;
}
g_clear_pointer ( & app_executable , g_free ) ;
g_clear_pointer ( & app_executable_folded , g_free ) ;
2019-11-29 17:48:32 +01:00
g_clear_pointer ( & app_dll_function , g_free ) ;
2014-08-29 10:53:35 +02:00
g_clear_pointer ( & fallback_friendly_name , g_free ) ;
g_clear_pointer ( & description , g_free ) ;
g_clear_pointer ( & icon_source , g_free ) ;
g_clear_pointer ( & narrow_application_name , g_free ) ;
g_clear_pointer ( & shell_open_command , g_free ) ;
g_object_unref ( appkey ) ;
g_object_unref ( shell_open_command_key ) ;
g_object_unref ( capabilities ) ;
g_free ( canonical_name_u8 ) ;
g_free ( canonical_name_folded ) ;
g_free ( app_key_path ) ;
}
static void
read_urls ( GWin32RegistryKey * url_associations )
{
GWin32RegistrySubkeyIter url_iter ;
gunichar2 * url_schema ;
gsize url_schema_len ;
if ( url_associations = = NULL )
return ;
if ( ! g_win32_registry_subkey_iter_init ( & url_iter , url_associations , NULL ) )
return ;
while ( g_win32_registry_subkey_iter_next ( & url_iter , TRUE , NULL ) )
{
if ( ! g_win32_registry_subkey_iter_get_name_w ( & url_iter ,
& url_schema ,
& url_schema_len ,
NULL ) )
continue ;
get_url_association ( url_schema ) ;
}
g_win32_registry_subkey_iter_clear ( & url_iter ) ;
}
static void
read_exeapps ( void )
{
GWin32RegistryKey * applications_key ;
GWin32RegistrySubkeyIter app_iter ;
applications_key =
g_win32_registry_key_new_w ( L " HKEY_CLASSES_ROOT \\ Applications " , NULL ) ;
if ( applications_key = = NULL )
return ;
if ( ! g_win32_registry_subkey_iter_init ( & app_iter , applications_key , NULL ) )
{
g_object_unref ( applications_key ) ;
return ;
}
while ( g_win32_registry_subkey_iter_next ( & app_iter , TRUE , NULL ) )
{
2019-11-29 17:48:32 +01:00
gunichar2 * app_exe_basename ;
gsize app_exe_basename_len ;
2014-08-29 10:53:35 +02:00
GWin32RegistryKey * incapable_app ;
gunichar2 * friendly_app_name ;
gboolean success ;
gboolean no_open_with ;
GWin32RegistryValueType vtype ;
GWin32RegistryKey * default_icon_key ;
gunichar2 * icon_source ;
GIcon * icon = NULL ;
gchar * appexe ;
gchar * appexe_basename ;
gchar * appexe_folded ;
gchar * appexe_folded_basename ;
GWin32AppInfoApplication * app ;
GWin32RegistryKey * shell_open_command_key ;
gunichar2 * shell_open_command ;
GWin32RegistryKey * supported_key ;
if ( ! g_win32_registry_subkey_iter_get_name_w ( & app_iter ,
& app_exe_basename ,
& app_exe_basename_len ,
2019-11-29 17:48:32 +01:00
NULL ) | |
! g_utf16_validate ( app_exe_basename , app_exe_basename_len ) )
2014-08-29 10:53:35 +02:00
continue ;
incapable_app =
g_win32_registry_key_get_child_w ( applications_key ,
app_exe_basename ,
NULL ) ;
if ( incapable_app = = NULL )
continue ;
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( app_exe_basename ,
& appexe ,
& appexe_basename ,
& appexe_folded ,
& appexe_folded_basename ,
NULL ) ;
2014-08-29 10:53:35 +02:00
shell_open_command_key =
g_win32_registry_key_get_child_w ( incapable_app ,
L " shell \\ open \\ command " ,
NULL ) ;
shell_open_command = NULL ;
if ( shell_open_command_key ! = NULL )
{
success = g_win32_registry_key_get_value_w ( shell_open_command_key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& vtype ,
( gpointer * ) & shell_open_command ,
NULL ,
NULL ) ;
2019-11-29 17:48:32 +01:00
if ( success & &
( vtype ! = G_WIN32_REGISTRY_VALUE_STR | |
! g_utf16_validate ( shell_open_command , - 1 ) ) )
2014-08-29 10:53:35 +02:00
{
g_clear_pointer ( & shell_open_command , g_free ) ;
}
g_object_unref ( shell_open_command_key ) ;
}
friendly_app_name = NULL ;
success = g_win32_registry_key_get_value_w ( incapable_app ,
2020-01-27 00:42:31 +01:00
g_win32_registry_get_os_dirs_w ( ) ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " FriendlyAppName " ,
& vtype ,
( void * * ) & friendly_app_name ,
NULL ,
NULL ) ;
if ( success & & vtype ! = G_WIN32_REGISTRY_VALUE_STR )
g_clear_pointer ( & friendly_app_name , g_free ) ;
no_open_with = FALSE ;
success = g_win32_registry_key_get_value_w ( incapable_app ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " NoOpenWith " ,
& vtype ,
NULL ,
NULL ,
NULL ) ;
if ( success )
no_open_with = TRUE ;
default_icon_key =
g_win32_registry_key_get_child_w ( incapable_app ,
L " DefaultIcon " ,
NULL ) ;
icon_source = NULL ;
if ( default_icon_key ! = NULL )
{
success =
g_win32_registry_key_get_value_w ( default_icon_key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " " ,
& vtype ,
( void * * ) & icon_source ,
NULL ,
NULL ) ;
if ( success & & vtype ! = G_WIN32_REGISTRY_VALUE_STR )
g_clear_pointer ( & icon_source , g_free ) ;
g_object_unref ( default_icon_key ) ;
}
if ( icon_source )
{
gchar * name = g_utf16_to_utf8 ( icon_source , - 1 , NULL , NULL , NULL ) ;
icon = g_themed_icon_new ( name ) ;
g_free ( name ) ;
}
app = g_hash_table_lookup ( apps_by_exe , appexe_folded_basename ) ;
if ( app = = NULL )
{
app = g_object_new ( G_TYPE_WIN32_APPINFO_APPLICATION , NULL ) ;
2019-11-29 17:48:32 +01:00
if ( shell_open_command )
{
gchar * dll_function ;
_g_win32_extract_executable ( shell_open_command ,
NULL ,
NULL ,
NULL ,
NULL ,
& dll_function ) ;
if ( dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( shell_open_command ) ;
g_clear_pointer ( & dll_function , g_free ) ;
}
2014-08-29 10:53:35 +02:00
app - > command =
shell_open_command ? g_wcsdup ( shell_open_command , - 1 ) : NULL ;
if ( shell_open_command )
app - > command_u8 = g_utf16_to_utf8 ( shell_open_command , - 1 , NULL , NULL , NULL ) ;
app - > executable = g_strdup ( appexe ) ;
app - > executable_basename = & app - > executable [ appexe_basename - appexe ] ;
app - > executable_folded = g_strdup ( appexe_folded ) ;
app - > no_open_with = no_open_with ;
if ( friendly_app_name )
{
app - > localized_pretty_name = g_wcsdup ( friendly_app_name , - 1 ) ;
g_clear_pointer ( & app - > localized_pretty_name_u8 , g_free ) ;
app - > localized_pretty_name_u8 =
g_utf16_to_utf8 ( friendly_app_name , - 1 , NULL , NULL , NULL ) ;
}
if ( icon )
app - > icon = g_object_ref ( icon ) ;
app - > user_specific = FALSE ;
app - > default_app = FALSE ;
g_hash_table_insert ( apps_by_exe ,
g_strdup ( appexe_folded_basename ) ,
app ) ;
}
supported_key =
g_win32_registry_key_get_child_w ( incapable_app ,
L " SupportedTypes " ,
NULL ) ;
if ( supported_key )
{
GWin32RegistryValueIter sup_iter ;
if ( g_win32_registry_value_iter_init ( & sup_iter , supported_key , NULL ) )
{
gunichar2 * ext_name ;
gsize ext_name_len ;
while ( g_win32_registry_value_iter_next ( & sup_iter , TRUE , NULL ) )
{
gchar * ext_u8 ;
gchar * ext_folded ;
GWin32AppInfoFileExtension * file_extn ;
gboolean file_ext_known ;
if ( ( ! g_win32_registry_value_iter_get_name_w ( & sup_iter ,
& ext_name ,
& ext_name_len ,
NULL ) ) | |
( ext_name_len < = 0 ) | |
( ext_name [ 0 ] ! = L ' . ' ) | |
2019-11-29 17:48:32 +01:00
( ! g_utf16_to_utf8_and_fold ( ext_name ,
- 1 ,
& ext_u8 ,
& ext_folded ) ) )
2014-08-29 10:53:35 +02:00
continue ;
file_extn = NULL ;
file_ext_known =
g_hash_table_lookup_extended ( extensions ,
ext_folded ,
NULL ,
( void * * ) & file_extn ) ;
if ( ! file_ext_known )
{
file_extn =
g_object_new ( G_TYPE_WIN32_APPINFO_FILE_EXTENSION , NULL ) ;
file_extn - > extension = g_wcsdup ( ext_name , - 1 ) ;
file_extn - > extension_u8 = g_strdup ( ext_u8 ) ;
g_hash_table_insert ( extensions ,
g_strdup ( ext_folded ) ,
file_extn ) ;
}
g_hash_table_insert ( file_extn - > other_apps ,
g_strdup ( appexe_folded ) ,
g_object_ref ( app ) ) ;
g_free ( ext_u8 ) ;
g_free ( ext_folded ) ;
}
g_win32_registry_value_iter_clear ( & sup_iter ) ;
}
g_object_unref ( supported_key ) ;
}
g_free ( appexe ) ;
g_free ( appexe_folded ) ;
g_free ( shell_open_command ) ;
g_free ( friendly_app_name ) ;
g_free ( icon_source ) ;
g_clear_object ( & icon ) ;
g_clear_object ( & incapable_app ) ;
}
g_win32_registry_subkey_iter_clear ( & app_iter ) ;
g_object_unref ( applications_key ) ;
}
static void
read_exts ( GWin32RegistryKey * file_exts )
{
GWin32RegistrySubkeyIter ext_iter ;
gunichar2 * file_extension ;
gsize file_extension_len ;
if ( file_exts = = NULL )
return ;
if ( ! g_win32_registry_subkey_iter_init ( & ext_iter , file_exts , NULL ) )
return ;
while ( g_win32_registry_subkey_iter_next ( & ext_iter , TRUE , NULL ) )
{
if ( ! g_win32_registry_subkey_iter_get_name_w ( & ext_iter ,
& file_extension ,
& file_extension_len ,
NULL ) )
continue ;
get_file_ext ( file_extension ) ;
}
g_win32_registry_subkey_iter_clear ( & ext_iter ) ;
}
static void
read_class_extension ( GWin32RegistryKey * classes_root ,
gunichar2 * class_name ,
gsize class_name_len )
{
gchar * ext_u8 ;
gchar * ext_folded ;
GWin32AppInfoFileExtension * file_extn ;
GWin32AppInfoHandler * handler_rec ;
GWin32AppInfoHandler * handler_rec_in_ext ;
GWin32RegistryKey * class_key ;
gsize program_id_size ;
gunichar2 * program_id ;
gunichar2 * proxy_id ;
GWin32RegistryKey * program_key ;
GWin32RegistryKey * proxy_key ;
gunichar2 * program_command ;
gunichar2 * proxy_command ;
class_key = g_win32_registry_key_get_child_w ( classes_root , class_name , NULL ) ;
if ( class_key = = NULL )
return ;
program_id = class_name ;
program_id_size = ( class_name_len + 1 ) * sizeof ( gunichar2 ) ;
program_key = proxy_key = NULL ;
program_command = proxy_command = NULL ;
if ( ! follow_class_chain_to_handler ( program_id ,
program_id_size ,
& program_command ,
& program_key ,
& proxy_id ,
& proxy_command ,
& proxy_key ,
& ext_u8 ,
& ext_folded ) )
{
g_object_unref ( class_key ) ;
return ;
}
file_extn = g_hash_table_lookup ( extensions , ext_folded ) ;
handler_rec = g_hash_table_lookup ( handlers , ext_folded ) ;
if ( file_extn = = NULL )
{
file_extn = g_object_new ( G_TYPE_WIN32_APPINFO_FILE_EXTENSION , NULL ) ;
file_extn - > extension = g_wcsdup ( class_name , - 1 ) ;
file_extn - > extension_u8 = g_strdup ( ext_u8 ) ;
g_hash_table_insert ( extensions , g_strdup ( ext_folded ) , file_extn ) ;
}
if ( handler_rec = = NULL )
{
handler_rec = g_object_new ( G_TYPE_WIN32_APPINFO_HANDLER , NULL ) ;
handler_rec - > proxy_key = proxy_key ;
handler_rec - > key = program_key ;
handler_rec - > handler_id = g_wcsdup ( program_id , program_id_size ) ;
handler_rec - > handler_id_folded = g_strdup ( ext_folded ) ;
handler_rec - > handler_command =
program_command ? g_wcsdup ( program_command , - 1 ) : NULL ;
handler_rec - > proxy_id = proxy_id ? g_wcsdup ( proxy_id , - 1 ) : NULL ;
handler_rec - > proxy_command =
proxy_command ? g_wcsdup ( proxy_command , - 1 ) : NULL ;
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( proxy_command ? proxy_command : program_command ,
& handler_rec - > executable ,
& handler_rec - > executable_basename ,
& handler_rec - > executable_folded ,
NULL ,
& handler_rec - > dll_function ) ;
if ( handler_rec - > dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( handler_rec - > handler_command ? handler_rec - > handler_command : handler_rec - > proxy_command ) ;
2014-08-29 10:53:35 +02:00
read_handler_icon ( proxy_key , program_key , & handler_rec - > icon ) ;
g_hash_table_insert ( handlers ,
g_strdup ( ext_folded ) ,
handler_rec ) ;
}
else
{
g_clear_object ( & program_key ) ;
g_clear_object ( & proxy_key ) ;
}
handler_rec_in_ext = g_hash_table_lookup ( file_extn - > handlers ,
ext_folded ) ;
if ( file_extn - > chosen_handler = = NULL )
g_hash_table_insert ( file_extn - > handlers ,
g_strdup ( ext_folded ) ,
g_object_ref ( handler_rec ) ) ;
else if ( handler_rec_in_ext = = NULL )
{
if ( file_extn - > chosen_handler - > handler_id_folded & &
strcmp ( file_extn - > chosen_handler - > handler_id_folded ,
ext_folded ) ! = 0 )
g_hash_table_insert ( file_extn - > handlers ,
g_strdup ( ext_folded ) ,
g_object_ref ( handler_rec ) ) ;
}
g_free ( program_command ) ;
g_free ( proxy_id ) ;
g_free ( proxy_command ) ;
g_free ( ext_u8 ) ;
g_free ( ext_folded ) ;
g_object_unref ( class_key ) ;
}
static void
read_class_url ( GWin32RegistryKey * classes_root ,
gunichar2 * class_name ,
gsize class_name_len )
{
GWin32RegistryKey * class_key ;
gboolean success ;
GWin32RegistryValueType vtype ;
GWin32AppInfoURLSchema * schema_rec ;
GWin32AppInfoHandler * handler_rec ;
GWin32AppInfoHandler * handler_rec_in_url ;
gunichar2 * program_id ;
gsize program_id_size ;
gunichar2 * program_command ;
gunichar2 * proxy_id ;
gunichar2 * proxy_command ;
gchar * program_id_u8 ;
gchar * program_id_folded ;
GWin32RegistryKey * program_key ;
GWin32RegistryKey * proxy_key ;
class_key = g_win32_registry_key_get_child_w ( classes_root , class_name , NULL ) ;
if ( class_key = = NULL )
return ;
success = g_win32_registry_key_get_value_w ( class_key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " URL Protocol " ,
& vtype ,
NULL ,
NULL ,
NULL ) ;
if ( ! success | |
vtype ! = G_WIN32_REGISTRY_VALUE_STR )
{
g_object_unref ( class_key ) ;
return ;
}
program_id = class_name ;
program_id_size = ( class_name_len + 1 ) * sizeof ( gunichar2 ) ;
proxy_key = program_key = NULL ;
program_command = proxy_id = proxy_command = NULL ;
if ( ! follow_class_chain_to_handler ( program_id ,
program_id_size ,
& program_command ,
& program_key ,
& proxy_id ,
& proxy_command ,
& proxy_key ,
& program_id_u8 ,
& program_id_folded ) )
{
g_object_unref ( class_key ) ;
return ;
}
schema_rec = g_hash_table_lookup ( urls , program_id_folded ) ;
handler_rec = g_hash_table_lookup ( handlers , program_id_folded ) ;
if ( handler_rec = = NULL )
{
handler_rec = g_object_new ( G_TYPE_WIN32_APPINFO_HANDLER , NULL ) ;
handler_rec - > proxy_key = proxy_key ;
handler_rec - > key = program_key ;
handler_rec - > handler_id = g_wcsdup ( program_id , program_id_size ) ;
handler_rec - > handler_id_folded =
g_strdup ( program_id_folded ) ;
handler_rec - > handler_command =
program_command ? g_wcsdup ( program_command , - 1 ) : NULL ;
handler_rec - > proxy_id = proxy_id ? g_wcsdup ( proxy_id , - 1 ) : NULL ;
handler_rec - > proxy_command =
proxy_command ? g_wcsdup ( proxy_command , - 1 ) : NULL ;
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( proxy_command ? proxy_command : program_command ,
& handler_rec - > executable ,
& handler_rec - > executable_basename ,
& handler_rec - > executable_folded ,
NULL ,
& handler_rec - > dll_function ) ;
if ( handler_rec - > dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( handler_rec - > handler_command ? handler_rec - > handler_command : handler_rec - > proxy_command ) ;
2014-08-29 10:53:35 +02:00
read_handler_icon ( proxy_key , program_key , & handler_rec - > icon ) ;
g_hash_table_insert ( handlers ,
g_strdup ( program_id_folded ) ,
handler_rec ) ;
}
else
{
g_clear_object ( & program_key ) ;
g_clear_object ( & proxy_key ) ;
}
if ( schema_rec = = NULL )
{
schema_rec = g_object_new ( G_TYPE_WIN32_APPINFO_URL_SCHEMA , NULL ) ;
schema_rec - > schema = g_wcsdup ( class_name , - 1 ) ;
schema_rec - > schema_u8 = g_strdup ( program_id_u8 ) ;
schema_rec - > schema_folded = g_strdup ( program_id_folded ) ;
schema_rec - > chosen_handler = g_object_ref ( handler_rec ) ;
g_hash_table_insert ( urls ,
g_strdup ( program_id_folded ) ,
schema_rec ) ;
}
if ( schema_rec - > chosen_handler = = NULL )
schema_rec - > chosen_handler = g_object_ref ( handler_rec ) ;
handler_rec_in_url = g_hash_table_lookup ( schema_rec - > handlers ,
program_id_folded ) ;
if ( handler_rec_in_url = = NULL & & schema_rec - > chosen_handler ! = handler_rec )
g_hash_table_insert ( schema_rec - > handlers ,
g_strdup ( program_id_folded ) ,
g_object_ref ( handler_rec ) ) ;
g_free ( program_id_u8 ) ;
g_free ( program_id_folded ) ;
g_free ( program_command ) ;
g_free ( proxy_id ) ;
g_free ( proxy_command ) ;
g_object_unref ( class_key ) ;
}
static void
read_classes ( GWin32RegistryKey * classes_root )
{
GWin32RegistrySubkeyIter class_iter ;
gunichar2 * class_name ;
gsize class_name_len ;
if ( classes_root = = NULL )
return ;
if ( ! g_win32_registry_subkey_iter_init ( & class_iter , classes_root , NULL ) )
return ;
while ( g_win32_registry_subkey_iter_next ( & class_iter , TRUE , NULL ) )
{
if ( ( ! g_win32_registry_subkey_iter_get_name_w ( & class_iter ,
& class_name ,
& class_name_len ,
NULL ) ) | |
( class_name_len < = 1 ) )
continue ;
if ( class_name [ 0 ] = = L ' . ' )
read_class_extension ( classes_root , class_name , class_name_len ) ;
else
{
gsize i ;
for ( i = 0 ; i < class_name_len ; i + + )
if ( ! iswalpha ( class_name [ i ] ) )
break ;
if ( i = = class_name_len )
read_class_url ( classes_root , class_name , class_name_len ) ;
}
}
g_win32_registry_subkey_iter_clear ( & class_iter ) ;
}
static void
link_chosen_handlers ( void )
{
GHashTableIter iter ;
GHashTableIter handler_iter ;
gchar * schema_folded ;
GWin32AppInfoURLSchema * schema ;
gchar * handler_id_folded ;
GWin32AppInfoHandler * handler ;
gchar * ext_folded ;
GWin32AppInfoFileExtension * ext ;
g_hash_table_iter_init ( & iter , urls ) ;
while ( g_hash_table_iter_next ( & iter ,
( gpointer * ) & schema_folded ,
( gpointer * ) & schema ) )
{
if ( schema - > chosen_handler ! = NULL )
continue ;
g_hash_table_iter_init ( & handler_iter , schema - > handlers ) ;
while ( g_hash_table_iter_next ( & handler_iter ,
( gpointer * ) & handler_id_folded ,
( gpointer * ) & handler ) )
{
gchar * proxy_id_folded ;
if ( schema - > chosen_handler ! = NULL )
break ;
if ( strcmp ( handler_id_folded , schema_folded ) ! = 0 )
continue ;
if ( handler - > proxy_command & &
handler - > proxy_id & &
2019-11-29 17:48:32 +01:00
g_utf16_to_utf8_and_fold ( handler - > proxy_id ,
- 1 ,
NULL ,
& proxy_id_folded ) )
2014-08-29 10:53:35 +02:00
{
GWin32AppInfoHandler * proxy ;
proxy = g_hash_table_lookup ( handlers , proxy_id_folded ) ;
if ( proxy )
{
schema - > chosen_handler = g_object_ref ( proxy ) ;
g_debug ( " Linking schema %s to proxy handler %c ? \" %S \" : %S \n " ,
schema - > schema_u8 ,
schema - > chosen_handler - > proxy_id ? ' P ' : ' T ' ,
schema - > chosen_handler - > proxy_id ? schema - > chosen_handler - > proxy_id : schema - > chosen_handler - > handler_id ,
schema - > chosen_handler - > proxy_command ? schema - > chosen_handler - > proxy_command : schema - > chosen_handler - > handler_command ) ;
}
g_free ( proxy_id_folded ) ;
}
if ( schema - > chosen_handler = = NULL )
{
schema - > chosen_handler = g_object_ref ( handler ) ;
g_debug ( " Linking schema %s to handler %c ? \" %S \" : %S \n " ,
schema - > schema_u8 ,
schema - > chosen_handler - > proxy_id ? ' P ' : ' T ' ,
schema - > chosen_handler - > proxy_id ? schema - > chosen_handler - > proxy_id : schema - > chosen_handler - > handler_id ,
schema - > chosen_handler - > proxy_command ? schema - > chosen_handler - > proxy_command : schema - > chosen_handler - > handler_command ) ;
}
}
}
g_hash_table_iter_init ( & iter , extensions ) ;
while ( g_hash_table_iter_next ( & iter ,
( gpointer * ) & ext_folded ,
( gpointer * ) & ext ) )
{
if ( ext - > chosen_handler ! = NULL )
continue ;
g_hash_table_iter_init ( & handler_iter , ext - > handlers ) ;
while ( g_hash_table_iter_next ( & handler_iter ,
( gpointer * ) & handler_id_folded ,
( gpointer * ) & handler ) )
{
gchar * proxy_id_folded ;
if ( ext - > chosen_handler ! = NULL )
break ;
if ( strcmp ( handler_id_folded , ext_folded ) ! = 0 )
continue ;
if ( handler - > proxy_command & &
handler - > proxy_id & &
2019-11-29 17:48:32 +01:00
g_utf16_to_utf8_and_fold ( handler - > proxy_id ,
- 1 ,
NULL ,
& proxy_id_folded ) )
2014-08-29 10:53:35 +02:00
{
GWin32AppInfoHandler * proxy ;
proxy = g_hash_table_lookup ( handlers , proxy_id_folded ) ;
if ( proxy )
{
ext - > chosen_handler = g_object_ref ( proxy ) ;
g_debug ( " Linking ext %s to proxy handler %c ? \" %S \" : %S \n " ,
ext - > extension_u8 ,
ext - > chosen_handler - > proxy_id ? ' P ' : ' T ' ,
ext - > chosen_handler - > proxy_id ? ext - > chosen_handler - > proxy_id : ext - > chosen_handler - > handler_id ,
ext - > chosen_handler - > proxy_command ? ext - > chosen_handler - > proxy_command : ext - > chosen_handler - > handler_command ) ;
}
g_free ( proxy_id_folded ) ;
}
if ( ext - > chosen_handler = = NULL )
{
ext - > chosen_handler = g_object_ref ( handler ) ;
g_debug ( " Linking ext %s to handler %c ? \" %S \" : %S \n " ,
ext - > extension_u8 ,
ext - > chosen_handler - > proxy_id ? ' P ' : ' T ' ,
ext - > chosen_handler - > proxy_id ? ext - > chosen_handler - > proxy_id : ext - > chosen_handler - > handler_id ,
ext - > chosen_handler - > proxy_command ? ext - > chosen_handler - > proxy_command : ext - > chosen_handler - > handler_command ) ;
}
}
}
}
static void
link_handlers_to_registered_apps ( void )
{
GHashTableIter iter ;
GHashTableIter sup_iter ;
gchar * app_id_folded ;
GWin32AppInfoApplication * app ;
gchar * schema_folded ;
GWin32AppInfoURLSchema * schema ;
gchar * ext_folded ;
GWin32AppInfoFileExtension * ext ;
gsize unhandled_exts ;
g_hash_table_iter_init ( & sup_iter , urls ) ;
while ( g_hash_table_iter_next ( & sup_iter ,
( gpointer * ) & schema_folded ,
( gpointer * ) & schema ) )
{
if ( schema - > chosen_handler = = NULL )
g_debug ( " WARNING: schema %s has no chosen handler \n " , schema - > schema_u8 ) ;
}
unhandled_exts = 0 ;
g_hash_table_iter_init ( & sup_iter , extensions ) ;
while ( g_hash_table_iter_next ( & sup_iter ,
( gpointer * ) & ext_folded ,
( gpointer * ) & ext ) )
{
if ( ext - > chosen_handler = = NULL )
{
g_debug ( " WARNING: extension %s has no chosen handler \n " ,
ext - > extension_u8 ) ;
unhandled_exts + = 1 ;
}
}
g_hash_table_iter_init ( & iter , apps_by_id ) ;
while ( g_hash_table_iter_next ( & iter ,
( gpointer * ) & app_id_folded ,
( gpointer * ) & app ) )
{
if ( app - > supported_urls )
{
GWin32AppInfoHandler * handler ;
g_hash_table_iter_init ( & sup_iter , app - > supported_urls ) ;
while ( g_hash_table_iter_next ( & sup_iter ,
( gpointer * ) & schema_folded ,
( gpointer * ) & handler ) )
{
schema = g_hash_table_lookup ( urls , schema_folded ) ;
g_assert ( schema ! = NULL ) ;
if ( schema - > chosen_handler ! = NULL & &
schema - > chosen_handler - > app = = NULL )
{
schema - > chosen_handler - > app = g_object_ref ( app ) ;
g_debug ( " Linking %S " , app - > canonical_name ) ;
if ( app - > localized_pretty_name )
g_debug ( " '%S' " , app - > localized_pretty_name ) ;
else if ( app - > pretty_name )
g_debug ( " '%S' " , app - > pretty_name ) ;
else
g_debug ( " '%s' " , app - > executable ) ;
if ( app - > command )
g_debug ( " %S " , app - > command ) ;
g_debug ( " \n to schema %s handler %c ? \" %S \" : %S \n " ,
schema - > schema_u8 ,
schema - > chosen_handler - > proxy_id ? ' P ' : ' T ' ,
schema - > chosen_handler - > proxy_id ? schema - > chosen_handler - > proxy_id : schema - > chosen_handler - > handler_id ,
schema - > chosen_handler - > proxy_command ? schema - > chosen_handler - > proxy_command : schema - > chosen_handler - > handler_command ) ;
}
}
g_hash_table_iter_init ( & sup_iter , app - > supported_urls ) ;
while ( g_hash_table_iter_next ( & sup_iter ,
( gpointer * ) & schema_folded ,
( gpointer * ) & handler ) )
{
if ( handler - > app = = NULL )
{
handler - > app = g_object_ref ( app ) ;
g_debug ( " Linking %S " , app - > canonical_name ) ;
if ( app - > localized_pretty_name )
g_debug ( " '%S' " , app - > localized_pretty_name ) ;
else if ( app - > pretty_name )
g_debug ( " '%S' " , app - > pretty_name ) ;
else
g_debug ( " '%s' " , app - > executable ) ;
if ( app - > command )
g_debug ( " %S " , app - > command ) ;
g_debug ( " \n directly to schema handler to %c ? \" %S \" : %S \n " ,
handler - > proxy_id ? ' P ' : ' T ' ,
handler - > proxy_id ? handler - > proxy_id : handler - > handler_id ,
handler - > proxy_command ? handler - > proxy_command : handler - > handler_command ) ;
}
}
}
if ( app - > supported_exts )
{
GWin32AppInfoHandler * handler ;
g_hash_table_iter_init ( & sup_iter , app - > supported_exts ) ;
while ( g_hash_table_iter_next ( & sup_iter ,
( gpointer * ) & ext_folded ,
( gpointer * ) & handler ) )
{
ext = g_hash_table_lookup ( extensions , ext_folded ) ;
g_assert ( ext ! = NULL ) ;
if ( ext - > chosen_handler ! = NULL & &
ext - > chosen_handler - > app = = NULL )
{
ext - > chosen_handler - > app = g_object_ref ( app ) ;
g_debug ( " Linking %S " , app - > canonical_name ) ;
if ( app - > localized_pretty_name )
g_debug ( " '%S' " , app - > localized_pretty_name ) ;
else if ( app - > pretty_name )
g_debug ( " '%S' " , app - > pretty_name ) ;
else
g_debug ( " '%s' " , app - > executable ) ;
if ( app - > command )
g_debug ( " %S " , app - > command ) ;
g_debug ( " \n to ext %s handler %c ? \" %S \" : %S \n " ,
ext - > extension_u8 ,
ext - > chosen_handler - > proxy_id ? ' P ' : ' T ' ,
ext - > chosen_handler - > proxy_id ? ext - > chosen_handler - > proxy_id : ext - > chosen_handler - > handler_id ,
ext - > chosen_handler - > proxy_command ? ext - > chosen_handler - > proxy_command : ext - > chosen_handler - > handler_command ) ;
}
}
g_hash_table_iter_init ( & sup_iter , app - > supported_exts ) ;
while ( g_hash_table_iter_next ( & sup_iter ,
( gpointer * ) & ext_folded ,
( gpointer * ) & handler ) )
{
if ( handler - > app = = NULL )
{
handler - > app = g_object_ref ( app ) ;
g_debug ( " Linking %S " , app - > canonical_name ) ;
if ( app - > localized_pretty_name )
g_debug ( " '%S' " , app - > localized_pretty_name ) ;
else if ( app - > pretty_name )
g_debug ( " '%S' " , app - > pretty_name ) ;
else
g_debug ( " '%s' " , app - > executable ) ;
if ( app - > command )
g_debug ( " %S " , app - > command ) ;
g_debug ( " \n directly to ext handler %c ? \" %S \" : %S \n " ,
handler - > proxy_id ? ' P ' : ' T ' ,
handler - > proxy_id ? handler - > proxy_id : handler - > handler_id ,
handler - > proxy_command ? handler - > proxy_command : handler - > handler_command ) ;
}
}
}
}
2015-09-17 12:38:10 +02:00
g_debug ( " % " G_GSIZE_FORMAT " undefhandled extensions \n " , unhandled_exts ) ;
2014-08-29 10:53:35 +02:00
unhandled_exts = 0 ;
g_hash_table_iter_init ( & sup_iter , extensions ) ;
while ( g_hash_table_iter_next ( & sup_iter ,
( gpointer * ) & ext_folded ,
( gpointer * ) & ext ) )
{
if ( ext - > chosen_handler = = NULL )
{
g_debug ( " WARNING: extension %s has no chosen handler \n " ,
ext - > extension_u8 ) ;
unhandled_exts + = 1 ;
}
}
2015-09-17 12:38:10 +02:00
g_debug ( " % " G_GSIZE_FORMAT " undefhandled extensions \n " , unhandled_exts ) ;
2014-08-29 10:53:35 +02:00
}
static void
link_handlers_to_unregistered_apps ( void )
{
GHashTableIter iter ;
GHashTableIter app_iter ;
GWin32AppInfoHandler * handler ;
gchar * handler_id_fc ;
GWin32AppInfoApplication * app ;
gchar * canonical_name_fc ;
gchar * appexe_fc_basename ;
g_hash_table_iter_init ( & iter , handlers ) ;
while ( g_hash_table_iter_next ( & iter ,
( gpointer * ) & handler_id_fc ,
( gpointer * ) & handler ) )
{
gchar * hndexe_fc_basename ;
if ( ( handler - > app ! = NULL ) | |
( handler - > executable_folded = = NULL ) )
continue ;
g_hash_table_iter_init ( & app_iter , apps_by_id ) ;
while ( g_hash_table_iter_next ( & app_iter ,
( gpointer * ) & canonical_name_fc ,
( gpointer * ) & app ) )
{
if ( app - > executable_folded = = NULL )
continue ;
if ( strcmp ( app - > executable_folded ,
handler - > executable_folded ) ! = 0 )
continue ;
handler - > app = app ;
break ;
}
if ( handler - > app ! = NULL )
continue ;
2019-11-29 17:49:01 +01:00
hndexe_fc_basename = g_utf8_casefold ( handler - > executable_basename , - 1 ) ;
if ( hndexe_fc_basename = = NULL )
continue ;
2014-08-29 10:53:35 +02:00
g_hash_table_iter_init ( & app_iter , apps_by_exe ) ;
while ( ( hndexe_fc_basename ! = NULL ) & &
( g_hash_table_iter_next ( & app_iter ,
( gpointer * ) & appexe_fc_basename ,
( gpointer * ) & app ) ) )
{
/* Use basename because apps_by_exe only has basenames */
if ( strcmp ( hndexe_fc_basename , appexe_fc_basename ) ! = 0 )
continue ;
handler - > app = app ;
break ;
}
g_free ( hndexe_fc_basename ) ;
if ( handler - > app = = NULL )
g_debug ( " WARNING: handler that runs %s has no corresponding app \n " ,
handler - > executable ) ;
}
}
static void
update_registry_data ( void )
{
guint i ;
GPtrArray * capable_apps_keys ;
GPtrArray * user_capable_apps_keys ;
GPtrArray * priority_capable_apps_keys ;
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 ;
url_associations =
g_win32_registry_key_new_w ( L " HKEY_CURRENT_USER \\ Software \\ Microsoft \\ Windows \\ Shell \\ Associations \\ UrlAssociations " ,
NULL ) ;
file_exts =
g_win32_registry_key_new_w ( L " HKEY_CURRENT_USER \\ Software \\ Microsoft \\ Windows \\ CurrentVersion \\ Explorer \\ FileExts " ,
NULL ) ;
classes_root = g_win32_registry_key_new_w ( L " HKEY_CLASSES_ROOT " , NULL ) ;
capable_apps_keys = g_ptr_array_new_with_free_func ( g_free ) ;
user_capable_apps_keys = g_ptr_array_new_with_free_func ( g_free ) ;
priority_capable_apps_keys = g_ptr_array_new_with_free_func ( g_free ) ;
g_clear_pointer ( & apps_by_id , g_hash_table_destroy ) ;
g_clear_pointer ( & apps_by_exe , g_hash_table_destroy ) ;
g_clear_pointer ( & urls , g_hash_table_destroy ) ;
g_clear_pointer ( & extensions , g_hash_table_destroy ) ;
g_clear_pointer ( & handlers , g_hash_table_destroy ) ;
collect_start = GetTickCount ( ) ;
collect_capable_apps_from_clients ( capable_apps_keys ,
priority_capable_apps_keys ,
FALSE ) ;
collect_capable_apps_from_clients ( user_capable_apps_keys ,
priority_capable_apps_keys ,
TRUE ) ;
collect_capable_apps_from_registered_apps ( user_capable_apps_keys ,
TRUE ) ;
collect_capable_apps_from_registered_apps ( capable_apps_keys ,
FALSE ) ;
collect_end = GetTickCount ( ) ;
apps_by_id =
g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_object_unref ) ;
apps_by_exe =
g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_object_unref ) ;
urls =
g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_object_unref ) ;
extensions =
g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_object_unref ) ;
handlers =
g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_object_unref ) ;
alloc_end = GetTickCount ( ) ;
for ( i = 0 ; i < priority_capable_apps_keys - > len ; i + + )
read_capable_app ( g_ptr_array_index ( priority_capable_apps_keys , i ) ,
TRUE ,
TRUE ) ;
for ( i = 0 ; i < user_capable_apps_keys - > len ; i + + )
read_capable_app ( g_ptr_array_index ( user_capable_apps_keys , i ) ,
TRUE ,
FALSE ) ;
for ( i = 0 ; i < capable_apps_keys - > len ; i + + )
read_capable_app ( g_ptr_array_index ( capable_apps_keys , i ) ,
FALSE ,
FALSE ) ;
capable_end = GetTickCount ( ) ;
read_urls ( url_associations ) ;
url_end = GetTickCount ( ) ;
read_exts ( file_exts ) ;
ext_end = GetTickCount ( ) ;
read_exeapps ( ) ;
exeapp_end = GetTickCount ( ) ;
read_classes ( classes_root ) ;
classes_end = GetTickCount ( ) ;
link_chosen_handlers ( ) ;
link_handlers_to_registered_apps ( ) ;
link_handlers_to_unregistered_apps ( ) ;
postproc_end = GetTickCount ( ) ;
g_debug ( " Collecting capable appnames: %lums \n "
" Allocating hashtables:...... %lums \n "
" Reading capable apps: %lums \n "
" Reading URL associations:... %lums \n "
" Reading extension assocs: %lums \n "
" Reading exe-only apps:...... %lums \n "
" Reading classes: %lums \n "
" Postprocessing:..............%lums \n "
" TOTAL: %lums \n " ,
collect_end - collect_start ,
alloc_end - collect_end ,
capable_end - alloc_end ,
url_end - capable_end ,
ext_end - url_end ,
exeapp_end - ext_end ,
classes_end - exeapp_end ,
postproc_end - classes_end ,
postproc_end - collect_start ) ;
g_clear_object ( & classes_root ) ;
g_clear_object ( & url_associations ) ;
g_clear_object ( & file_exts ) ;
g_ptr_array_free ( capable_apps_keys , TRUE ) ;
g_ptr_array_free ( user_capable_apps_keys , TRUE ) ;
g_ptr_array_free ( priority_capable_apps_keys , TRUE ) ;
return ;
}
static void
watch_keys ( void )
{
if ( url_associations_key )
g_win32_registry_key_watch ( url_associations_key ,
TRUE ,
G_WIN32_REGISTRY_WATCH_NAME |
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
G_WIN32_REGISTRY_WATCH_VALUES ,
NULL ,
NULL ,
NULL ) ;
if ( file_exts_key )
g_win32_registry_key_watch ( file_exts_key ,
TRUE ,
G_WIN32_REGISTRY_WATCH_NAME |
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
G_WIN32_REGISTRY_WATCH_VALUES ,
NULL ,
NULL ,
NULL ) ;
if ( user_clients_key )
g_win32_registry_key_watch ( user_clients_key ,
TRUE ,
G_WIN32_REGISTRY_WATCH_NAME |
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
G_WIN32_REGISTRY_WATCH_VALUES ,
NULL ,
NULL ,
NULL ) ;
if ( system_clients_key )
g_win32_registry_key_watch ( system_clients_key ,
TRUE ,
G_WIN32_REGISTRY_WATCH_NAME |
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
G_WIN32_REGISTRY_WATCH_VALUES ,
NULL ,
NULL ,
NULL ) ;
if ( applications_key )
g_win32_registry_key_watch ( applications_key ,
TRUE ,
G_WIN32_REGISTRY_WATCH_NAME |
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
G_WIN32_REGISTRY_WATCH_VALUES ,
NULL ,
NULL ,
NULL ) ;
if ( user_registered_apps_key )
g_win32_registry_key_watch ( user_registered_apps_key ,
TRUE ,
G_WIN32_REGISTRY_WATCH_NAME |
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
G_WIN32_REGISTRY_WATCH_VALUES ,
NULL ,
NULL ,
NULL ) ;
if ( system_registered_apps_key )
g_win32_registry_key_watch ( system_registered_apps_key ,
TRUE ,
G_WIN32_REGISTRY_WATCH_NAME |
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
G_WIN32_REGISTRY_WATCH_VALUES ,
NULL ,
NULL ,
NULL ) ;
if ( classes_root_key )
g_win32_registry_key_watch ( classes_root_key ,
FALSE ,
G_WIN32_REGISTRY_WATCH_NAME |
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
G_WIN32_REGISTRY_WATCH_VALUES ,
NULL ,
NULL ,
NULL ) ;
}
static void
g_win32_appinfo_init ( void )
{
2015-08-31 19:48:22 +02:00
static gsize initialized ;
2014-08-29 10:53:35 +02:00
if ( g_once_init_enter ( & initialized ) )
{
url_associations_key =
g_win32_registry_key_new_w ( L " HKEY_CURRENT_USER \\ Software \\ Microsoft \\ Windows \\ Shell \\ Associations \\ UrlAssociations " ,
NULL ) ;
file_exts_key =
g_win32_registry_key_new_w ( L " HKEY_CURRENT_USER \\ Software \\ Microsoft \\ Windows \\ CurrentVersion \\ Explorer \\ FileExts " ,
NULL ) ;
user_clients_key =
g_win32_registry_key_new_w ( L " HKEY_CURRENT_USER \\ Software \\ Clients " ,
NULL ) ;
system_clients_key =
g_win32_registry_key_new_w ( L " HKEY_LOCAL_MACHINE \\ Software \\ Clients " ,
NULL ) ;
applications_key =
g_win32_registry_key_new_w ( L " HKEY_CLASSES_ROOT \\ Applications " ,
NULL ) ;
user_registered_apps_key =
g_win32_registry_key_new_w ( L " HKEY_CURRENT_USER \\ Software \\ RegisteredApplications " ,
NULL ) ;
system_registered_apps_key =
g_win32_registry_key_new_w ( L " HKEY_LOCAL_MACHINE \\ Software \\ RegisteredApplications " ,
NULL ) ;
classes_root_key =
g_win32_registry_key_new_w ( L " HKEY_CLASSES_ROOT " ,
NULL ) ;
watch_keys ( ) ;
update_registry_data ( ) ;
g_once_init_leave ( & initialized , TRUE ) ;
}
if ( ( url_associations_key & & g_win32_registry_key_has_changed ( url_associations_key ) ) | |
( file_exts_key & & g_win32_registry_key_has_changed ( file_exts_key ) ) | |
( user_clients_key & & g_win32_registry_key_has_changed ( user_clients_key ) ) | |
( system_clients_key & & g_win32_registry_key_has_changed ( system_clients_key ) ) | |
( applications_key & & g_win32_registry_key_has_changed ( applications_key ) ) | |
( user_registered_apps_key & & g_win32_registry_key_has_changed ( user_registered_apps_key ) ) | |
( system_registered_apps_key & & g_win32_registry_key_has_changed ( system_registered_apps_key ) ) | |
( classes_root_key & & g_win32_registry_key_has_changed ( classes_root_key ) ) )
{
G_LOCK ( gio_win32_appinfo ) ;
update_registry_data ( ) ;
watch_keys ( ) ;
G_UNLOCK ( gio_win32_appinfo ) ;
}
}
static void g_win32_app_info_iface_init ( GAppInfoIface * iface ) ;
struct _GWin32AppInfo
{
GObject parent_instance ;
/*<private>*/
gchar * * supported_types ;
GWin32AppInfoApplication * app ;
GWin32AppInfoHandler * handler ;
guint startup_notify : 1 ;
} ;
G_DEFINE_TYPE_WITH_CODE ( GWin32AppInfo , g_win32_app_info , G_TYPE_OBJECT ,
G_IMPLEMENT_INTERFACE ( G_TYPE_APP_INFO ,
g_win32_app_info_iface_init ) )
static void
g_win32_app_info_finalize ( GObject * object )
{
GWin32AppInfo * info ;
info = G_WIN32_APP_INFO ( object ) ;
g_clear_pointer ( & info - > supported_types , g_free ) ;
g_clear_object ( & info - > app ) ;
g_clear_object ( & info - > handler ) ;
G_OBJECT_CLASS ( g_win32_app_info_parent_class ) - > finalize ( object ) ;
}
static void
g_win32_app_info_class_init ( GWin32AppInfoClass * klass )
{
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
gobject_class - > finalize = g_win32_app_info_finalize ;
}
static void
g_win32_app_info_init ( GWin32AppInfo * local )
{
}
static GAppInfo *
g_win32_app_info_new_from_app ( GWin32AppInfoApplication * app ,
GWin32AppInfoHandler * handler )
{
GWin32AppInfo * new_info ;
GHashTableIter iter ;
gpointer ext ;
int i ;
new_info = g_object_new ( G_TYPE_WIN32_APP_INFO , NULL ) ;
new_info - > app = g_object_ref ( app ) ;
g_win32_appinfo_init ( ) ;
G_LOCK ( gio_win32_appinfo ) ;
i = 0 ;
g_hash_table_iter_init ( & iter , new_info - > app - > supported_exts ) ;
while ( g_hash_table_iter_next ( & iter , & ext , NULL ) )
{
if ( ext )
i + = 1 ;
}
new_info - > supported_types = g_malloc ( sizeof ( gchar * ) * ( i + 1 ) ) ;
i = 0 ;
g_hash_table_iter_init ( & iter , new_info - > app - > supported_exts ) ;
while ( g_hash_table_iter_next ( & iter , & ext , NULL ) )
{
if ( ! ext )
continue ;
new_info - > supported_types [ i ] = ( gchar * ) ext ;
i + = 1 ;
}
G_UNLOCK ( gio_win32_appinfo ) ;
new_info - > supported_types [ i ] = NULL ;
2015-06-24 12:07:15 +02:00
new_info - > handler = handler ? g_object_ref ( handler ) : NULL ;
2014-08-29 10:53:35 +02:00
return G_APP_INFO ( new_info ) ;
}
static GAppInfo *
g_win32_app_info_dup ( GAppInfo * appinfo )
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
GWin32AppInfo * new_info ;
new_info = g_object_new ( G_TYPE_WIN32_APP_INFO , NULL ) ;
if ( info - > app )
new_info - > app = g_object_ref ( info - > app ) ;
if ( info - > handler )
new_info - > handler = g_object_ref ( info - > handler ) ;
new_info - > startup_notify = info - > startup_notify ;
if ( info - > supported_types )
{
int i ;
for ( i = 0 ; info - > supported_types [ i ] ; i + + )
break ;
new_info - > supported_types = g_malloc ( sizeof ( gchar * ) * ( i + 1 ) ) ;
for ( i = 0 ; info - > supported_types [ i ] ; i + + )
new_info - > supported_types [ i ] = g_strdup ( info - > supported_types [ i ] ) ;
new_info - > supported_types [ i ] = NULL ;
}
return G_APP_INFO ( new_info ) ;
}
static gboolean
g_win32_app_info_equal ( GAppInfo * appinfo1 ,
GAppInfo * appinfo2 )
{
GWin32AppInfo * info1 = G_WIN32_APP_INFO ( appinfo1 ) ;
GWin32AppInfo * info2 = G_WIN32_APP_INFO ( appinfo2 ) ;
if ( info1 - > app = = NULL | |
info2 - > app = = NULL )
return info1 = = info2 ;
if ( info1 - > app - > canonical_name_folded ! = NULL & &
info2 - > app - > canonical_name_folded ! = NULL )
return ( strcmp ( info1 - > app - > canonical_name_folded ,
info2 - > app - > canonical_name_folded ) ) = = 0 ;
if ( info1 - > app - > executable_folded ! = NULL & &
info2 - > app - > executable_folded ! = NULL )
return ( strcmp ( info1 - > app - > executable_folded ,
info2 - > app - > executable_folded ) ) = = 0 ;
return info1 - > app = = info2 - > app ;
}
static const char *
g_win32_app_info_get_id ( GAppInfo * appinfo )
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
if ( info - > app = = NULL )
return NULL ;
if ( info - > app - > canonical_name_u8 )
return info - > app - > canonical_name_u8 ;
if ( info - > app - > executable_basename )
return info - > app - > executable_basename ;
return NULL ;
}
static const char *
g_win32_app_info_get_name ( GAppInfo * appinfo )
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
if ( info - > app & & info - > app - > canonical_name_u8 )
return info - > app - > canonical_name_u8 ;
else
return P_ ( " Unnamed " ) ;
}
static const char *
g_win32_app_info_get_display_name ( GAppInfo * appinfo )
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
if ( info - > app )
{
if ( info - > app - > localized_pretty_name_u8 )
return info - > app - > localized_pretty_name_u8 ;
else if ( info - > app - > pretty_name_u8 )
return info - > app - > pretty_name_u8 ;
}
return g_win32_app_info_get_name ( appinfo ) ;
}
static const char *
g_win32_app_info_get_description ( GAppInfo * appinfo )
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
if ( info - > app = = NULL )
return NULL ;
return info - > app - > description_u8 ;
}
static const char *
g_win32_app_info_get_executable ( GAppInfo * appinfo )
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
if ( info - > app = = NULL )
return NULL ;
return info - > app - > executable ;
}
static const char *
g_win32_app_info_get_commandline ( GAppInfo * appinfo )
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
if ( info - > app = = NULL )
return NULL ;
return info - > app - > command_u8 ;
}
static GIcon *
g_win32_app_info_get_icon ( GAppInfo * appinfo )
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
if ( info - > app = = NULL )
return NULL ;
return info - > app - > icon ;
}
typedef struct _file_or_uri {
gchar * uri ;
gchar * file ;
} file_or_uri ;
static char *
expand_macro_single ( char macro , file_or_uri * obj )
{
char * result = NULL ;
switch ( macro )
{
case ' * ' :
case ' 0 ' :
case ' 1 ' :
case ' l ' :
case ' d ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
/* TODO: handle 'l' and 'd' differently (longname and desktop name) */
if ( obj - > uri )
result = g_strdup ( obj - > uri ) ;
else if ( obj - > file )
result = g_strdup ( obj - > file ) ;
break ;
case ' u ' :
case ' U ' :
if ( obj - > uri )
result = g_shell_quote ( obj - > uri ) ;
break ;
case ' f ' :
case ' F ' :
if ( obj - > file )
result = g_shell_quote ( obj - > file ) ;
break ;
}
return result ;
}
static gboolean
expand_macro ( char macro ,
GString * exec ,
GWin32AppInfo * info ,
GList * * stat_obj_list ,
GList * * obj_list )
{
GList * objs = * obj_list ;
char * expanded ;
gboolean result = FALSE ;
g_return_val_if_fail ( exec ! = NULL , FALSE ) ;
/*
Legend : ( from http : //msdn.microsoft.com/en-us/library/windows/desktop/cc144101%28v=vs.85%29.aspx)
% * - replace with all parameters
% ~ - replace with all parameters starting with and following the second parameter
% 0 or % 1 the first file parameter . For example " C: \\ Users \\ Eric \\ Destop \\ New Text Document.txt " . Generally this should be in quotes and the applications command line parsing should accept quotes to disambiguate files with spaces in the name and different command line parameters ( this is a security best practice and I believe mentioned in MSDN ) .
% < n > ( where N is 2 - 9 ) , replace with the nth parameter
% s - show command
% h - hotkey value
% i - IDList stored in a shared memory handle is passed here .
% l - long file name form of the first parameter . Note win32 applications will be passed the long file name , win16 applications get the short file name . Specifying % L is preferred as it avoids the need to probe for the application type .
% d - desktop absolute parsing name of the first parameter ( for items that don ' t have file system paths )
% v - for verbs that are none implies all , if there is no parameter passed this is the working directory
% w - the working directory
*/
switch ( macro )
{
case ' * ' :
case ' ~ ' :
if ( * stat_obj_list )
{
gint i ;
GList * o ;
for ( o = * stat_obj_list , i = 0 ;
macro = = ' ~ ' & & o & & i < 2 ;
o = o - > next , i + + ) ;
for ( ; o ; o = o - > next )
{
expanded = expand_macro_single ( macro , o - > data ) ;
if ( expanded )
{
if ( o ! = * stat_obj_list )
g_string_append ( exec , " " ) ;
g_string_append ( exec , expanded ) ;
g_free ( expanded ) ;
}
}
objs = NULL ;
result = TRUE ;
}
break ;
case ' 0 ' :
case ' 1 ' :
case ' l ' :
case ' d ' :
if ( * stat_obj_list )
{
GList * o ;
o = * stat_obj_list ;
if ( o )
{
expanded = expand_macro_single ( macro , o - > data ) ;
if ( expanded )
{
if ( o ! = * stat_obj_list )
g_string_append ( exec , " " ) ;
g_string_append ( exec , expanded ) ;
g_free ( expanded ) ;
}
}
if ( objs )
objs = objs - > next ;
result = TRUE ;
}
break ;
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
if ( * stat_obj_list )
{
gint i ;
GList * o ;
gint n ;
switch ( macro )
{
case ' 2 ' :
n = 2 ;
break ;
case ' 3 ' :
n = 3 ;
break ;
case ' 4 ' :
n = 4 ;
break ;
case ' 5 ' :
n = 5 ;
break ;
case ' 6 ' :
n = 6 ;
break ;
case ' 7 ' :
n = 7 ;
break ;
case ' 8 ' :
n = 8 ;
break ;
case ' 9 ' :
n = 9 ;
break ;
}
for ( o = * stat_obj_list , i = 0 ; o & & i < n ; o = o - > next , i + + ) ;
if ( o )
{
expanded = expand_macro_single ( macro , o - > data ) ;
if ( expanded )
{
if ( o ! = * stat_obj_list )
g_string_append ( exec , " " ) ;
2007-11-28 13:39:07 +01:00
2014-08-29 10:53:35 +02:00
g_string_append ( exec , expanded ) ;
g_free ( expanded ) ;
}
}
result = TRUE ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( objs )
objs = NULL ;
}
break ;
case ' s ' :
break ;
case ' h ' :
break ;
case ' i ' :
break ;
case ' v ' :
break ;
case ' w ' :
expanded = g_get_current_dir ( ) ;
g_string_append ( exec , expanded ) ;
g_free ( expanded ) ;
break ;
case ' u ' :
case ' f ' :
if ( objs )
{
expanded = expand_macro_single ( macro , objs - > data ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( expanded )
{
g_string_append ( exec , expanded ) ;
g_free ( expanded ) ;
}
objs = objs - > next ;
result = TRUE ;
}
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
break ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
case ' U ' :
case ' F ' :
while ( objs )
{
expanded = expand_macro_single ( macro , objs - > data ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( expanded )
{
g_string_append ( exec , expanded ) ;
g_free ( expanded ) ;
}
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
objs = objs - > next ;
result = TRUE ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( objs ! = NULL & & expanded )
g_string_append_c ( exec , ' ' ) ;
}
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
break ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
case ' c ' :
if ( info - > app & & info - > app - > localized_pretty_name_u8 )
{
expanded = g_shell_quote ( info - > app - > localized_pretty_name_u8 ) ;
g_string_append ( exec , expanded ) ;
g_free ( expanded ) ;
}
break ;
2008-06-16 11:54:04 +02:00
2014-08-29 10:53:35 +02:00
case ' m ' : /* deprecated */
case ' n ' : /* deprecated */
case ' N ' : /* deprecated */
/*case 'd': */ /* deprecated */
case ' D ' : /* deprecated */
break ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
case ' % ' :
g_string_append_c ( exec , ' % ' ) ;
break ;
}
* obj_list = objs ;
return result ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
static gboolean
expand_application_parameters ( GWin32AppInfo * info ,
const gchar * exec_line ,
GList * * objs ,
int * argc ,
char * * * argv ,
GError * * error )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
GList * obj_list = * objs ;
GList * * stat_obj_list = objs ;
const char * p = exec_line ;
GString * expanded_exec ;
gboolean res ;
gchar * a_char ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( exec_line = = NULL )
{
g_set_error_literal ( error , G_IO_ERROR , G_IO_ERROR_FAILED ,
P_ ( " Application registry did not specify "
" a shell \\ open \\ command " ) ) ;
return FALSE ;
}
expanded_exec = g_string_new ( NULL ) ;
res = FALSE ;
while ( * p )
{
if ( p [ 0 ] = = ' % ' & & p [ 1 ] ! = ' \0 ' )
{
if ( expand_macro ( p [ 1 ] ,
expanded_exec ,
info , stat_obj_list ,
objs ) )
res = TRUE ;
p + + ;
}
2007-11-26 17:13:05 +01:00
else
2014-08-29 10:53:35 +02:00
g_string_append_c ( expanded_exec , * p ) ;
p + + ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
/* No file substitutions */
if ( obj_list = = * objs & & obj_list ! = NULL & & ! res )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
/* If there is no macro default to %f. This is also what KDE does */
g_string_append_c ( expanded_exec , ' ' ) ;
expand_macro ( ' f ' , expanded_exec , info , stat_obj_list , objs ) ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
/* Replace '\\' with '/', because g_shell_parse_argv considers them
* to be escape sequences .
*/
for ( a_char = expanded_exec - > str ;
a_char < = & expanded_exec - > str [ expanded_exec - > len ] ;
a_char + + )
{
if ( * a_char = = ' \\ ' )
* a_char = ' / ' ;
}
res = g_shell_parse_argv ( expanded_exec - > str , argc , argv , error ) ;
g_string_free ( expanded_exec , TRUE ) ;
return res ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
static gchar *
get_appath_for_exe ( gunichar2 * exe_basename )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
GWin32RegistryKey * apppath_key = NULL ;
GWin32RegistryValueType val_type ;
gunichar2 * appath = NULL ;
gboolean got_value ;
gchar * result = NULL ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
apppath_key = _g_win32_registry_key_build_and_new_w ( NULL , L " HKEY_LOCAL_MACHINE \\ "
L " \\ SOFTWARE "
L " \\ Microsoft "
L " \\ Windows "
L " \\ CurrentVersion "
L " \\ App Paths \\ " ,
exe_basename , NULL ) ;
if ( apppath_key = = NULL )
return NULL ;
got_value = g_win32_registry_key_get_value_w ( apppath_key ,
2020-01-27 00:28:19 +01:00
NULL ,
2014-08-29 10:53:35 +02:00
TRUE ,
L " Path " ,
& val_type ,
( void * * ) & appath ,
NULL ,
NULL ) ;
g_object_unref ( apppath_key ) ;
if ( got_value & & val_type = = G_WIN32_REGISTRY_VALUE_STR )
result = g_utf16_to_utf8 ( appath , - 1 , NULL , NULL , NULL ) ;
g_clear_pointer ( & appath , g_free ) ;
return result ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
2007-11-26 17:13:05 +01:00
static gboolean
2014-08-29 10:53:35 +02:00
g_win32_app_info_launch_internal ( GWin32AppInfo * info ,
GList * objs ,
GAppLaunchContext * launch_context ,
GSpawnFlags spawn_flags ,
GError * * error )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
gboolean completed = FALSE ;
char * * argv , * * envp ;
int argc ;
gchar * command ;
gchar * apppath ;
gunichar2 * exe_basename ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
g_return_val_if_fail ( info ! = NULL , FALSE ) ;
g_return_val_if_fail ( info - > app ! = NULL , FALSE ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
argv = NULL ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( launch_context )
envp = g_app_launch_context_get_environment ( launch_context ) ;
else
envp = g_get_environ ( ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
command = NULL ;
exe_basename = NULL ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( info - > handler )
{
if ( info - > handler - > handler_command )
{
command = g_utf16_to_utf8 ( info - > handler - > handler_command ,
- 1 ,
NULL ,
NULL ,
NULL ) ;
exe_basename = g_utf8_to_utf16 ( info - > handler - > executable_basename ,
- 1 ,
NULL ,
NULL ,
NULL ) ;
}
else if ( info - > handler - > proxy_command )
{
command = g_utf16_to_utf8 ( info - > handler - > proxy_command ,
- 1 ,
NULL ,
NULL ,
NULL ) ;
exe_basename = g_utf8_to_utf16 ( info - > handler - > executable_basename ,
- 1 ,
NULL ,
NULL ,
NULL ) ;
}
}
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( command = = NULL )
{
command = g_strdup ( info - > app - > command_u8 ) ;
exe_basename = g_utf8_to_utf16 ( info - > app - > executable_basename ,
- 1 ,
NULL ,
NULL ,
NULL ) ;
}
apppath = get_appath_for_exe ( exe_basename ) ;
g_free ( exe_basename ) ;
if ( apppath )
{
gchar * * p ;
gint p_index ;
for ( p = envp , p_index = 0 ; p [ 0 ] ; p + + , p_index + + )
if ( ( p [ 0 ] [ 0 ] = = ' p ' | | p [ 0 ] [ 0 ] = = ' P ' ) & &
( p [ 0 ] [ 1 ] = = ' a ' | | p [ 0 ] [ 1 ] = = ' A ' ) & &
( p [ 0 ] [ 2 ] = = ' t ' | | p [ 0 ] [ 2 ] = = ' T ' ) & &
( p [ 0 ] [ 3 ] = = ' h ' | | p [ 0 ] [ 3 ] = = ' H ' ) & &
( p [ 0 ] [ 4 ] = = ' = ' ) )
break ;
if ( p [ 0 ] = = NULL )
{
gchar * * new_envp ;
new_envp = g_new ( char * , g_strv_length ( envp ) + 2 ) ;
new_envp [ 0 ] = g_strdup_printf ( " PATH=%s " , apppath ) ;
for ( p_index = 0 ; p_index < = g_strv_length ( envp ) ; p_index + + )
new_envp [ 1 + p_index ] = envp [ p_index ] ;
g_free ( envp ) ;
envp = new_envp ;
}
else
{
gchar * p_path ;
p_path = & p [ 0 ] [ 5 ] ;
if ( p_path [ 0 ] ! = ' \0 ' )
envp [ p_index ] = g_strdup_printf ( " PATH=%s%c%s " ,
apppath ,
G_SEARCHPATH_SEPARATOR ,
p_path ) ;
else
envp [ p_index ] = g_strdup_printf ( " PATH=%s " , apppath ) ;
g_free ( & p_path [ - 5 ] ) ;
}
}
do
{
GPid pid ;
if ( ! expand_application_parameters ( info ,
command ,
& objs ,
& argc ,
& argv ,
error ) )
goto out ;
if ( ! g_spawn_async ( NULL ,
argv ,
envp ,
spawn_flags ,
NULL ,
NULL ,
& pid ,
error ) )
goto out ;
if ( launch_context ! = NULL )
{
GVariantBuilder builder ;
GVariant * platform_data ;
g_variant_builder_init ( & builder , G_VARIANT_TYPE_ARRAY ) ;
g_variant_builder_add ( & builder , " {sv} " , " pid " , g_variant_new_int32 ( ( gint32 ) pid ) ) ;
platform_data = g_variant_ref_sink ( g_variant_builder_end ( & builder ) ) ;
g_signal_emit_by_name ( launch_context , " launched " , info , platform_data ) ;
g_variant_unref ( platform_data ) ;
}
g_strfreev ( argv ) ;
argv = NULL ;
}
while ( objs ! = NULL ) ;
completed = TRUE ;
out :
g_strfreev ( argv ) ;
g_strfreev ( envp ) ;
g_free ( command ) ;
return completed ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
static void
free_file_or_uri ( gpointer ptr )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
file_or_uri * obj = ptr ;
g_free ( obj - > file ) ;
g_free ( obj - > uri ) ;
g_free ( obj ) ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
static gboolean
g_win32_app_supports_uris ( GWin32AppInfoApplication * app )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
gssize num_of_uris_supported ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( app = = NULL )
return FALSE ;
num_of_uris_supported = ( gssize ) g_hash_table_size ( app - > supported_urls ) ;
if ( g_hash_table_lookup ( app - > supported_urls , " file " ) )
num_of_uris_supported - = 1 ;
return num_of_uris_supported > 0 ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
2007-11-26 17:13:05 +01:00
static gboolean
2014-08-29 10:53:35 +02:00
g_win32_app_info_supports_uris ( GAppInfo * appinfo )
2007-11-26 17:13:05 +01:00
{
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
2014-08-29 10:53:35 +02:00
if ( info - > app = = NULL )
return FALSE ;
2011-10-15 22:59:59 +02:00
2014-08-29 10:53:35 +02:00
return g_win32_app_supports_uris ( info - > app ) ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
2007-11-26 17:13:05 +01:00
static gboolean
2014-08-29 10:53:35 +02:00
g_win32_app_info_supports_files ( GAppInfo * appinfo )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
if ( info - > app = = NULL )
return FALSE ;
return g_hash_table_size ( info - > app - > supported_exts ) > 0 ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
2008-01-04 11:51:56 +01:00
static gboolean
2014-08-29 10:53:35 +02:00
g_win32_app_info_launch_uris ( GAppInfo * appinfo ,
GList * uris ,
GAppLaunchContext * launch_context ,
GError * * error )
2008-01-04 11:51:56 +01:00
{
2014-08-29 10:53:35 +02:00
gboolean res = FALSE ;
gboolean do_files ;
GList * objs ;
do_files = g_win32_app_info_supports_files ( appinfo ) ;
objs = NULL ;
while ( uris )
{
file_or_uri * obj ;
obj = g_new0 ( file_or_uri , 1 ) ;
if ( do_files )
{
GFile * file ;
gchar * path ;
file = g_file_new_for_uri ( uris - > data ) ;
path = g_file_get_path ( file ) ;
obj - > file = path ;
g_object_unref ( file ) ;
}
obj - > uri = g_strdup ( uris - > data ) ;
objs = g_list_prepend ( objs , obj ) ;
uris = uris - > next ;
}
objs = g_list_reverse ( objs ) ;
res = g_win32_app_info_launch_internal ( G_WIN32_APP_INFO ( appinfo ) ,
objs ,
launch_context ,
G_SPAWN_SEARCH_PATH ,
error ) ;
g_list_free_full ( objs , free_file_or_uri ) ;
return res ;
2008-01-04 11:51:56 +01:00
}
2014-11-05 07:20:25 +01:00
static gboolean
g_win32_app_info_launch ( GAppInfo * appinfo ,
GList * files ,
GAppLaunchContext * launch_context ,
GError * * error )
{
2014-08-29 10:53:35 +02:00
gboolean res = FALSE ;
gboolean do_uris ;
GList * objs ;
2014-11-05 07:20:25 +01:00
2014-08-29 10:53:35 +02:00
do_uris = g_win32_app_info_supports_uris ( appinfo ) ;
2014-11-05 07:20:25 +01:00
2014-08-29 10:53:35 +02:00
objs = NULL ;
while ( files )
{
file_or_uri * obj ;
obj = g_new0 ( file_or_uri , 1 ) ;
obj - > file = g_file_get_path ( G_FILE ( files - > data ) ) ;
2014-11-05 07:20:25 +01:00
2014-08-29 10:53:35 +02:00
if ( do_uris )
obj - > uri = g_file_get_uri ( G_FILE ( files - > data ) ) ;
2014-11-05 07:20:25 +01:00
2014-08-29 10:53:35 +02:00
objs = g_list_prepend ( objs , obj ) ;
files = files - > next ;
}
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
objs = g_list_reverse ( objs ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
res = g_win32_app_info_launch_internal ( G_WIN32_APP_INFO ( appinfo ) ,
objs ,
launch_context ,
G_SPAWN_SEARCH_PATH ,
error ) ;
g_list_free_full ( objs , free_file_or_uri ) ;
return res ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
static const char * *
g_win32_app_info_get_supported_types ( GAppInfo * appinfo )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
GWin32AppInfo * info = G_WIN32_APP_INFO ( appinfo ) ;
return ( const char * * ) info - > supported_types ;
2007-11-26 17:13:05 +01:00
}
GAppInfo *
2007-11-30 06:11:25 +01:00
g_app_info_create_from_commandline ( const char * commandline ,
2014-08-29 10:53:35 +02:00
const char * application_name ,
GAppInfoCreateFlags flags ,
GError * * error )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
GWin32AppInfo * info ;
GWin32AppInfoApplication * app ;
2019-11-29 17:48:32 +01:00
gunichar2 * app_command ;
2014-08-29 10:53:35 +02:00
g_return_val_if_fail ( commandline , NULL ) ;
2019-11-29 17:48:32 +01:00
app_command = g_utf8_to_utf16 ( commandline , - 1 , NULL , NULL , NULL ) ;
if ( app_command = = NULL )
return NULL ;
2014-08-29 10:53:35 +02:00
2019-11-29 17:48:32 +01:00
info = g_object_new ( G_TYPE_WIN32_APP_INFO , NULL ) ;
2014-08-29 10:53:35 +02:00
app = g_object_new ( G_TYPE_WIN32_APPINFO_APPLICATION , NULL ) ;
2019-11-29 17:48:32 +01:00
app - > command = g_steal_pointer ( & app_command ) ;
2014-08-29 10:53:35 +02:00
if ( application_name )
{
app - > canonical_name = g_utf8_to_utf16 ( application_name ,
- 1 ,
NULL ,
NULL ,
NULL ) ;
app - > canonical_name_u8 = g_strdup ( application_name ) ;
app - > canonical_name_folded = g_utf8_casefold ( application_name , - 1 ) ;
}
2019-11-29 17:48:32 +01:00
_g_win32_extract_executable ( app - > command ,
& app - > executable ,
& app - > executable_basename ,
& app - > executable_folded ,
NULL ,
& app - > dll_function ) ;
if ( app - > dll_function ! = NULL )
_g_win32_fixup_broken_microsoft_rundll_commandline ( app - > command ) ;
2014-08-29 10:53:35 +02:00
2019-11-29 17:48:32 +01:00
app - > command_u8 = g_utf16_to_utf8 ( app - > command , - 1 , NULL , NULL , NULL ) ;
2014-08-29 10:53:35 +02:00
app - > no_open_with = FALSE ;
app - > user_specific = FALSE ;
app - > default_app = FALSE ;
info - > app = app ;
info - > handler = NULL ;
return G_APP_INFO ( info ) ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
/* GAppInfo interface init */
2007-11-26 17:13:05 +01:00
static void
g_win32_app_info_iface_init ( GAppInfoIface * iface )
{
iface - > dup = g_win32_app_info_dup ;
iface - > equal = g_win32_app_info_equal ;
iface - > get_id = g_win32_app_info_get_id ;
iface - > get_name = g_win32_app_info_get_name ;
iface - > get_description = g_win32_app_info_get_description ;
iface - > get_executable = g_win32_app_info_get_executable ;
iface - > get_icon = g_win32_app_info_get_icon ;
iface - > launch = g_win32_app_info_launch ;
iface - > supports_uris = g_win32_app_info_supports_uris ;
2008-01-04 11:51:56 +01:00
iface - > supports_files = g_win32_app_info_supports_files ;
2007-11-26 17:13:05 +01:00
iface - > launch_uris = g_win32_app_info_launch_uris ;
2014-08-29 10:53:35 +02:00
/* iface->should_show = g_win32_app_info_should_show;*/
/* iface->set_as_default_for_type = g_win32_app_info_set_as_default_for_type;*/
/* iface->set_as_default_for_extension = g_win32_app_info_set_as_default_for_extension;*/
/* iface->add_supports_type = g_win32_app_info_add_supports_type;*/
/* iface->can_remove_supports_type = g_win32_app_info_can_remove_supports_type;*/
/* iface->remove_supports_type = g_win32_app_info_remove_supports_type;*/
/* iface->can_delete = g_win32_app_info_can_delete;*/
/* iface->do_delete = g_win32_app_info_delete;*/
iface - > get_commandline = g_win32_app_info_get_commandline ;
iface - > get_display_name = g_win32_app_info_get_display_name ;
/* iface->set_as_last_used_for_type = g_win32_app_info_set_as_last_used_for_type;*/
iface - > get_supported_types = g_win32_app_info_get_supported_types ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
GAppInfo *
g_app_info_get_default_for_uri_scheme ( const char * uri_scheme )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
GWin32AppInfoURLSchema * scheme ;
char * scheme_down ;
GAppInfo * result ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
scheme_down = g_utf8_casefold ( uri_scheme , - 1 ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( ! scheme_down )
return NULL ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( strcmp ( scheme_down , " file " ) = = 0 )
2007-11-26 17:13:05 +01:00
{
2014-08-29 10:53:35 +02:00
g_free ( scheme_down ) ;
return NULL ;
2007-11-26 17:13:05 +01:00
}
2014-08-29 10:53:35 +02:00
g_win32_appinfo_init ( ) ;
G_LOCK ( gio_win32_appinfo ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
scheme = g_hash_table_lookup ( urls , scheme_down ) ;
g_free ( scheme_down ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( scheme )
g_object_ref ( scheme ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
G_UNLOCK ( gio_win32_appinfo ) ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
result = NULL ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
if ( scheme ! = NULL & &
scheme - > chosen_handler ! = NULL & &
scheme - > chosen_handler - > app ! = NULL )
result = g_win32_app_info_new_from_app ( scheme - > chosen_handler - > app ,
scheme - > chosen_handler ) ;
2010-11-19 10:39:33 +01:00
2014-08-29 10:53:35 +02:00
if ( scheme )
g_object_unref ( scheme ) ;
2010-11-19 10:39:33 +01:00
2014-08-29 10:53:35 +02:00
return result ;
2007-11-26 17:13:05 +01:00
}
2014-11-05 07:18:25 +01:00
GAppInfo *
g_app_info_get_default_for_type ( const char * content_type ,
gboolean must_support_uris )
{
2014-08-29 10:53:35 +02:00
GWin32AppInfoFileExtension * ext ;
char * ext_down ;
GWin32AppInfoHandler * handler ;
GAppInfo * result ;
GWin32AppInfoApplication * app ;
GHashTableIter iter ;
2014-11-05 07:18:25 +01:00
2014-08-29 10:53:35 +02:00
ext_down = g_utf8_casefold ( content_type , - 1 ) ;
if ( ! ext_down )
return NULL ;
g_win32_appinfo_init ( ) ;
G_LOCK ( gio_win32_appinfo ) ;
/* Assuming that "content_type" is a file extension, not a MIME type */
ext = g_hash_table_lookup ( extensions , ext_down ) ;
g_free ( ext_down ) ;
result = NULL ;
if ( ext ! = NULL )
g_object_ref ( ext ) ;
G_UNLOCK ( gio_win32_appinfo ) ;
if ( ext ! = NULL )
{
if ( ext - > chosen_handler ! = NULL & &
ext - > chosen_handler - > app ! = NULL & &
( ! must_support_uris | |
g_win32_app_supports_uris ( ext - > chosen_handler - > app ) ) )
result = g_win32_app_info_new_from_app ( ext - > chosen_handler - > app ,
ext - > chosen_handler ) ;
else
{
g_hash_table_iter_init ( & iter , ext - > handlers ) ;
while ( g_hash_table_iter_next ( & iter , NULL , ( gpointer * ) & handler ) )
{
if ( handler - > app & &
( ! must_support_uris | |
g_win32_app_supports_uris ( ext - > chosen_handler - > app ) ) )
{
result = g_win32_app_info_new_from_app ( handler - > app , handler ) ;
break ;
}
}
if ( result = = NULL )
{
g_hash_table_iter_init ( & iter , ext - > other_apps ) ;
while ( g_hash_table_iter_next ( & iter , NULL , ( gpointer * ) & app ) )
{
if ( ! must_support_uris | |
g_win32_app_supports_uris ( ext - > chosen_handler - > app ) )
{
result = g_win32_app_info_new_from_app ( app , NULL ) ;
break ;
}
}
}
}
g_object_unref ( ext ) ;
}
return result ;
2007-11-26 17:13:05 +01:00
}
GList *
g_app_info_get_all ( void )
{
2014-08-29 10:53:35 +02:00
GHashTableIter iter ;
gpointer value ;
2007-11-26 17:13:05 +01:00
GList * infos ;
2014-08-29 10:53:35 +02:00
GList * apps ;
GList * apps_i ;
2007-11-26 17:13:05 +01:00
2014-08-29 10:53:35 +02:00
g_win32_appinfo_init ( ) ;
G_LOCK ( gio_win32_appinfo ) ;
apps = NULL ;
g_hash_table_iter_init ( & iter , apps_by_id ) ;
while ( g_hash_table_iter_next ( & iter , NULL , & value ) )
apps = g_list_prepend ( apps , g_object_ref ( G_OBJECT ( value ) ) ) ;
G_UNLOCK ( gio_win32_appinfo ) ;
2007-11-26 17:13:05 +01:00
infos = NULL ;
2014-08-29 10:53:35 +02:00
for ( apps_i = apps ; apps_i ; apps_i = apps_i - > next )
infos = g_list_prepend ( infos ,
g_win32_app_info_new_from_app ( apps_i - > data , NULL ) ) ;
g_list_free_full ( apps , g_object_unref ) ;
return infos ;
2008-09-26 21:57:36 +02:00
}
2015-06-24 12:07:40 +02:00
GList *
g_app_info_get_all_for_type ( const char * content_type )
{
GWin32AppInfoFileExtension * ext ;
char * ext_down ;
GWin32AppInfoHandler * handler ;
GWin32AppInfoApplication * app ;
GHashTableIter iter ;
GList * result ;
ext_down = g_utf8_casefold ( content_type , - 1 ) ;
if ( ! ext_down )
return NULL ;
g_win32_appinfo_init ( ) ;
G_LOCK ( gio_win32_appinfo ) ;
/* Assuming that "content_type" is a file extension, not a MIME type */
ext = g_hash_table_lookup ( extensions , ext_down ) ;
g_free ( ext_down ) ;
result = NULL ;
if ( ext ! = NULL )
g_object_ref ( ext ) ;
G_UNLOCK ( gio_win32_appinfo ) ;
if ( ext = = NULL )
return NULL ;
if ( ext - > chosen_handler ! = NULL & &
ext - > chosen_handler - > app ! = NULL )
result = g_list_prepend ( result ,
g_win32_app_info_new_from_app ( ext - > chosen_handler - > app ,
ext - > chosen_handler ) ) ;
g_hash_table_iter_init ( & iter , ext - > handlers ) ;
while ( g_hash_table_iter_next ( & iter , NULL , ( gpointer * ) & handler ) )
{
if ( handler - > app & &
2015-12-13 19:32:39 +01:00
( ext - > chosen_handler = = NULL | | ext - > chosen_handler - > app ! = handler - > app ) )
2015-06-24 12:07:40 +02:00
result = g_list_prepend ( result ,
g_win32_app_info_new_from_app ( handler - > app ,
handler ) ) ;
}
g_hash_table_iter_init ( & iter , ext - > other_apps ) ;
while ( g_hash_table_iter_next ( & iter , NULL , ( gpointer * ) & app ) )
{
result = g_list_prepend ( result , g_win32_app_info_new_from_app ( app , NULL ) ) ;
}
g_object_unref ( ext ) ;
result = g_list_reverse ( result ) ;
return result ;
}
GList *
g_app_info_get_fallback_for_type ( const gchar * content_type )
{
/* TODO: fix this once gcontenttype support is improved */
return g_app_info_get_all_for_type ( content_type ) ;
}
GList *
g_app_info_get_recommended_for_type ( const gchar * content_type )
{
/* TODO: fix this once gcontenttype support is improved */
return g_app_info_get_all_for_type ( content_type ) ;
}
2015-07-02 13:06:17 +02:00
void
g_app_info_reset_type_associations ( const char * content_type )
{
/* nothing to do */
}