def register(): base = os.path.dirname(sys.executable) for program, data in iteritems(default_programs()): data = data.copy() exe = os.path.join(base, program) capabilities_path = cap_path(data) ext_map = {ext.lower():guess_type('file.' + ext.lower())[0] for ext in extensions(program)} ext_map = {ext:mt for ext, mt in iteritems(ext_map) if mt} prog_id_map = {ext:progid_name(data['assoc_name'], ext) for ext in ext_map} with Key(capabilities_path) as key: for k, v in iteritems({'ApplicationDescription':'description', 'ApplicationName':'name'}): key.set(k, data[v]) key.set('ApplicationIcon', '%s,0' % exe) key.set_default_value(r'shell\open\command', '"%s" "%%1"' % exe) with Key('FileAssociations', root=key) as fak, Key('MimeAssociations', root=key) as mak: # previous_associations = set(fak.values()) for ext, prog_id in iteritems(prog_id_map): mt = ext_map[ext] fak.set('.' + ext, prog_id) mak.set(mt, prog_id) for ext, prog_id in iteritems(prog_id_map): create_prog_id(ext, prog_id, ext_map, exe) with Key(r'Software\RegisteredApplications') as key: key.set(data['name'], capabilities_path) winutil = plugins['winutil'][0] winutil.notify_associations_changed()
def register(): base = os.path.dirname(sys.executable) for program, data in default_programs().iteritems(): data = data.copy() exe = os.path.join(base, program) capabilities_path = cap_path(data) ext_map = {ext.lower():guess_type('file.' + ext.lower())[0] for ext in extensions(program)} ext_map = {ext:mt for ext, mt in ext_map.iteritems() if mt} prog_id_map = {ext:progid_name(data['assoc_name'], ext) for ext in ext_map} with Key(capabilities_path) as key: for k, v in {'ApplicationDescription':'description', 'ApplicationName':'name'}.iteritems(): key.set(k, data[v]) key.set('ApplicationIcon', '%s,0' % exe) key.set_default_value(r'shell\open\command', '"%s" "%%1"' % exe) with Key('FileAssociations', root=key) as fak, Key('MimeAssociations', root=key) as mak: # previous_associations = set(fak.itervalues()) for ext, prog_id in prog_id_map.iteritems(): mt = ext_map[ext] fak.set('.' + ext, prog_id) mak.set(mt, prog_id) for ext, prog_id in prog_id_map.iteritems(): create_prog_id(ext, prog_id, ext_map, exe) with Key(r'Software\RegisteredApplications') as key: key.set(data['name'], capabilities_path) from win32com.shell import shell, shellcon shell.SHChangeNotify(shellcon.SHCNE_ASSOCCHANGED, shellcon.SHCNF_DWORD | shellcon.SHCNF_FLUSH, 0, 0)
def get_open_data(base, prog_id): try: k = Key(open_at=r'Software\Classes\%s' % prog_id, root=base) except WindowsError as err: if err.errno == winerror.ERROR_FILE_NOT_FOUND: return None, None with k: return k.get(sub_key=r'shell\open\command'), k.get(sub_key='DefaultIcon'), k.get_mui_string('FriendlyTypeName') or k.get()
def find_programs(extensions): extensions = frozenset(extensions) ans = [] seen_prog_ids, seen_cmdlines = set(), set() # Search for programs registered using Default Programs that claim they are # capable of handling the specified extensions. for base in (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE): try: k = Key(open_at=r'Software\RegisteredApplications', root=base) except WindowsError as err: if err.errno == winerror.ERROR_FILE_NOT_FOUND: continue raise with k: for name, key_path in k.itervalues(get_data=True): try: app_desc, prog_id_map = get_prog_id_map(base, key_path) except Exception: import traceback traceback.print_exc() continue for ext in extensions: prog_id = prog_id_map.get(ext) if prog_id is not None and prog_id not in seen_prog_ids: seen_prog_ids.add(prog_id) cmdline, icon_resource, friendly_name = get_open_data(base, prog_id) if cmdline and cmdline not in seen_cmdlines: seen_cmdlines.add(cmdline) ans.append({'name':app_desc, 'cmdline':cmdline, 'icon_resource':icon_resource}) # Now look for programs that only register with Windows Explorer instead of # Default Programs (for example, FoxIt PDF reader) for ext in extensions: try: k = Key(open_at=r'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.%s\OpenWithProgIDs' % ext, root=HKEY_CURRENT_USER) except WindowsError as err: if err.errno == winerror.ERROR_FILE_NOT_FOUND: continue for prog_id in k.itervalues(): if prog_id and prog_id not in seen_prog_ids: seen_prog_ids.add(prog_id) cmdline, icon_resource, friendly_name = get_open_data(base, prog_id) if cmdline and cmdline not in seen_cmdlines: seen_cmdlines.add(cmdline) exe_name = None exe = split_commandline(cmdline) if exe: exe_name = friendly_app_name(prog_id) or os.path.splitext(os.path.basename(exe[0]))[0] name = exe_name or friendly_name if name: ans.append({'name':name, 'cmdline':cmdline, 'icon_resource':icon_resource}) return ans
def create_prog_id(ext, prog_id, ext_map, exe): with Key(r'Software\Classes\%s' % prog_id) as key: type_name = _('%s Document') % ext.upper() key.set(value=type_name) key.set('FriendlyTypeName', type_name) key.set('PerceivedType', 'Document') key.set(sub_key='DefaultIcon', value=exe+',0') key.set_default_value(r'shell\open\command', '"%s" "%%1"' % exe) key.set('AllowSilentDefaultTakeOver') with Key(r'Software\Classes\.%s\OpenWithProgIDs' % ext) as key: key.set(prog_id)
def find_programs(extensions): extensions = frozenset(extensions) ans = [] seen_prog_ids, seen_cmdlines = set(), set() # Search for programs registered using Default Programs that claim they are # capable of handling the specified extensions. for base in (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE): try: k = Key(open_at=r'Software\RegisteredApplications', root=base) except WindowsError as err: if err.errno == winerror.ERROR_FILE_NOT_FOUND: continue raise with k: for name, key_path in k.values(get_data=True): try: app_desc, prog_id_map = get_prog_id_map(base, key_path) except Exception: import traceback traceback.print_exc() continue for ext in extensions: prog_id = prog_id_map.get(ext) if prog_id is not None and prog_id not in seen_prog_ids: seen_prog_ids.add(prog_id) cmdline, icon_resource, friendly_name = get_open_data(base, prog_id) if cmdline and cmdline not in seen_cmdlines: seen_cmdlines.add(cmdline) ans.append({'name':app_desc, 'cmdline':cmdline, 'icon_resource':icon_resource}) # Now look for programs that only register with Windows Explorer instead of # Default Programs (for example, FoxIt PDF reader) for ext in extensions: try: k = Key(open_at=r'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.%s\OpenWithProgIDs' % ext, root=HKEY_CURRENT_USER) except WindowsError as err: if err.errno == winerror.ERROR_FILE_NOT_FOUND: continue for prog_id in itervalues(k): if prog_id and prog_id not in seen_prog_ids: seen_prog_ids.add(prog_id) cmdline, icon_resource, friendly_name = get_open_data(base, prog_id) if cmdline and cmdline not in seen_cmdlines: seen_cmdlines.add(cmdline) exe_name = None exe = split_commandline(cmdline) if exe: exe_name = friendly_app_name(prog_id) or os.path.splitext(os.path.basename(exe[0]))[0] name = exe_name or friendly_name if name: ans.append({'name':name, 'cmdline':cmdline, 'icon_resource':icon_resource}) return ans
def get_open_data(base, prog_id): try: k = Key(open_at=r'Software\Classes\%s' % prog_id, root=base) except WindowsError as err: if err.errno == winerror.ERROR_FILE_NOT_FOUND: return None, None, None with k: cmd = k.get(sub_key=r'shell\open\command') if cmd: parts = cmd.split() if parts[-1] == '/dde' and '%1' not in cmd: cmd = ' '.join(parts[:-1]) + ' "%1"' return cmd, k.get(sub_key='DefaultIcon'), k.get_mui_string('FriendlyTypeName') or k.get()
def get_prog_id_map(base, key_path): desc, ans = None, {} try: k = Key(open_at=key_path, root=base) except WindowsError as err: if err.errno == winerror.ERROR_FILE_NOT_FOUND: return desc, ans raise with k: desc = k.get_mui_string('ApplicationDescription') if desc is None: return desc, ans for ext, prog_id in k.itervalues(sub_key='FileAssociations', get_data=True): ans[ext[1:].lower()] = prog_id return desc, ans
def create_prog_id(ext, prog_id, ext_map, exe): with Key(r'Software\Classes\%s' % prog_id) as key: type_name = _('%s Document') % ext.upper() key.set(value=type_name) key.set('FriendlyTypeName', type_name) key.set('PerceivedType', 'Document') key.set(sub_key='DefaultIcon', value=exe + ',0') key.set_default_value(r'shell\open\command', '"%s" "%%1"' % exe) # contrary to the msdn docs, this key prevents calibre programs # from appearing in the initial open with list, see # https://www.mobileread.com/forums/showthread.php?t=313668 # key.set('AllowSilentDefaultTakeOver') with Key(r'Software\Classes\.%s\OpenWithProgIDs' % ext) as key: key.set(prog_id)
def unregister(): for program, data in default_programs().iteritems(): capabilities_path = cap_path(data).rpartition('\\')[0] ext_map = {ext.lower():guess_type('file.' + ext.lower())[0] for ext in extensions(program)} ext_map = {ext:mt for ext, mt in ext_map.iteritems() if mt} prog_id_map = {ext:progid_name(data['assoc_name'], ext) for ext in ext_map} with Key(r'Software\RegisteredApplications') as key: key.delete_value(data['name']) parent, sk = capabilities_path.rpartition('\\')[0::2] with Key(parent) as key: key.delete_tree(sk) for ext, prog_id in prog_id_map.iteritems(): with Key(r'Software\Classes\.%s\OpenWithProgIDs' % ext) as key: key.delete_value(prog_id) with Key(r'Software\Classes') as key: key.delete_tree(prog_id)