PyXR

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



0001 """Policies 
0002 
0003 Note that Dispatchers are now implemented in "dispatcher.py", but
0004 are still documented here.
0005 
0006 Policies
0007 
0008  A policy is an object which manages the interaction between a public 
0009  Python object, and COM .  In simple terms, the policy object is the 
0010  object which is actually called by COM, and it invokes the requested 
0011  method, fetches/sets the requested property, etc.  See the 
0012  @win32com.server.policy.CreateInstance@ method for a description of
0013  how a policy is specified or created.
0014 
0015  Exactly how a policy determines which underlying object method/property 
0016  is obtained is up to the policy.  A few policies are provided, but you 
0017  can build your own.  See each policy class for a description of how it 
0018  implements its policy.
0019 
0020  There is a policy that allows the object to specify exactly which 
0021  methods and properties will be exposed.  There is also a policy that 
0022  will dynamically expose all Python methods and properties - even those 
0023  added after the object has been instantiated.
0024 
0025 Dispatchers
0026 
0027  A Dispatcher is a level in front of a Policy.  A dispatcher is the 
0028  thing which actually receives the COM calls, and passes them to the 
0029  policy object (which in turn somehow does something with the wrapped 
0030  object).
0031 
0032  It is important to note that a policy does not need to have a dispatcher.
0033  A dispatcher has the same interface as a policy, and simply steps in its 
0034  place, delegating to the real policy.  The primary use for a Dispatcher 
0035  is to support debugging when necessary, but without imposing overheads 
0036  when not (ie, by not using a dispatcher at all).
0037 
0038  There are a few dispatchers provided - "tracing" dispatchers which simply 
0039  prints calls and args (including a variation which uses 
0040  win32api.OutputDebugString), and a "debugger" dispatcher, which can 
0041  invoke the debugger when necessary.
0042 
0043 Error Handling
0044 
0045  It is important to realise that the caller of these interfaces may
0046  not be Python.  Therefore, general Python exceptions and tracebacks aren't 
0047  much use.
0048 
0049  In general, there is an Exception class that should be raised, to allow 
0050  the framework to extract rich COM type error information.
0051 
0052  The general rule is that the **only** exception returned from Python COM 
0053  Server code should be an Exception instance.  Any other Python exception 
0054  should be considered an implementation bug in the server (if not, it 
0055  should be handled, and an appropriate Exception instance raised).  Any 
0056  other exception is considered "unexpected", and a dispatcher may take 
0057  special action (see Dispatchers above)
0058 
0059  Occasionally, the implementation will raise the policy.error error.  
0060  This usually means there is a problem in the implementation that the 
0061  Python programmer should fix.
0062 
0063  For example, if policy is asked to wrap an object which it can not 
0064  support (because, eg, it does not provide _public_methods_ or _dynamic_) 
0065  then policy.error will be raised, indicating it is a Python programmers 
0066  problem, rather than a COM error.
0067  
0068 """
0069 __author__ = "Greg Stein and Mark Hammond"
0070 
0071 import win32api
0072 import winerror
0073 import string
0074 import sys
0075 import types
0076 import win32con, pythoncom
0077 
0078 #Import a few important constants to speed lookups.
0079 from pythoncom import \
0080         DISPATCH_METHOD, DISPATCH_PROPERTYGET, DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF, \
0081         DISPID_UNKNOWN, DISPID_VALUE, DISPID_PROPERTYPUT, DISPID_NEWENUM, \
0082         DISPID_EVALUATE, DISPID_CONSTRUCTOR, DISPID_DESTRUCTOR, DISPID_COLLECT,DISPID_STARTENUM
0083 
0084 S_OK = 0
0085 
0086 # Few more globals to speed things.
0087 from pywintypes import UnicodeType
0088 IDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
0089 IUnknownType = pythoncom.TypeIIDs[pythoncom.IID_IUnknown]
0090 core_has_unicode = hasattr(__builtins__, "unicode")
0091 
0092 from exception import COMException
0093 error = __name__ + " error"
0094 
0095 regSpec = 'CLSID\\%s\\PythonCOM'
0096 regPolicy = 'CLSID\\%s\\PythonCOMPolicy'
0097 regDispatcher = 'CLSID\\%s\\PythonCOMDispatcher'
0098 regAddnPath = 'CLSID\\%s\\PythonCOMPath'
0099 
0100 # exc_info doesnt appear 'till Python 1.5, but we now have other 1.5 deps!
0101 from sys import exc_info
0102 
0103 def CreateInstance(clsid, reqIID):
0104   """Create a new instance of the specified IID
0105 
0106   The COM framework **always** calls this function to create a new 
0107   instance for the specified CLSID.  This function looks up the
0108   registry for the name of a policy, creates the policy, and asks the
0109   policy to create the specified object by calling the _CreateInstance_ method.
0110   
0111   Exactly how the policy creates the instance is up to the policy.  See the
0112   specific policy documentation for more details.
0113   """
0114   # First see is sys.path should have something on it.
0115   try:
0116     addnPaths = string.split(win32api.RegQueryValue(win32con.HKEY_CLASSES_ROOT,
0117                                       regAddnPath % clsid),';')
0118     for newPath in addnPaths:
0119       if newPath not in sys.path:
0120         sys.path.insert(0, newPath)
0121   except win32api.error:
0122     pass
0123   try:
0124     policy = win32api.RegQueryValue(win32con.HKEY_CLASSES_ROOT,
0125                                       regPolicy % clsid)
0126     policy = resolve_func(policy)
0127   except win32api.error:
0128     policy = DefaultPolicy
0129 
0130   try:
0131     dispatcher = win32api.RegQueryValue(win32con.HKEY_CLASSES_ROOT,
0132                                       regDispatcher % clsid)
0133     if dispatcher: dispatcher = resolve_func(dispatcher)
0134   except win32api.error:
0135     dispatcher = None
0136     
0137   # clear exception information
0138   sys.exc_type = sys.exc_value = sys.exc_traceback = None # sys.clearexc() appears in 1.5?
0139 
0140   if dispatcher:
0141     retObj = dispatcher(policy, None)
0142   else:
0143     retObj = policy(None)
0144   return retObj._CreateInstance_(clsid, reqIID)
0145 
0146 class BasicWrapPolicy:
0147   """The base class of policies.
0148 
0149      Normally not used directly (use a child class, instead)
0150 
0151      This policy assumes we are wrapping another object
0152      as the COM server.  This supports the delegation of the core COM entry points
0153      to either the wrapped object, or to a child class.
0154 
0155      This policy supports the following special attributes on the wrapped object
0156 
0157      _query_interface_ -- A handler which can respond to the COM 'QueryInterface' call.
0158      _com_interfaces_ -- An optional list of IIDs which the interface will assume are
0159          valid for the object.
0160      _invoke_ -- A handler which can respond to the COM 'Invoke' call.  If this attribute
0161          is not provided, then the default policy implementation is used.  If this attribute
0162          does exist, it is responsible for providing all required functionality - ie, the
0163          policy _invoke_ method is not invoked at all (and nor are you able to call it!)
0164      _getidsofnames_ -- A handler which can respond to the COM 'GetIDsOfNames' call.  If this attribute
0165          is not provided, then the default policy implementation is used.  If this attribute
0166          does exist, it is responsible for providing all required functionality - ie, the
0167          policy _getidsofnames_ method is not invoked at all (and nor are you able to call it!)
0168 
0169      IDispatchEx functionality:
0170 
0171      _invokeex_ -- Very similar to _invoke_, except slightly different arguments are used.
0172          And the result is just the _real_ result (rather than the (hresult, argErr, realResult)
0173          tuple that _invoke_ uses.      
0174          This is the new, prefered handler (the default _invoke_ handler simply called _invokeex_)
0175      _getdispid_ -- Very similar to _getidsofnames_, except slightly different arguments are used,
0176          and only 1 property at a time can be fetched (which is all we support in getidsofnames anyway!)
0177          This is the new, prefered handler (the default _invoke_ handler simply called _invokeex_)
0178      _getnextdispid_- uses self._name_to_dispid_ to enumerate the DISPIDs
0179   """
0180   def __init__(self, object):
0181     """Initialise the policy object
0182 
0183        Params:
0184 
0185        object -- The object to wrap.  May be None *iff* @BasicWrapPolicy._CreateInstance_@ will be
0186        called immediately after this to setup a brand new object
0187     """
0188     if object is not None:
0189       self._wrap_(object)
0190 
0191   def _CreateInstance_(self, clsid, reqIID):
0192     """Creates a new instance of a **wrapped** object
0193 
0194        This method looks up a "@win32com.server.policy.regSpec@" % clsid entry
0195        in the registry (using @DefaultPolicy@)
0196     """
0197     try:
0198       classSpec = win32api.RegQueryValue(win32con.HKEY_CLASSES_ROOT,
0199                                        regSpec % clsid)
0200     except win32api.error:
0201       raise error, "The object is not correctly registered - %s key can not be read" % (regSpec % clsid)
0202     myob = call_func(classSpec)
0203     self._wrap_(myob)
0204     try:
0205       return pythoncom.WrapObject(self, reqIID)
0206     except pythoncom.com_error, (hr, desc, exc, arg):
0207       from win32com.util import IIDToInterfaceName
0208       desc = "The object '%r' was created, but does not support the " \
0209              "interface '%s'(%s): %s" \
0210              % (myob, IIDToInterfaceName(reqIID), reqIID, desc)
0211       raise pythoncom.com_error, (hr, desc, exc, arg)
0212 
0213 
0214   def _wrap_(self, object):
0215     """Wraps up the specified object.
0216 
0217        This function keeps a reference to the passed
0218        object, and may interogate it to determine how to respond to COM requests, etc.
0219     """
0220     # We "clobber" certain of our own methods with ones
0221     # provided by the wrapped object, iff they exist.
0222     self._name_to_dispid_ = { }
0223     ob = self._obj_ = object
0224     if hasattr(ob, '_query_interface_'):
0225       self._query_interface_ = ob._query_interface_
0226 
0227     if hasattr(ob, '_invoke_'):
0228       self._invoke_ = ob._invoke_
0229 
0230     if hasattr(ob, '_invokeex_'):
0231       self._invokeex_ = ob._invokeex_
0232 
0233     if hasattr(ob, '_getidsofnames_'):
0234       self._getidsofnames_ = ob._getidsofnames_
0235 
0236     if hasattr(ob, '_getdispid_'):
0237       self._getdispid_ = ob._getdispid_
0238 
0239     # Allow for override of certain special attributes.
0240     if hasattr(ob, '_com_interfaces_'):
0241       self._com_interfaces_ = []
0242       # Allow interfaces to be specified by name.
0243       for i in ob._com_interfaces_:
0244         if type(i) != pythoncom.PyIIDType:
0245           # Prolly a string!
0246           if i[0] != "{":
0247             i = pythoncom.InterfaceNames[i]
0248         self._com_interfaces_.append(i)
0249     else:
0250       self._com_interfaces_ = [ ]
0251 
0252   # "QueryInterface" handling.
0253   def _QueryInterface_(self, iid):
0254     """The main COM entry-point for QueryInterface. 
0255 
0256        This checks the _com_interfaces_ attribute and if the interface is not specified 
0257        there, it calls the derived helper _query_interface_
0258     """
0259     if iid in self._com_interfaces_:
0260       return 1
0261     return self._query_interface_(iid)
0262 
0263   def _query_interface_(self, iid):
0264     """Called if the object does not provide the requested interface in _com_interfaces,
0265        and does not provide a _query_interface_ handler.
0266 
0267        Returns a result to the COM framework indicating the interface is not supported.
0268     """
0269     return 0
0270 
0271   # "Invoke" handling.
0272   def _Invoke_(self, dispid, lcid, wFlags, args):
0273     """The main COM entry-point for Invoke.  
0274 
0275        This calls the _invoke_ helper.
0276     """
0277     #Translate a possible string dispid to real dispid.
0278     if type(dispid) == type(""):
0279       try:
0280         dispid = self._name_to_dispid_[string.lower(dispid)]
0281       except KeyError:
0282         raise COMException(scode = winerror.DISP_E_MEMBERNOTFOUND, desc="Member not found")
0283     return self._invoke_(dispid, lcid, wFlags, args)
0284  
0285   def _invoke_(self, dispid, lcid, wFlags, args):
0286     # Delegates to the _invokeex_ implementation.  This allows
0287     # a custom policy to define _invokeex_, and automatically get _invoke_ too.
0288     return S_OK, -1, self._invokeex_(dispid, lcid, wFlags, args, None, None)
0289 
0290   # "GetIDsOfNames" handling.
0291   def _GetIDsOfNames_(self, names, lcid):
0292     """The main COM entry-point for GetIDsOfNames.
0293 
0294        This checks the validity of the arguments, and calls the _getidsofnames_ helper.
0295     """
0296     if len(names) > 1:
0297       raise COMException(scode = winerror.DISP_E_INVALID, desc="Cannot support member argument names")
0298     return self._getidsofnames_(names, lcid)
0299 
0300   def _getidsofnames_(self, names, lcid):
0301     ### note: lcid is being ignored...
0302     return (self._getdispid_(names[0], 0), )
0303 
0304   # IDispatchEx support for policies.  Most of the IDispathEx functionality
0305   # by default will raise E_NOTIMPL.  Thus it is not necessary for derived
0306   # policies to explicitely implement all this functionality just to not implement it!
0307 
0308   def _GetDispID_(self, name, fdex):
0309     return self._getdispid_(name, fdex)
0310 
0311   def _getdispid_(self, name, fdex):
0312     try:
0313       ### TODO - look at the fdex flags!!!
0314       return self._name_to_dispid_[string.lower(str(name))]
0315     except KeyError:
0316       raise COMException(scode = winerror.DISP_E_UNKNOWNNAME)
0317 
0318   # "InvokeEx" handling.
0319   def _InvokeEx_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):
0320     """The main COM entry-point for InvokeEx.  
0321 
0322        This calls the _invokeex_ helper.
0323     """
0324     #Translate a possible string dispid to real dispid.
0325     if type(dispid) == type(""):
0326       try:
0327         dispid = self._name_to_dispid_[string.lower(dispid)]
0328       except KeyError:
0329         raise COMException(scode = winerror.DISP_E_MEMBERNOTFOUND, desc="Member not found")
0330     return self._invokeex_(dispid, lcid, wFlags, args, kwargs, serviceProvider)
0331  
0332   def _invokeex_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):
0333     """A stub for _invokeex_ - should never be called.  
0334  
0335        Simply raises an exception.
0336     """
0337     # Base classes should override this method (and not call the base)
0338     raise error, "This class does not provide _invokeex_ semantics"
0339 
0340   def _DeleteMemberByName_(self, name, fdex):
0341     return self._deletememberbyname_(name, fdex)
0342   def _deletememberbyname_(self, name, fdex):
0343     raise COMException(scode = winerror.E_NOTIMPL)
0344 
0345   def _DeleteMemberByDispID_(self, id):
0346     return self._deletememberbydispid(id)
0347   def _deletememberbydispid_(self, id):
0348     raise COMException(scode = winerror.E_NOTIMPL)
0349 
0350   def _GetMemberProperties_(self, id, fdex):
0351     return self._getmemberproperties_(id, fdex)
0352   def _getmemberproperties_(self, id, fdex):
0353     raise COMException(scode = winerror.E_NOTIMPL)
0354 
0355   def _GetMemberName_(self, dispid):
0356     return self._getmembername_(dispid)
0357   def _getmembername_(self, dispid):
0358     raise COMException(scode = winerror.E_NOTIMPL)
0359 
0360   def _GetNextDispID_(self, fdex, dispid):
0361     return self._getnextdispid_(fdex, dispid)
0362   def _getnextdispid_(self, fdex, dispid):
0363     ids = self._name_to_dispid_.values()
0364     ids.sort()
0365     if DISPID_STARTENUM in ids: ids.remove(DISPID_STARTENUM)
0366     if dispid==DISPID_STARTENUM:
0367       return ids[0]
0368     else:
0369       try:
0370         return ids[ids.index(dispid)+1]
0371       except ValueError: # dispid not in list?
0372         raise COMException(scode = winerror.E_UNEXPECTED)
0373       except IndexError: # No more items
0374         raise COMException(scode = winerror.S_FALSE)
0375 
0376   def _GetNameSpaceParent_(self):
0377     return self._getnamespaceparent()
0378   def _getnamespaceparent_(self):
0379     raise COMException(scode = winerror.E_NOTIMPL)
0380 
0381 
0382 class MappedWrapPolicy(BasicWrapPolicy):
0383   """Wraps an object using maps to do its magic
0384 
0385      This policy wraps up a Python object, using a number of maps
0386      which translate from a Dispatch ID and flags, into an object to call/getattr, etc.
0387 
0388      It is the responsibility of derived classes to determine exactly how the
0389      maps are filled (ie, the derived classes determine the map filling policy.
0390 
0391      This policy supports the following special attributes on the wrapped object
0392 
0393      _dispid_to_func_/_dispid_to_get_/_dispid_to_put_ -- These are dictionaries
0394        (keyed by integer dispid, values are string attribute names) which the COM
0395        implementation uses when it is processing COM requests.  Note that the implementation
0396        uses this dictionary for its own purposes - not a copy - which means the contents of 
0397        these dictionaries will change as the object is used.
0398 
0399   """
0400   def _wrap_(self, object):
0401     BasicWrapPolicy._wrap_(self, object)
0402     ob = self._obj_
0403     if hasattr(ob, '_dispid_to_func_'):
0404       self._dispid_to_func_ = ob._dispid_to_func_
0405     else:
0406       self._dispid_to_func_ = { }
0407     if hasattr(ob, '_dispid_to_get_'):
0408       self._dispid_to_get_ = ob._dispid_to_get_
0409     else:
0410       self._dispid_to_get_ = { }
0411     if hasattr(ob, '_dispid_to_put_'):
0412       self._dispid_to_put_ = ob._dispid_to_put_
0413     else:
0414       self._dispid_to_put_ = { }
0415 
0416   def _getmembername_(self, dispid):
0417     if self._dispid_to_func_.has_key(dispid):
0418       return self._dispid_to_func_[dispid]
0419     elif self._dispid_to_get_.has_key(dispid):
0420       return self._dispid_to_get_[dispid]
0421     elif self._dispid_to_put_.has_key(dispid):
0422       return self._dispid_to_put_[dispid]
0423     else:
0424       raise COMException(scode = winerror.DISP_E_MEMBERNOTFOUND)
0425 
0426 class DesignatedWrapPolicy(MappedWrapPolicy):
0427   """A policy which uses a mapping to link functions and dispid
0428      
0429      A MappedWrappedPolicy which allows the wrapped object to specify, via certain
0430      special named attributes, exactly which methods and properties are exposed.
0431 
0432      All a wrapped object need do is provide the special attributes, and the policy
0433      will handle everything else.
0434 
0435      Attributes:
0436 
0437      _public_methods_ -- Required, unless a typelib GUID is given -- A list
0438                   of strings, which must be the names of methods the object
0439                   provides.  These methods will be exposed and callable
0440                   from other COM hosts.
0441      _public_attrs_ A list of strings, which must be the names of attributes on the object.
0442                   These attributes will be exposed and readable and possibly writeable from other COM hosts.
0443      _readonly_attrs_ -- A list of strings, which must also appear in _public_attrs.  These
0444                   attributes will be readable, but not writable, by other COM hosts.
0445      _value_ -- A method that will be called if the COM host requests the "default" method
0446                   (ie, calls Invoke with dispid==DISPID_VALUE)
0447      _NewEnum -- A method that will be called if the COM host requests an enumerator on the
0448                   object (ie, calls Invoke with dispid==DISPID_NEWENUM.)
0449                   It is the responsibility of the method to ensure the returned
0450                   object conforms to the required Enum interface.
0451 
0452     _typelib_guid_ -- The GUID of the typelibrary with interface definitions we use.
0453     _typelib_version_ -- A tuple of (major, minor) with a default of 1,1
0454     _typelib_lcid_ -- The LCID of the typelib, default = LOCALE_USER_DEFAULT
0455 
0456      _Evaluate -- Dunno what this means, except the host has called Invoke with dispid==DISPID_EVALUATE!
0457                   See the COM documentation for details.
0458   """
0459   def _wrap_(self, ob):
0460     # If we have nominated universal interfaces to support, load them now
0461     tlb_guid = getattr(ob, '_typelib_guid_', None)
0462     if tlb_guid is not None:
0463       tlb_major, tlb_minor = getattr(ob, '_typelib_version_', (1,0))
0464       tlb_lcid = getattr(ob, '_typelib_lcid_', 0)
0465       from win32com import universal
0466       interfaces = getattr(ob, '_com_interfaces_', None)
0467       universal_data = universal.RegisterInterfaces(tlb_guid, tlb_lcid,
0468                                        tlb_major, tlb_minor, interfaces)
0469     else:
0470       universal_data = []
0471     MappedWrapPolicy._wrap_(self, ob)
0472     if not hasattr(ob, '_public_methods_') and not hasattr(ob, "_typelib_guid_"):
0473       raise error, "Object does not support DesignatedWrapPolicy, as it does not have either _public_methods_ or _typelib_guid_ attributes."
0474 
0475     # Copy existing _dispid_to_func_ entries to _name_to_dispid_
0476     for dispid, name in self._dispid_to_func_.items():
0477       self._name_to_dispid_[string.lower(name)]=dispid
0478     for dispid, name in self._dispid_to_get_.items():
0479       self._name_to_dispid_[string.lower(name)]=dispid
0480     for dispid, name in self._dispid_to_put_.items():
0481       self._name_to_dispid_[string.lower(name)]=dispid
0482 
0483     # Patch up the universal stuff.
0484     for dispid, invkind, name in universal_data:
0485       self._name_to_dispid_[string.lower(name)]=dispid
0486       if invkind == DISPATCH_METHOD:
0487           self._dispid_to_func_[dispid] = name
0488       elif invkind == DISPATCH_PROPERTYPUT:
0489           self._dispid_to_put_[dispid] = name
0490       elif invkind == DISPATCH_PROPERTYGET:
0491           self._dispid_to_get_[dispid] = name
0492       else:
0493         raise ValueError, "unexpected invkind: %d (%s)" % (invkind,name)
0494     
0495     # look for reserved methods
0496     if hasattr(ob, '_value_'):
0497       self._dispid_to_get_[DISPID_VALUE] = '_value_'
0498       self._dispid_to_put_[DISPID_PROPERTYPUT] = '_value_'
0499     if hasattr(ob, '_NewEnum'):
0500       self._name_to_dispid_['_newenum'] = DISPID_NEWENUM
0501       self._dispid_to_func_[DISPID_NEWENUM] = '_NewEnum'
0502     if hasattr(ob, '_Evaluate'):
0503       self._name_to_dispid_['_evaluate'] = DISPID_EVALUATE
0504       self._dispid_to_func_[DISPID_EVALUATE] = '_Evaluate'
0505 
0506     dispid = self._allocnextdispid(999)
0507     # note: funcs have precedence over attrs (install attrs first)
0508     if hasattr(ob, '_public_attrs_'):
0509       if hasattr(ob, '_readonly_attrs_'):
0510         readonly = ob._readonly_attrs_
0511       else:
0512         readonly = [ ]
0513       for name in ob._public_attrs_:
0514         self._name_to_dispid_[string.lower(name)] = dispid
0515         self._dispid_to_get_[dispid] = name
0516         if name not in readonly:
0517           self._dispid_to_put_[dispid] = name
0518         dispid = self._allocnextdispid(dispid)
0519     for name in getattr(ob, "_public_methods_", []):
0520       if not self._name_to_dispid_.has_key(string.lower(name)):
0521          self._name_to_dispid_[string.lower(name)] = dispid
0522          self._dispid_to_func_[dispid] = name
0523          dispid = self._allocnextdispid(dispid)
0524     self._typeinfos_ = None # load these on demand.
0525 
0526   def _build_typeinfos_(self):
0527     # Can only ever be one for now.
0528     tlb_guid = getattr(self._obj_, '_typelib_guid_', None)
0529     if tlb_guid is None:
0530       return []
0531     tlb_major, tlb_minor = getattr(self._obj_, '_typelib_version_', (1,0))
0532     tlb = pythoncom.LoadRegTypeLib(tlb_guid, tlb_major, tlb_minor)
0533     typecomp = tlb.GetTypeComp()
0534     # Not 100% sure what semantics we should use for the default interface.
0535     # Look for the first name in _com_interfaces_ that exists in the typelib.
0536     for iname in self._obj_._com_interfaces_:
0537       try:
0538         type_info, type_comp = typecomp.BindType(iname)
0539         return [type_info]
0540       except pythoncom.com_error:
0541         pass
0542     return []
0543 
0544   def _GetTypeInfoCount_(self):
0545     if self._typeinfos_ is None:
0546       self._typeinfos_ = self._build_typeinfos_()
0547     return len(self._typeinfos_)
0548   
0549   def _GetTypeInfo_(self, index, lcid):
0550     if self._typeinfos_ is None:
0551       self._typeinfos_ = self._build_typeinfos_()
0552     if index < 0 or index >= len(self._typeinfos_):
0553       raise COMException(scode=winerror.DISP_E_BADINDEX)
0554     return 0, self._typeinfos_[index]
0555 
0556   def _allocnextdispid(self, last_dispid):
0557       while 1:
0558         last_dispid = last_dispid + 1
0559         if not self._dispid_to_func_.has_key(last_dispid) and \
0560            not self._dispid_to_get_.has_key(last_dispid) and \
0561            not self._dispid_to_put_.has_key(last_dispid):
0562               return last_dispid
0563 
0564   def _invokeex_(self, dispid, lcid, wFlags, args, kwArgs, serviceProvider):
0565     ### note: lcid is being ignored...
0566 
0567     if wFlags & DISPATCH_METHOD:
0568       try:
0569         funcname = self._dispid_to_func_[dispid]
0570       except KeyError:
0571         if not wFlags & DISPATCH_PROPERTYGET:
0572           raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)        # not found
0573       else:
0574         try:
0575           func = getattr(self._obj_, funcname)
0576         except AttributeError:
0577           # May have a dispid, but that doesnt mean we have the function!
0578           raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)
0579         # Should check callable here
0580         try:
0581             return func(*args)
0582         except TypeError, v:
0583             # Particularly nasty is "wrong number of args" type error
0584             # This helps you see what 'func' and 'args' actually is
0585             if str(v).find("arguments")>=0:
0586                 print "** TypeError calling function %r(%r)" % (func, args)
0587             raise
0588 
0589     if wFlags & DISPATCH_PROPERTYGET:
0590       try:
0591         name = self._dispid_to_get_[dispid]
0592       except KeyError:
0593           raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)        # not found
0594       retob = getattr(self._obj_, name)
0595       if type(retob)==types.MethodType: # a method as a property - call it.
0596         retob = retob(*args)
0597       return retob
0598 
0599     if wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF): ### correct?
0600       try:
0601         name = self._dispid_to_put_[dispid]
0602       except KeyError:
0603         raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)        # read-only
0604       # If we have a method of that name (ie, a property get function), and
0605       # we have an equiv. property set function, use that instead.
0606       if type(getattr(self._obj_, name, None)) == types.MethodType and \
0607          type(getattr(self._obj_, "Set" + name, None)) == types.MethodType:
0608         fn = getattr(self._obj_, "Set" + name)
0609         fn( *args )
0610       else:
0611         # just set the attribute
0612         setattr(self._obj_, name, args[0])
0613       return
0614 
0615     raise COMException(scode=winerror.E_INVALIDARG, desc="invalid wFlags")
0616 
0617 class EventHandlerPolicy(DesignatedWrapPolicy):
0618     """The default policy used by event handlers in the win32com.client package.
0619 
0620     In addition to the base policy, this provides argument conversion semantics for
0621     params
0622       * dispatch params are converted to dispatch objects.
0623       * Unicode objects are converted to strings (1.5.2 and earlier)
0624 
0625     NOTE: Later, we may allow the object to override this process??
0626     """
0627     def _transform_args_(self, args, kwArgs, dispid, lcid, wFlags, serviceProvider):
0628         ret = []
0629         for arg in args:
0630             arg_type = type(arg)
0631             if arg_type == IDispatchType:
0632                 import win32com.client
0633                 arg = win32com.client.Dispatch(arg)
0634             elif arg_type == IUnknownType:
0635                 try:
0636                     import win32com.client
0637                     arg = win32com.client.Dispatch(arg.QueryInterface(pythoncom.IID_IDispatch))
0638                 except pythoncom.error:
0639                     pass # Keep it as IUnknown
0640             elif not core_has_unicode and arg_type==UnicodeType:
0641                 arg = str(arg)
0642             ret.append(arg)
0643         return tuple(ret), kwArgs
0644     def _invokeex_(self, dispid, lcid, wFlags, args, kwArgs, serviceProvider):
0645         # transform the args.
0646         args, kwArgs = self._transform_args_(args, kwArgs, dispid, lcid, wFlags, serviceProvider)
0647         return DesignatedWrapPolicy._invokeex_( self, dispid, lcid, wFlags, args, kwArgs, serviceProvider)
0648 
0649 class DynamicPolicy(BasicWrapPolicy):
0650   """A policy which dynamically (ie, at run-time) determines public interfaces.
0651   
0652      A dynamic policy is used to dynamically dispatch methods and properties to the
0653      wrapped object.  The list of objects and properties does not need to be known in
0654      advance, and methods or properties added to the wrapped object after construction
0655      are also handled.
0656 
0657      The wrapped object must provide the following attributes:
0658 
0659      _dynamic_ -- A method that will be called whenever an invoke on the object
0660             is called.  The method is called with the name of the underlying method/property
0661             (ie, the mapping of dispid to/from name has been resolved.)  This name property
0662             may also be '_value_' to indicate the default, and '_NewEnum' to indicate a new
0663             enumerator is requested.
0664             
0665   """
0666   def _wrap_(self, object):
0667     BasicWrapPolicy._wrap_(self, object)
0668     if not hasattr(self._obj_, '_dynamic_'):
0669       raise error, "Object does not support Dynamic COM Policy"
0670     self._next_dynamic_ = self._min_dynamic_ = 1000
0671     self._dyn_dispid_to_name_ = {DISPID_VALUE:'_value_', DISPID_NEWENUM:'_NewEnum' }
0672 
0673   def _getdispid_(self, name, fdex):
0674     # TODO - Look at fdex flags.
0675     # TODO - Remove str() of Unicode name param.
0676     lname = string.lower(str(name))
0677     try:
0678       return self._name_to_dispid_[lname]
0679     except KeyError:
0680       dispid = self._next_dynamic_ = self._next_dynamic_ + 1
0681       self._name_to_dispid_[lname] = dispid
0682       self._dyn_dispid_to_name_[dispid] = name # Keep case in this map...
0683       return dispid
0684 
0685   def _invoke_(self, dispid, lcid, wFlags, args):
0686     return S_OK, -1, self._invokeex_(dispid, lcid, wFlags, args, None, None)
0687 
0688   def _invokeex_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):
0689     ### note: lcid is being ignored...
0690     ### note: kwargs is being ignored...
0691     ### note: serviceProvider is being ignored...
0692     ### there might be assigned DISPID values to properties, too...
0693     ### TODO - Remove the str() of the Unicode argument
0694     try:
0695       name = str(self._dyn_dispid_to_name_[dispid])
0696     except KeyError:
0697       raise COMException(scode = winerror.DISP_E_MEMBERNOTFOUND, desc="Member not found")
0698     return self._obj_._dynamic_(name, lcid, wFlags, args)
0699 
0700 
0701 DefaultPolicy = DesignatedWrapPolicy
0702 
0703 def resolve_func(spec):
0704   """Resolve a function by name
0705   
0706   Given a function specified by 'module.function', return a callable object
0707   (ie, the function itself)
0708   """
0709   try:
0710     idx = string.rindex(spec, ".")
0711     mname = spec[:idx]
0712     fname = spec[idx+1:]
0713     # Dont attempt to optimize by looking in sys.modules,
0714     # as another thread may also be performing the import - this
0715     # way we take advantage of the built-in import lock.
0716     module = _import_module(mname)
0717     return getattr(module, fname)
0718   except ValueError: # No "." in name - assume in this module
0719     return globals()[spec]
0720 
0721 def call_func(spec, *args):
0722   """Call a function specified by name.
0723   
0724   Call a function specified by 'module.function' and return the result.
0725   """
0726 
0727   return resolve_func(spec)(*args)
0728 
0729 def _import_module(mname):
0730   """Import a module just like the 'import' statement.
0731 
0732   Having this function is much nicer for importing arbitrary modules than
0733   using the 'exec' keyword.  It is more efficient and obvious to the reader.
0734   """
0735   __import__(mname)
0736   # Eeek - result of _import_ is "win32com" - not "win32com.a.b.c"
0737   # Get the full module from sys.modules
0738   return sys.modules[mname]
0739 
0740 #######
0741 #
0742 # Temporary hacks until all old code moves.
0743 #
0744 # These have been moved to a new source file, but some code may
0745 # still reference them here.  These will end up being removed.
0746 try:
0747   from dispatcher import DispatcherTrace, DispatcherWin32trace
0748 except ImportError: # Quite likely a frozen executable that doesnt need dispatchers
0749   pass
0750 

Generated by PyXR 0.9.4
SourceForge.net Logo