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