PyXR

c:\python24\lib\site-packages\win32 \ com \ server \ register.py



0001 """Utilities for registering objects.
0002 
0003 This module contains utility functions to register Python objects as
0004 valid COM Servers.  The RegisterServer function provides all information
0005 necessary to allow the COM framework to respond to a request for a COM object,
0006 construct the necessary Python object, and dispatch COM events.
0007 
0008 """
0009 import sys
0010 import win32api
0011 import win32con
0012 import pythoncom
0013 import winerror
0014 import os
0015 
0016 CATID_PythonCOMServer = "{B3EF80D0-68E2-11D0-A689-00C04FD658FF}"
0017 
0018 def _set_subkeys(keyName, valueDict, base=win32con.HKEY_CLASSES_ROOT):
0019   hkey = win32api.RegCreateKey(base, keyName)
0020   try:
0021     for key, value in valueDict.items():
0022       win32api.RegSetValueEx(hkey, key, None, win32con.REG_SZ, value)
0023   finally:
0024     win32api.RegCloseKey(hkey)
0025                         
0026 def _set_string(path, value, base=win32con.HKEY_CLASSES_ROOT):
0027   "Set a string value in the registry."
0028 
0029   win32api.RegSetValue(base,
0030                        path,
0031                        win32con.REG_SZ,
0032                        value)
0033 
0034 def _get_string(path, base=win32con.HKEY_CLASSES_ROOT):
0035   "Get a string value from the registry."
0036 
0037   try:
0038     return win32api.RegQueryValue(base, path)
0039   except win32api.error:
0040     return None
0041 
0042 def _remove_key(path, base=win32con.HKEY_CLASSES_ROOT):
0043   "Remove a string from the registry."
0044 
0045   try:
0046     win32api.RegDeleteKey(base, path)
0047   except win32api.error, (code, fn, msg):
0048     if code != winerror.ERROR_FILE_NOT_FOUND:
0049       raise win32api.error, (code, fn, msg)
0050 
0051 def recurse_delete_key(path, base=win32con.HKEY_CLASSES_ROOT):
0052   """Recursively delete registry keys.
0053 
0054   This is needed since you can't blast a key when subkeys exist.
0055   """
0056   try:
0057     h = win32api.RegOpenKey(base, path)
0058   except win32api.error, (code, fn, msg):
0059     if code != winerror.ERROR_FILE_NOT_FOUND:
0060       raise win32api.error, (code, fn, msg)
0061   else:
0062     # parent key found and opened successfully. do some work, making sure
0063     # to always close the thing (error or no).
0064     try:
0065       # remove all of the subkeys
0066       while 1:
0067         try:
0068           subkeyname = win32api.RegEnumKey(h, 0)
0069         except win32api.error, (code, fn, msg):
0070           if code != winerror.ERROR_NO_MORE_ITEMS:
0071             raise win32api.error, (code, fn, msg)
0072           break
0073         recurse_delete_key(path + '\\' + subkeyname, base)
0074 
0075       # remove the parent key
0076       _remove_key(path, base)
0077     finally:
0078       win32api.RegCloseKey(h)
0079 
0080 def _cat_registrar():
0081   return pythoncom.CoCreateInstance(
0082     pythoncom.CLSID_StdComponentCategoriesMgr,
0083     None,
0084     pythoncom.CLSCTX_INPROC_SERVER,
0085     pythoncom.IID_ICatRegister
0086     )
0087     
0088 def _find_localserver_exe(mustfind):
0089   if not sys.platform.startswith("win32"):
0090     return sys.executable
0091   if pythoncom.__file__.find("_d") < 0:
0092     exeBaseName = "pythonw.exe"
0093   else:
0094     exeBaseName = "pythonw_d.exe"
0095   # First see if in the same directory as this .EXE
0096   exeName = os.path.join( os.path.split(sys.executable)[0], exeBaseName )
0097   if not os.path.exists(exeName):
0098     # See if in our sys.prefix directory
0099     exeName = os.path.join( sys.prefix, exeBaseName )
0100   if not os.path.exists(exeName):
0101     # See if in our sys.prefix/pcbuild directory (for developers)
0102     exeName = os.path.join( sys.prefix, "PCbuild",  exeBaseName )
0103   if not os.path.exists(exeName):
0104     # See if the registry has some info.
0105     try:
0106       key = "SOFTWARE\\Python\\PythonCore\\%s\\InstallPath" % sys.winver
0107       path = win32api.RegQueryValue( win32con.HKEY_LOCAL_MACHINE, key )
0108       exeName = os.path.join( path, exeBaseName )
0109     except (AttributeError,win32api.error):
0110       pass
0111   if not os.path.exists(exeName):
0112     if mustfind:
0113       raise RuntimeError, "Can not locate the program '%s'" % exeBaseName
0114     return None
0115   return exeName
0116 
0117 def _find_localserver_module():
0118   import win32com.server
0119   path = win32com.server.__path__[0]
0120   baseName = "localserver"
0121   pyfile = os.path.join(path, baseName + ".py")
0122   try:
0123     os.stat(pyfile)
0124   except os.error:
0125     # See if we have a compiled extension
0126     if __debug__:
0127       ext = ".pyc"
0128     else:
0129       ext = ".pyo"
0130     pyfile = os.path.join(path, baseName + ext)
0131     try:
0132       os.stat(pyfile)
0133     except os.error:
0134       raise RuntimeError, "Can not locate the Python module 'win32com.server.%s'" % baseName
0135   return pyfile
0136 
0137 def RegisterServer(clsid, 
0138                    pythonInstString=None, 
0139                    desc=None,
0140                    progID=None, verProgID=None,
0141                    defIcon=None,
0142                    threadingModel="both",
0143                    policy=None,
0144                    catids=[], other={},
0145                    addPyComCat=None,
0146                    dispatcher = None,
0147                    clsctx = None,
0148                    addnPath = None,
0149                   ):
0150   """Registers a Python object as a COM Server.  This enters almost all necessary
0151      information in the system registry, allowing COM to use the object.
0152 
0153      clsid -- The (unique) CLSID of the server.
0154      pythonInstString -- A string holding the instance name that will be created
0155                    whenever COM requests a new object.
0156      desc -- The description of the COM object.
0157      progID -- The user name of this object (eg, Word.Document)
0158      verProgId -- The user name of this version's implementation (eg Word.6.Document)
0159      defIcon -- The default icon for the object.
0160      threadingModel -- The threading model this object supports.
0161      policy -- The policy to use when creating this object.
0162      catids -- A list of category ID's this object belongs in.
0163      other -- A dictionary of extra items to be registered.
0164      addPyComCat -- A flag indicating if the object should be added to the list
0165               of Python servers installed on the machine.  If None (the default)
0166               then it will be registered when running from python source, but
0167               not registered if running in a frozen environment.
0168      dispatcher -- The dispatcher to use when creating this object.
0169      clsctx -- One of the CLSCTX_* constants.
0170      addnPath -- An additional path the COM framework will add to sys.path
0171                  before attempting to create the object.
0172   """
0173 
0174 
0175   ### backwards-compat check
0176   ### Certain policies do not require a "class name", just the policy itself.
0177   if not pythonInstString and not policy:
0178     raise TypeError, 'You must specify either the Python Class or Python Policy which implement the COM object.'
0179 
0180   keyNameRoot = "CLSID\\%s" % str(clsid)
0181   _set_string(keyNameRoot, desc)
0182 
0183   # Also register as an "Application" so DCOM etc all see us.
0184   _set_string("AppID\\%s" % clsid, progID)
0185   # Depending on contexts requested, register the specified server type.
0186   # Set default clsctx.
0187   if not clsctx:
0188     clsctx = pythoncom.CLSCTX_INPROC_SERVER | pythoncom.CLSCTX_LOCAL_SERVER
0189   # And if we are frozen, ignore the ones that don't make sense in this
0190   # context.
0191   if pythoncom.frozen:
0192     assert sys.frozen, "pythoncom is frozen, but sys.frozen is not set - don't know the context!"
0193     if sys.frozen == "dll":
0194       clsctx = clsctx & pythoncom.CLSCTX_INPROC_SERVER
0195     else:
0196       clsctx = clsctx & pythoncom.CLSCTX_LOCAL_SERVER
0197   # Now setup based on the clsctx left over.
0198   if clsctx & pythoncom.CLSCTX_INPROC_SERVER:
0199     # get the module to use for registration.
0200     # nod to Gordon's installer - if sys.frozen and sys.frozendllhandle
0201     # exist, then we are being registered via a DLL - use this DLL as the
0202     # file name.
0203     if pythoncom.frozen:
0204       if hasattr(sys, "frozendllhandle"):
0205         dllName = win32api.GetModuleFileName(sys.frozendllhandle)
0206       else:
0207         raise RuntimeError, "We appear to have a frozen DLL, but I don't know the DLL to use"
0208     else:
0209       # Normal case - running from .py file, so register pythoncom's DLL.
0210       dllName = os.path.basename(pythoncom.__file__)
0211 
0212     _set_subkeys(keyNameRoot + "\\InprocServer32",
0213                  { None : dllName,
0214                    "ThreadingModel" : threadingModel,
0215                    })
0216   else: # Remove any old InProcServer32 registrations
0217     _remove_key(keyNameRoot + "\\InprocServer32")
0218 
0219   if clsctx & pythoncom.CLSCTX_LOCAL_SERVER:
0220     if pythoncom.frozen:
0221       # If we are frozen, we write "{exe} /Automate", just
0222       # like "normal" .EXEs do
0223       exeName = win32api.GetShortPathName(sys.executable)
0224       command = '%s /Automate' % (exeName,)
0225     else:
0226       # Running from .py sources - we need to write
0227       # 'python.exe win32com\server\localserver.py {clsid}"
0228       exeName = _find_localserver_exe(1)
0229       exeName = win32api.GetShortPathName(exeName)
0230       pyfile = _find_localserver_module()
0231       command = '%s "%s" %s' % (exeName, pyfile, str(clsid))
0232     _set_string(keyNameRoot + '\\LocalServer32', command)
0233   else: # Remove any old LocalServer32 registrations
0234     _remove_key(keyNameRoot + "\\LocalServer32")
0235 
0236   if pythonInstString:
0237     _set_string(keyNameRoot + '\\PythonCOM', pythonInstString)
0238   else:
0239     _remove_key(keyNameRoot + '\\PythonCOM')
0240   if policy:
0241     _set_string(keyNameRoot + '\\PythonCOMPolicy', policy)
0242   else:
0243     _remove_key(keyNameRoot + '\\PythonCOMPolicy')
0244 
0245   if dispatcher:
0246     _set_string(keyNameRoot + '\\PythonCOMDispatcher', dispatcher)
0247   else:
0248     _remove_key(keyNameRoot + '\\PythonCOMDispatcher')
0249 
0250   if defIcon:
0251     _set_string(keyNameRoot + '\\DefaultIcon', defIcon)
0252 
0253   if addnPath:
0254     _set_string(keyNameRoot + "\\PythonCOMPath", addnPath)
0255   else:
0256     _remove_key(keyNameRoot + "\\PythonCOMPath")
0257 
0258   if addPyComCat is None:
0259     addPyComCat = pythoncom.frozen == 0
0260   if addPyComCat:
0261     catids = catids + [ CATID_PythonCOMServer ]
0262 
0263   # Set up the implemented categories
0264   if catids:
0265     regCat = _cat_registrar()
0266     regCat.RegisterClassImplCategories(clsid, catids)
0267 
0268   # set up any other reg values they might have
0269   if other:
0270     for key, value in other.items():
0271       _set_string(keyNameRoot + '\\' + key, value)
0272 
0273   if progID:
0274     # set the progID as the most specific that was given to us
0275     if verProgID:
0276       _set_string(keyNameRoot + '\\ProgID', verProgID)
0277     else:
0278       _set_string(keyNameRoot + '\\ProgID', progID)
0279 
0280     # Set up the root entries - version independent.
0281     if desc:
0282       _set_string(progID, desc)
0283     _set_string(progID + '\\CLSID', str(clsid))
0284 
0285     # Set up the root entries - version dependent.
0286     if verProgID:
0287       # point from independent to the current version
0288       _set_string(progID + '\\CurVer', verProgID)
0289 
0290       # point to the version-independent one
0291       _set_string(keyNameRoot + '\\VersionIndependentProgID', progID)
0292 
0293       # set up the versioned progID
0294       if desc:
0295         _set_string(verProgID, desc)
0296       _set_string(verProgID + '\\CLSID', str(clsid))
0297 
0298 def GetUnregisterServerKeys(clsid, progID=None, verProgID=None, customKeys = None):
0299   """Given a server, return a list of of ("key", root), which are keys recursively
0300   and uncondtionally deleted at unregister or uninstall time.
0301   """
0302   # remove the main CLSID registration
0303   ret = [("CLSID\\%s" % str(clsid), win32con.HKEY_CLASSES_ROOT)]
0304   # remove the versioned ProgID registration
0305   if verProgID:
0306     ret.append((verProgID, win32con.HKEY_CLASSES_ROOT))
0307   # blow away the independent ProgID. we can't leave it since we just
0308   # torched the class.
0309   ### could potentially check the CLSID... ?
0310   if progID:
0311     ret.append((progID, win32con.HKEY_CLASSES_ROOT))
0312   # The DCOM config tool may write settings to the AppID key for our CLSID
0313   ret.append( ("AppID\\%s" % str(clsid), win32con.HKEY_CLASSES_ROOT) )
0314   # Any custom keys?
0315   if customKeys:
0316     ret = ret + customKeys
0317    
0318   return ret
0319   
0320 
0321 def UnregisterServer(clsid, progID=None, verProgID=None, customKeys = None):
0322   """Unregisters a Python COM server."""
0323 
0324   for args in GetUnregisterServerKeys(clsid, progID, verProgID, customKeys ):
0325     recurse_delete_key(*args)
0326 
0327   ### it might be nice at some point to "roll back" the independent ProgID
0328   ### to an earlier version if one exists, and just blowing away the
0329   ### specified version of the ProgID (and its corresponding CLSID)
0330   ### another time, though...
0331 
0332   ### NOTE: ATL simply blows away the above three keys without the
0333   ### potential checks that I describe.  Assuming that defines the
0334   ### "standard" then we have no additional changes necessary.
0335 
0336 def GetRegisteredServerOption(clsid, optionName):
0337   """Given a CLSID for a server and option name, return the option value
0338   """
0339   keyNameRoot = "CLSID\\%s\\%s" % (str(clsid), str(optionName))
0340   return _get_string(keyNameRoot)
0341 
0342 
0343 def _get(ob, attr, default=None):
0344   try:
0345     return getattr(ob, attr)
0346   except AttributeError:
0347     pass
0348   # look down sub-classes
0349   try:
0350     bases = ob.__bases__
0351   except AttributeError:
0352     # ob is not a class - no probs.
0353     return default
0354   for base in bases:
0355     val = _get(base, attr, None)
0356     if val is not None:
0357       return val
0358   return default
0359 
0360 def RegisterClasses(*classes, **flags):
0361   quiet = flags.has_key('quiet') and flags['quiet']
0362   debugging = flags.has_key('debug') and flags['debug']
0363   for cls in classes:
0364     clsid = cls._reg_clsid_
0365     progID = _get(cls, '_reg_progid_')
0366     desc = _get(cls, '_reg_desc_', progID)
0367     spec = _get(cls, '_reg_class_spec_')
0368     verProgID = _get(cls, '_reg_verprogid_')
0369     defIcon = _get(cls, '_reg_icon_')
0370     threadingModel = _get(cls, '_reg_threading_', 'both')
0371     catids = _get(cls, '_reg_catids_', [])
0372     options = _get(cls, '_reg_options_', {})
0373     policySpec = _get(cls, '_reg_policy_spec_')
0374     clsctx = _get(cls, '_reg_clsctx_')
0375     tlb_filename = _get(cls, '_reg_typelib_filename_')
0376     # default to being a COM category only when not frozen.
0377     addPyComCat = not _get(cls, '_reg_disable_pycomcat_', pythoncom.frozen!=0)
0378     addnPath = None
0379     if debugging:
0380       # If the class has a debugging dispatcher specified, use it, otherwise
0381       # use our default dispatcher.
0382       dispatcherSpec = _get(cls, '_reg_debug_dispatcher_spec_')
0383       if dispatcherSpec is None:
0384         dispatcherSpec = "win32com.server.dispatcher.DefaultDebugDispatcher"
0385       # And remember the debugging flag as servers may wish to use it at runtime.
0386       debuggingDesc = "(for debugging)"
0387       options['Debugging'] = "1"
0388     else:
0389       dispatcherSpec = _get(cls, '_reg_dispatcher_spec_')
0390       debuggingDesc = ""
0391       options['Debugging'] = "0"
0392 
0393     if spec is None:
0394       moduleName = cls.__module__
0395       if moduleName == '__main__':
0396         # Use argv[0] to determine the module name.
0397         try:
0398          # Use the win32api to find the case-sensitive name
0399           moduleName = os.path.splitext(win32api.FindFiles(sys.argv[0])[0][8])[0]
0400         except (IndexError, win32api.error):
0401           # Can't find the script file - the user must explicitely set the _reg_... attribute.
0402           raise TypeError, "Can't locate the script hosting the COM object - please set _reg_class_spec_ in your object"
0403 
0404       spec = moduleName + "." + cls.__name__
0405       # Frozen apps don't need their directory on sys.path
0406       if not pythoncom.frozen:
0407         scriptDir = os.path.split(sys.argv[0])[0]
0408         if not scriptDir: scriptDir = "."
0409         addnPath = win32api.GetFullPathName(scriptDir)
0410 
0411     RegisterServer(clsid, spec, desc, progID, verProgID, defIcon,
0412                    threadingModel, policySpec, catids, options,
0413                    addPyComCat, dispatcherSpec, clsctx, addnPath)
0414     if not quiet:
0415       print 'Registered:', progID or spec, debuggingDesc
0416     # Register the typelibrary
0417     if tlb_filename:
0418       tlb_filename = os.path.abspath(tlb_filename)
0419       typelib = pythoncom.LoadTypeLib(tlb_filename)
0420       pythoncom.RegisterTypeLib(typelib, tlb_filename)
0421       if not quiet:
0422         print 'Registered type library:', tlb_filename
0423   extra = flags.get('finalize_register')
0424   if extra:
0425     extra()
0426 
0427 def UnregisterClasses(*classes, **flags):
0428   quiet = flags.has_key('quiet') and flags['quiet']
0429   for cls in classes:
0430     clsid = cls._reg_clsid_
0431     progID = _get(cls, '_reg_progid_')
0432     verProgID = _get(cls, '_reg_verprogid_')
0433     customKeys = _get(cls, '_reg_remove_keys_')
0434     unregister_typelib = _get(cls, '_reg_typelib_filename_') is not None
0435 
0436     UnregisterServer(clsid, progID, verProgID, customKeys)
0437     if not quiet:
0438       print 'Unregistered:', progID or str(clsid)
0439     if unregister_typelib:
0440       tlb_guid = _get(cls, "_typelib_guid_")
0441       if tlb_guid is None:
0442         # I guess I could load the typelib, but they need the GUID anyway.
0443         print "Have typelib filename, but no GUID - can't unregister"
0444       else:
0445         major, minor = _get(cls, "_typelib_version_", (1,0))
0446         lcid = _get(cls, "_typelib_lcid_", 0)
0447         try:
0448           pythoncom.UnRegisterTypeLib(tlb_guid, major, minor, lcid)
0449           if not quiet:
0450             print 'Unregistered type library'
0451         except pythoncom.com_error:
0452           pass
0453 
0454   extra = flags.get('finalize_unregister')
0455   if extra:
0456     extra()
0457 #
0458 # Unregister info is for installers or external uninstallers.
0459 # The WISE installer, for example firstly registers the COM server,
0460 # then queries for the Unregister info, appending it to its
0461 # install log.  Uninstalling the package will the uninstall the server
0462 def UnregisterInfoClasses(*classes, **flags):
0463   ret = []
0464   for cls in classes:
0465     clsid = cls._reg_clsid_
0466     progID = _get(cls, '_reg_progid_')
0467     verProgID = _get(cls, '_reg_verprogid_')
0468     customKeys = _get(cls, '_reg_remove_keys_')
0469 
0470     ret = ret + GetUnregisterServerKeys(clsid, progID, verProgID, customKeys)
0471   return ret
0472 
0473 def UseCommandLine(*classes, **flags):
0474   unregisterInfo = '--unregister_info' in sys.argv
0475   unregister = '--unregister' in sys.argv
0476   flags['quiet'] = flags.get('quiet',0) or '--quiet' in sys.argv
0477   flags['debug'] = flags.get('debug',0) or '--debug' in sys.argv
0478   if unregisterInfo:
0479     return UnregisterInfoClasses(*classes, **flags)
0480   if unregister:
0481     UnregisterClasses(*classes, **flags)
0482   else:
0483     RegisterClasses(*classes, **flags)
0484 
0485 
0486 def RegisterPyComCategory():
0487   """ Register the Python COM Server component category.
0488   """
0489   regCat = _cat_registrar()
0490   regCat.RegisterCategories( [ (CATID_PythonCOMServer,
0491                                 0x0409,
0492                                 "Python COM Server") ] )
0493 
0494 if not pythoncom.frozen:
0495   try:
0496     win32api.RegQueryValue(win32con.HKEY_CLASSES_ROOT,
0497                            'Component Categories\\%s' % CATID_PythonCOMServer)
0498   except win32api.error:
0499     try:
0500       RegisterPyComCategory()
0501     except pythoncom.error: # Error with the COM category manager - oh well.
0502       pass    
0503 
0504 

Generated by PyXR 0.9.4
SourceForge.net Logo