PyXR

c:\python24\lib\site-packages\win32 \ com \ client

Subpackages:

Modules

Init code



0001 # This module exists to create the "best" dispatch object for a given
0002 # object.  If "makepy" support for a given object is detected, it is
0003 # used, otherwise a dynamic dispatch object.
0004 
0005 # Note that if the unknown dispatch object then returns a known
0006 # dispatch object, the known class will be used.  This contrasts
0007 # with dynamic.Dispatch behaviour, where dynamic objects are always used.
0008 import __builtin__
0009 # For some bizarre reason, __builtins__ fails with attribute error on __dict__ here?
0010 NeedUnicodeConversions = not hasattr(__builtin__, "unicode")
0011 
0012 import dynamic, gencache, pythoncom
0013 import sys
0014 import pywintypes
0015 from types import TupleType
0016 from pywintypes import UnicodeType
0017 _PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
0018 
0019 
0020 def __WrapDispatch(dispatch, userName = None, resultCLSID = None, typeinfo = None, \
0021                   UnicodeToString = NeedUnicodeConversions, clsctx = pythoncom.CLSCTX_SERVER,
0022                   WrapperClass = None):
0023   """
0024     Helper function to return a makepy generated class for a CLSID if it exists,
0025     otherwise cope by using CDispatch.
0026   """
0027   if resultCLSID is None:
0028     try:
0029       typeinfo = dispatch.GetTypeInfo()
0030       if typeinfo is not None: # Some objects return NULL, some raise exceptions...
0031         resultCLSID = str(typeinfo.GetTypeAttr()[0])
0032     except pythoncom.com_error:
0033       pass
0034   if resultCLSID is not None:
0035     import gencache
0036     # Attempt to load generated module support
0037     # This may load the module, and make it available
0038     klass = gencache.GetClassForCLSID(resultCLSID)
0039     if klass is not None:
0040       return klass(dispatch)
0041 
0042   # Return a "dynamic" object - best we can do!
0043   if WrapperClass is None: WrapperClass = CDispatch
0044   return dynamic.Dispatch(dispatch, userName, WrapperClass, typeinfo, UnicodeToString=UnicodeToString,clsctx=clsctx)
0045 
0046 
0047 def GetObject(Pathname = None, Class = None, clsctx = None):
0048   """
0049     Mimic VB's GetObject() function.
0050 
0051     ob = GetObject(Class = "ProgID") or GetObject(Class = clsid) will
0052     connect to an already running instance of the COM object.
0053     
0054     ob = GetObject(r"c:\blah\blah\foo.xls") (aka the COM moniker syntax)
0055     will return a ready to use Python wrapping of the required COM object.
0056 
0057     Note: You must specifiy one or the other of these arguments. I know
0058     this isn't pretty, but it is what VB does. Blech. If you don't
0059     I'll throw ValueError at you. :)
0060     
0061     This will most likely throw pythoncom.com_error if anything fails.
0062   """
0063   if clsctx is None:
0064     clsctx = pythoncom.CLSCTX_ALL
0065     
0066   if (Pathname is None and Class is None) or \
0067      (Pathname is not None and Class is not None):
0068     raise ValueError, "You must specify a value for Pathname or Class, but not both."
0069 
0070   if Class is not None:
0071     return GetActiveObject(Class, clsctx)
0072   else:
0073     return Moniker(Pathname, clsctx)    
0074 
0075 def GetActiveObject(Class, clsctx = pythoncom.CLSCTX_ALL):
0076   """
0077     Python friendly version of GetObject's ProgID/CLSID functionality.
0078   """  
0079   resultCLSID = pywintypes.IID(Class)
0080   dispatch = pythoncom.GetActiveObject(resultCLSID)
0081   dispatch = dispatch.QueryInterface(pythoncom.IID_IDispatch)
0082   return __WrapDispatch(dispatch, Class, resultCLSID = resultCLSID, clsctx = clsctx)
0083 
0084 def Moniker(Pathname, clsctx = pythoncom.CLSCTX_ALL):
0085   """
0086     Python friendly version of GetObject's moniker functionality.
0087   """
0088   moniker, i, bindCtx = pythoncom.MkParseDisplayName(Pathname)
0089   dispatch = moniker.BindToObject(bindCtx, None, pythoncom.IID_IDispatch)
0090   return __WrapDispatch(dispatch, Pathname, clsctx = clsctx)
0091   
0092 def Dispatch(dispatch, userName = None, resultCLSID = None, typeinfo = None, UnicodeToString=NeedUnicodeConversions, clsctx = pythoncom.CLSCTX_SERVER):
0093   """Creates a Dispatch based COM object.
0094   """
0095   dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
0096   return __WrapDispatch(dispatch, userName, resultCLSID, typeinfo, UnicodeToString, clsctx)
0097 
0098 def DispatchEx(clsid, machine=None, userName = None, resultCLSID = None, typeinfo = None, UnicodeToString=NeedUnicodeConversions, clsctx = None):
0099   """Creates a Dispatch based COM object on a specific machine.
0100   """
0101   # If InProc is registered, DCOM will use it regardless of the machine name 
0102   # (and regardless of the DCOM config for the object.)  So unless the user
0103   # specifies otherwise, we exclude inproc apps when a remote machine is used.
0104   if clsctx is None:
0105     clsctx = pythoncom.CLSCTX_SERVER
0106     if machine is not None: clsctx = clsctx & ~pythoncom.CLSCTX_INPROC
0107   if machine is None:
0108     serverInfo = None
0109   else:
0110     serverInfo = (machine,)          
0111   if userName is None: userName = clsid
0112   dispatch = pythoncom.CoCreateInstanceEx(clsid, None, clsctx, serverInfo, (pythoncom.IID_IDispatch,))[0]
0113   return Dispatch(dispatch, userName, resultCLSID, typeinfo, UnicodeToString=UnicodeToString, clsctx=clsctx)
0114 
0115 class CDispatch(dynamic.CDispatch):
0116   """
0117     The dynamic class used as a last resort.
0118     The purpose of this overriding of dynamic.CDispatch is to perpetuate the policy
0119     of using the makepy generated wrapper Python class instead of dynamic.CDispatch
0120     if/when possible.
0121   """
0122   def _wrap_dispatch_(self, ob, userName = None, returnCLSID = None, UnicodeToString = NeedUnicodeConversions):
0123     return Dispatch(ob, userName, returnCLSID,None,UnicodeToString)
0124 
0125 def CastTo(ob, target):
0126     """'Cast' a COM object to another interface"""
0127     # todo - should support target being an IID
0128     if hasattr(target, "index"): # string like
0129     # for now, we assume makepy for this to work.
0130         if not ob.__class__.__dict__.has_key("CLSID"):
0131             # Eeek - no makepy support - try and build it.
0132             ob = gencache.EnsureDispatch(ob)
0133         if not ob.__class__.__dict__.has_key("CLSID"):
0134             raise ValueError, "Must be a makepy-able object for this to work"
0135         clsid = ob.CLSID
0136         # Lots of hoops to support "demand-build" - ie, generating
0137         # code for an interface first time it is used.  We assume the
0138         # interface name exists in the same library as the object.
0139         # This is generally the case - only referenced typelibs may be
0140         # a problem, and we can handle that later.  Maybe <wink>
0141         # So get the generated module for the library itself, then
0142         # find the interface CLSID there.
0143         mod = gencache.GetModuleForCLSID(clsid)
0144         # Get the 'root' module.
0145         mod = gencache.GetModuleForTypelib(mod.CLSID, mod.LCID,
0146                                            mod.MajorVersion, mod.MinorVersion)
0147         # Find the CLSID of the target
0148         target_clsid = mod.NamesToIIDMap.get(target)
0149         if target_clsid is None:
0150             raise ValueError, "The interface name '%s' does not appear in the " \
0151                               "same library as object '%r'" % (target, ob)
0152         mod = gencache.GetModuleForCLSID(target_clsid)
0153         target_class = getattr(mod, target)
0154         # resolve coclass to interface
0155         target_class = getattr(target_class, "default_interface", target_class)
0156         return target_class(ob) # auto QI magic happens
0157     raise ValueError, "This object can not be cast"
0158 
0159 class Constants:
0160   """A container for generated COM constants.
0161   """
0162   def __init__(self):
0163     self.__dicts__ = [] # A list of dictionaries
0164   def __getattr__(self, a):
0165     for d in self.__dicts__:
0166       if d.has_key(a):
0167         return d[a]
0168     raise AttributeError, a
0169 
0170 # And create an instance.
0171 constants = Constants()
0172 
0173 # A helpers for DispatchWithEvents - this becomes __setattr__ for the
0174 # temporary class.
0175 def _event_setattr_(self, attr, val):
0176   try:
0177     # Does the COM object have an attribute of this name?
0178     self.__class__.__bases__[0].__setattr__(self, attr, val)
0179   except AttributeError:
0180     # Otherwise just stash it away in the instance.
0181     self.__dict__[attr] = val
0182 
0183 # An instance of this "proxy" is created to break the COM circular references
0184 # that exist (ie, when we connect to the COM events, COM keeps a reference
0185 # to the object.  Thus, the Event connection must be manually broken before
0186 # our object can die.  This solves the problem by manually breaking the connection
0187 # to the real object as the proxy dies.
0188 class EventsProxy:
0189   def __init__(self, ob):
0190     self.__dict__['_obj_'] = ob
0191   def __del__(self):
0192     try:
0193       # If there is a COM error on disconnection we should
0194       # just ignore it - object probably already shut down...
0195       self._obj_.close()
0196     except pythoncom.com_error:
0197       pass
0198   def __getattr__(self, attr):
0199     return getattr(self._obj_, attr)
0200   def __setattr__(self, attr, val):
0201     setattr(self._obj_, attr, val)
0202 
0203 def DispatchWithEvents(clsid, user_event_class):
0204   """Create a COM object that can fire events to a user defined class.
0205   clsid -- The ProgID or CLSID of the object to create.
0206   user_event_class -- A Python class object that responds to the events.
0207 
0208   This requires makepy support for the COM object being created.  If
0209   this support does not exist it will be automatically generated by
0210   this function.  If the object does not support makepy, a TypeError
0211   exception will be raised.
0212 
0213   The result is a class instance that both represents the COM object
0214   and handles events from the COM object.
0215 
0216   It is important to note that the returned instance is not a direct
0217   instance of the user_event_class, but an instance of a temporary
0218   class object that derives from three classes:
0219   * The makepy generated class for the COM object
0220   * The makepy generated class for the COM events
0221   * The user_event_class as passed to this function.
0222 
0223   If this is not suitable, see the getevents function for an alternative
0224   technique of handling events.
0225 
0226   Object Lifetimes:  Whenever the object returned from this function is
0227   cleaned-up by Python, the events will be disconnected from
0228   the COM object.  This is almost always what should happen,
0229   but see the documentation for getevents() for more details.
0230 
0231   Example:
0232 
0233   >>> class IEEvents:
0234   ...    def OnVisible(self, visible):
0235   ...       print "Visible changed:", visible
0236   ...
0237   >>> ie = DispatchWithEvents("InternetExplorer.Application", IEEvents)
0238   >>> ie.Visible = 1
0239   Visible changed: 1
0240   >>> 
0241   """
0242   # Create/Get the object.
0243   disp = Dispatch(clsid)
0244   if not disp.__dict__.get("CLSID"): # Eeek - no makepy support - try and build it.
0245     try:
0246       ti = disp._oleobj_.GetTypeInfo()
0247       disp_clsid = ti.GetTypeAttr()[0]
0248       tlb, index = ti.GetContainingTypeLib()
0249       tla = tlb.GetLibAttr()
0250       gencache.EnsureModule(tla[0], tla[1], tla[3], tla[4], bValidateFile=0)
0251       # Get the class from the module.
0252       disp_class = gencache.GetClassForProgID(str(disp_clsid))
0253     except pythoncom.com_error:
0254       raise TypeError, "This COM object can not automate the makepy process - please run makepy manually for this object"
0255   else:
0256     disp_class = disp.__class__
0257   # If the clsid was an object, get the clsid
0258   clsid = disp_class.CLSID
0259   # Create a new class that derives from 3 classes - the dispatch class, the event sink class and the user class.
0260   import new
0261   events_class = getevents(clsid)
0262   if events_class is None:
0263     raise ValueError, "This COM object does not support events."
0264   result_class = new.classobj("COMEventClass", (disp_class, events_class, user_event_class), {"__setattr__" : _event_setattr_})
0265   instance = result_class(disp._oleobj_) # This only calls the first base class __init__.
0266   events_class.__init__(instance, instance)
0267   if hasattr(user_event_class, "__init__"):
0268     user_event_class.__init__(instance)
0269   return EventsProxy(instance)
0270 
0271 def WithEvents(disp, user_event_class):
0272   """Similar to DispatchWithEvents - except that the returned
0273   object is *not* also usable as the original Dispatch object - that is
0274   the returned object is not dispatchable.
0275 
0276   The difference is best summarised by example.
0277 
0278   >>> class IEEvents:
0279   ...    def OnVisible(self, visible):
0280   ...       print "Visible changed:", visible
0281   ...
0282   >>> ie = Dispatch("InternetExplorer.Application")
0283   >>> ie_events = WithEvents(ie, IEEvents)
0284   >>> ie.Visible = 1
0285   Visible changed: 1
0286 
0287   Compare with the code sample for DispatchWithEvents, where you get a
0288   single object that is both the interface and the event handler.  Note that
0289   the event handler instance will *not* be able to use 'self.' to refer to
0290   IE's methods and properties.
0291 
0292   This is mainly useful where using DispatchWithEvents causes
0293   circular reference problems that the simple proxy doesn't deal with
0294   """
0295   disp = Dispatch(disp)
0296   if not disp.__dict__.get("CLSID"): # Eeek - no makepy support - try and build it.
0297     try:
0298       ti = disp._oleobj_.GetTypeInfo()
0299       disp_clsid = ti.GetTypeAttr()[0]
0300       tlb, index = ti.GetContainingTypeLib()
0301       tla = tlb.GetLibAttr()
0302       gencache.EnsureModule(tla[0], tla[1], tla[3], tla[4], bValidateFile=0)
0303       # Get the class from the module.
0304       disp_class = gencache.GetClassForProgID(str(disp_clsid))
0305     except pythoncom.com_error:
0306       raise TypeError, "This COM object can not automate the makepy process - please run makepy manually for this object"
0307   else:
0308     disp_class = disp.__class__
0309   # Get the clsid
0310   clsid = disp_class.CLSID
0311   # Create a new class that derives from 2 classes - the event sink
0312   # class and the user class.
0313   import new
0314   events_class = getevents(clsid)
0315   if events_class is None:
0316     raise ValueError, "This COM object does not support events."
0317   result_class = new.classobj("COMEventClass", (events_class, user_event_class), {})
0318   instance = result_class(disp) # This only calls the first base class __init__.
0319   if hasattr(user_event_class, "__init__"):
0320     user_event_class.__init__(instance)
0321   return instance
0322 
0323 def getevents(clsid):
0324     """Determine the default outgoing interface for a class, given
0325     either a clsid or progid. It returns a class - you can
0326     conveniently derive your own handler from this class and implement
0327     the appropriate methods.
0328 
0329     This method relies on the classes produced by makepy. You must use
0330     either makepy or the gencache module to ensure that the
0331     appropriate support classes have been generated for the com server
0332     that you will be handling events from.
0333 
0334     Beware of COM circular references.  When the Events class is connected
0335     to the COM object, the COM object itself keeps a reference to the Python
0336     events class.  Thus, neither the Events instance or the COM object will
0337     ever die by themselves.  The 'close' method on the events instance
0338     must be called to break this chain and allow standard Python collection
0339     rules to manage object lifetimes.  Note that DispatchWithEvents() does
0340     work around this problem by the use of a proxy object, but if you use
0341     the getevents() function yourself, you must make your own arrangements
0342     to manage this circular reference issue.
0343 
0344     Beware of creating Python circular references: this will happen if your
0345     handler has a reference to an object that has a reference back to
0346     the event source. Call the 'close' method to break the chain.
0347     
0348     Example:
0349 
0350     >>>win32com.client.gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}',0,1,1)
0351     <module 'win32com.gen_py.....
0352     >>>
0353     >>> class InternetExplorerEvents(win32com.client.getevents("InternetExplorer.Application.1")):
0354     ...    def OnVisible(self, Visible):
0355     ...        print "Visibility changed: ", Visible
0356     ...
0357     >>>
0358     >>> ie=win32com.client.Dispatch("InternetExplorer.Application.1")
0359     >>> events=InternetExplorerEvents(ie) 
0360     >>> ie.Visible=1
0361     Visibility changed:  1
0362     >>>
0363     """
0364 
0365     # find clsid given progid or clsid
0366     clsid=str(pywintypes.IID(clsid))
0367     # return default outgoing interface for that class
0368     klass = gencache.GetClassForCLSID(clsid)
0369     try:
0370       return klass.default_source
0371     except AttributeError:
0372       # See if we have a coclass for the interfaces.
0373       try:
0374         return gencache.GetClassForCLSID(klass.coclass_clsid).default_source
0375       except AttributeError:
0376         return None
0377 
0378 # A Record object, as used by the COM struct support
0379 def Record(name, object):
0380   """Creates a new record object, given the name of the record,
0381   and an object from the same type library.
0382 
0383   Example usage would be:
0384     app = win32com.client.Dispatch("Some.Application")
0385     point = win32com.client.Record("SomeAppPoint", app)
0386     point.x = 0
0387     point.y = 0
0388     app.MoveTo(point)
0389   """
0390   # XXX - to do - probably should allow "object" to already be a module object.
0391   import gencache
0392   object = gencache.EnsureDispatch(object)
0393   module = sys.modules[object.__class__.__module__]
0394   # to allow us to work correctly with "demand generated" code,
0395   # we must use the typelib CLSID to obtain the module
0396   # (otherwise we get the sub-module for the object, which
0397   # does not hold the records)
0398   # thus, package may be module, or may be module's parent if demand generated.
0399   package = gencache.GetModuleForTypelib(module.CLSID, module.LCID, module.MajorVersion, module.MinorVersion)
0400   try:
0401     struct_guid = package.RecordMap[name]
0402   except KeyError:
0403     raise ValueError, "The structure '%s' is not defined in module '%s'" % (name, package)
0404 
0405   return pythoncom.GetRecordFromGuids(module.CLSID, module.MajorVersion, module.MinorVersion, module.LCID, struct_guid)
0406 
0407 
0408 ############################################
0409 # The base of all makepy generated classes
0410 ############################################
0411 class DispatchBaseClass:
0412         def __init__(self, oobj=None):
0413                 if oobj is None:
0414                         oobj = pythoncom.new(self.CLSID)
0415                 elif type(self) == type(oobj): # An instance
0416                         try:
0417                                 oobj = oobj._oleobj_.QueryInterface(self.CLSID, pythoncom.IID_IDispatch) # Must be a valid COM instance
0418                         except pythoncom.com_error, details:
0419                                 import winerror
0420                                 # Some stupid objects fail here, even tho it is _already_ IDispatch!!??
0421                                 # Eg, Lotus notes.
0422                                 # So just let it use the existing object if E_NOINTERFACE
0423                                 if details[0] != winerror.E_NOINTERFACE:
0424                                         raise
0425                                 oobj = oobj._oleobj_
0426                 self.__dict__["_oleobj_"] = oobj # so we dont call __setattr__
0427         # Provide a prettier name than the CLSID
0428         def __repr__(self):
0429                 # Need to get the docstring for the module for this class.
0430                 try:
0431                         mod_doc = sys.modules[self.__class__.__module__].__doc__
0432                         if mod_doc:
0433                                 mod_name = "win32com.gen_py." + mod_doc
0434                         else:
0435                                 mod_name = sys.modules[self.__class__.__module__].__name__
0436                 except KeyError:
0437                   mod_name = "win32com.gen_py.unknown"
0438                 return "<%s.%s instance at 0x%s>" % (mod_name, self.__class__.__name__, id(self))
0439         # Delegate comparison to the oleobjs, as they know how to do identity.
0440         def __cmp__(self, other):
0441                 other = getattr(other, "_oleobj_", other)
0442                 return cmp(self._oleobj_, other)
0443 
0444         def _ApplyTypes_(self, dispid, wFlags, retType, argTypes, user,
0445                      resultCLSID, *args):
0446                 return self._get_good_object_(
0447                     self._oleobj_.InvokeTypes(
0448                               dispid, 0, wFlags, retType, argTypes, *args),
0449                     user, resultCLSID)
0450 
0451         def __getattr__(self, attr):
0452                 args=self._prop_map_get_.get(attr)
0453                 if args is None:
0454                         raise AttributeError, "'%s' object has no attribute '%s'" % (repr(self), attr)
0455                 return self._ApplyTypes_(*args)
0456 
0457         def __setattr__(self, attr, value):
0458                 if self.__dict__.has_key(attr): self.__dict__[attr] = value; return
0459                 try:
0460                         args, defArgs=self._prop_map_put_[attr]
0461                 except KeyError:
0462                         raise AttributeError, "'%s' object has no attribute '%s'" % (repr(self), attr)
0463                 self._oleobj_.Invoke(*(args + (value,) + defArgs))
0464         def _get_good_single_object_(self, obj, obUserName=None, resultCLSID=None):
0465                 return _get_good_single_object_(obj, obUserName, resultCLSID)
0466         def _get_good_object_(self, obj, obUserName=None, resultCLSID=None):
0467                 return _get_good_object_(obj, obUserName, resultCLSID)
0468 
0469 # XXX - These should be consolidated with dynamic.py versions.
0470 def _get_good_single_object_(obj, obUserName=None, resultCLSID=None):
0471         if _PyIDispatchType==type(obj):
0472                 return Dispatch(obj, obUserName, resultCLSID, UnicodeToString=NeedUnicodeConversions)
0473         elif NeedUnicodeConversions and UnicodeType==type(obj):
0474                 return str(obj)
0475         return obj
0476 
0477 def _get_good_object_(obj, obUserName=None, resultCLSID=None):
0478         if obj is None:
0479                 return None
0480         elif type(obj)==TupleType:
0481                 obUserNameTuple = (obUserName,) * len(obj)
0482                 resultCLSIDTuple = (resultCLSID,) * len(obj)
0483                 return tuple(map(_get_good_object_, obj, obUserNameTuple, resultCLSIDTuple))
0484         else:
0485                 return _get_good_single_object_(obj, obUserName, resultCLSID)
0486 
0487 class CoClassBaseClass:
0488         def __init__(self, oobj=None):
0489                 if oobj is None: oobj = pythoncom.new(self.CLSID)
0490                 self.__dict__["_dispobj_"] = self.default_interface(oobj)
0491         def __repr__(self):
0492                 return "<win32com.gen_py.%s.%s>" % (__doc__, self.__class__.__name__)
0493 
0494         def __getattr__(self, attr):
0495                 d=self.__dict__["_dispobj_"]
0496                 if d is not None: return getattr(d, attr)
0497                 raise AttributeError, attr
0498         def __setattr__(self, attr, value):
0499                 if self.__dict__.has_key(attr): self.__dict__[attr] = value; return
0500                 try:
0501                         d=self.__dict__["_dispobj_"]
0502                         if d is not None:
0503                                 d.__setattr__(attr, value)
0504                                 return
0505                 except AttributeError:
0506                         pass
0507                 self.__dict__[attr] = value
0508 

Generated by PyXR 0.9.4
SourceForge.net Logo