# # The idea is to simplify a little bit the mechanics # of setting up even the simplest COM program. You # have to set out a fair bit of boilerplate text # to even get started. We're trying to Pythonise # that boilerplate. # import pythoncom from win32com.shell import shell, shellcon from win32com import taskscheduler, axdebug, adsi COM_MODULES = [pythoncom, shell, axdebug, taskscheduler, axdebug, adsi] # # Interface ids all starts with IID_... so pick them out of the # module we know have some. # def _find_interfaces (module): PREFIX = "IID_" interfaces = {} interfaces.update ((i, getattr (module, i)) for i in dir (module) if i.startswith (PREFIX)) interfaces.update ((i[len (PREFIX):], getattr (module, i)) for i in dir (module) if i.startswith (PREFIX)) return interfaces _INTERFACES = {} for module in COM_MODULES: _INTERFACES.update (_find_interfaces (module)) def _find_classes (module): PREFIX = "CLSID_" classes = {} for item in dir (module): if item.startswith (PREFIX): name = item[len (PREFIX):] for interface in _INTERFACES: if interface[1:] == name: break elif "Std" + interface[1:] == name: break elif "Default" + interface[1:] == name: break else: interface = None classes[name] = (getattr (module, item), interface) return classes _CLASSES = {} for module in COM_MODULES: _CLASSES.update (_find_classes (module)) # # This is the most by-hand section of the lot. We have # to identify what interfaces have been exposed by pywin32 # and set up a mapping with a usable name -- as close as # possible to the MS ones -- which maps to the CLSID and # the default interface. # # The default interface may be None, in which case the # user has to pass one in when the class is instantiated. # This may always be done in any case to override the # default. # _MAP = { "ShellLink" : (shell.CLSID_ShellLink, shell.IID_IShellLink), "ActiveDesktop" : (shell.CLSID_ActiveDesktop, shell.IID_IActiveDesktop), "InternetShortcut" : (shell.CLSID_InternetShortcut, shell.IID_IUniformResourceLocator), } class _COMInterface (object): def __init__ (self, instance, *args, **kwargs): self.instance = instance def __getattr__ (self, attr): try: return getattr (self.instance, attr) except AttributeError: try: interface = _INTERFACES[attr] except KeyError: raise AttributeError, "No such interface" else: return _COMInterface (self.instance.QueryInterface (interface)) class _COMInstance (object): def __init__ (self, clsid, default_interface): self.clsid = clsid self.default_interface = default_interface def __call__ (self, default_interface=None, *args, **kwargs): if default_interface is None: default_interface = self.default_interface elif isinstance (default_interface, basestring): default_interface = _INTERFACES[default_interface] else: default_interface = self.default_interface instance = pythoncom.CoCreateInstance ( self.clsid, None, pythoncom.CLSCTX_INPROC_SERVER, default_interface ) return _COMInterface (instance) class _COM (object): def __getattr__ (self, attr): try: clsid, default_interface = _MAP[attr] except KeyError: raise AttributeError else: return _COMInstance (clsid, default_interface) COM = _COM ()