0001 """Support for dynamic COM client support. 0002 0003 Introduction 0004 Dynamic COM client support is the ability to use a COM server without 0005 prior knowledge of the server. This can be used to talk to almost all 0006 COM servers, including much of MS Office. 0007 0008 In general, you should not use this module directly - see below. 0009 0010 Example 0011 >>> import win32com.client 0012 >>> xl = win32com.client.Dispatch("Excel.Application") 0013 # The line above invokes the functionality of this class. 0014 # xl is now an object we can use to talk to Excel. 0015 >>> xl.Visible = 1 # The Excel window becomes visible. 0016 0017 """ 0018 import traceback 0019 import string 0020 import new 0021 0022 import pythoncom 0023 import winerror 0024 import build 0025 0026 from types import StringType, IntType, TupleType, ListType 0027 from pywintypes import UnicodeType, IIDType 0028 0029 import win32com.client # Needed as code we eval() references it. 0030 from win32com.client import NeedUnicodeConversions 0031 0032 debugging=0 # General debugging 0033 debugging_attr=0 # Debugging dynamic attribute lookups. 0034 0035 LCID = 0x0 0036 0037 # These errors generally mean the property or method exists, 0038 # but can't be used in this context - eg, property instead of a method, etc. 0039 # Used to determine if we have a real error or not. 0040 ERRORS_BAD_CONTEXT = [ 0041 winerror.DISP_E_MEMBERNOTFOUND, 0042 winerror.DISP_E_BADPARAMCOUNT, 0043 winerror.DISP_E_PARAMNOTOPTIONAL, 0044 winerror.DISP_E_TYPEMISMATCH, 0045 winerror.E_INVALIDARG, 0046 ] 0047 0048 ALL_INVOKE_TYPES = [ 0049 pythoncom.INVOKE_PROPERTYGET, 0050 pythoncom.INVOKE_PROPERTYPUT, 0051 pythoncom.INVOKE_PROPERTYPUTREF, 0052 pythoncom.INVOKE_FUNC 0053 ] 0054 0055 def debug_print(*args): 0056 if debugging: 0057 for arg in args: 0058 print arg, 0059 print 0060 0061 def debug_attr_print(*args): 0062 if debugging_attr: 0063 for arg in args: 0064 print arg, 0065 print 0066 0067 # get the dispatch type in use. 0068 dispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch] 0069 iunkType = pythoncom.TypeIIDs[pythoncom.IID_IUnknown] 0070 _StringOrUnicodeType=[StringType, UnicodeType] 0071 _GoodDispatchType=[StringType,IIDType,UnicodeType] 0072 _defaultDispatchItem=build.DispatchItem 0073 0074 def _GetGoodDispatch(IDispatch, clsctx = pythoncom.CLSCTX_SERVER): 0075 if type(IDispatch) in _GoodDispatchType: 0076 try: 0077 IDispatch = pythoncom.connect(IDispatch) 0078 except pythoncom.ole_error: 0079 IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch) 0080 else: 0081 # may already be a wrapped class. 0082 IDispatch = getattr(IDispatch, "_oleobj_", IDispatch) 0083 return IDispatch 0084 0085 def _GetGoodDispatchAndUserName(IDispatch,userName,clsctx): 0086 if userName is None: 0087 if type(IDispatch) in _StringOrUnicodeType: 0088 userName = IDispatch 0089 else: 0090 userName = "<unknown>" 0091 return (_GetGoodDispatch(IDispatch, clsctx), userName) 0092 0093 def _GetDescInvokeType(entry, default_invoke_type): 0094 if not entry or not entry.desc: return default_invoke_type 0095 return entry.desc[4] 0096 0097 def Dispatch(IDispatch, userName = None, createClass = None, typeinfo = None, UnicodeToString=NeedUnicodeConversions, clsctx = pythoncom.CLSCTX_SERVER): 0098 IDispatch, userName = _GetGoodDispatchAndUserName(IDispatch,userName,clsctx) 0099 if createClass is None: 0100 createClass = CDispatch 0101 lazydata = None 0102 try: 0103 if typeinfo is None: 0104 typeinfo = IDispatch.GetTypeInfo() 0105 try: 0106 #try for a typecomp 0107 typecomp = typeinfo.GetTypeComp() 0108 lazydata = typeinfo, typecomp 0109 except pythoncom.com_error: 0110 pass 0111 except pythoncom.com_error: 0112 typeinfo = None 0113 olerepr = MakeOleRepr(IDispatch, typeinfo, lazydata) 0114 return createClass(IDispatch, olerepr, userName,UnicodeToString, lazydata) 0115 0116 def MakeOleRepr(IDispatch, typeinfo, typecomp): 0117 olerepr = None 0118 if typeinfo is not None: 0119 try: 0120 attr = typeinfo.GetTypeAttr() 0121 # If the type info is a special DUAL interface, magically turn it into 0122 # a DISPATCH typeinfo. 0123 if attr[5] == pythoncom.TKIND_INTERFACE and attr[11] & pythoncom.TYPEFLAG_FDUAL: 0124 # Get corresponding Disp interface; 0125 # -1 is a special value which does this for us. 0126 href = typeinfo.GetRefTypeOfImplType(-1); 0127 typeinfo = typeinfo.GetRefTypeInfo(href) 0128 attr = typeinfo.GetTypeAttr() 0129 if typecomp is None: 0130 olerepr = build.DispatchItem(typeinfo, attr, None, 0) 0131 else: 0132 olerepr = build.LazyDispatchItem(attr, None) 0133 except pythoncom.ole_error: 0134 pass 0135 if olerepr is None: olerepr = build.DispatchItem() 0136 return olerepr 0137 0138 def DumbDispatch(IDispatch, userName = None, createClass = None,UnicodeToString=NeedUnicodeConversions, clsctx=pythoncom.CLSCTX_SERVER): 0139 "Dispatch with no type info" 0140 IDispatch, userName = _GetGoodDispatchAndUserName(IDispatch,userName,clsctx) 0141 if createClass is None: 0142 createClass = CDispatch 0143 return createClass(IDispatch, build.DispatchItem(), userName,UnicodeToString) 0144 0145 class CDispatch: 0146 def __init__(self, IDispatch, olerepr, userName = None, UnicodeToString=NeedUnicodeConversions, lazydata = None): 0147 if userName is None: userName = "<unknown>" 0148 self.__dict__['_oleobj_'] = IDispatch 0149 self.__dict__['_username_'] = userName 0150 self.__dict__['_olerepr_'] = olerepr 0151 self.__dict__['_mapCachedItems_'] = {} 0152 self.__dict__['_builtMethods_'] = {} 0153 self.__dict__['_enum_'] = None 0154 self.__dict__['_unicode_to_string_'] = UnicodeToString 0155 self.__dict__['_lazydata_'] = lazydata 0156 0157 def __call__(self, *args): 0158 "Provide 'default dispatch' COM functionality - allow instance to be called" 0159 if self._olerepr_.defaultDispatchName: 0160 invkind, dispid = self._find_dispatch_type_(self._olerepr_.defaultDispatchName) 0161 else: 0162 invkind, dispid = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET, pythoncom.DISPID_VALUE 0163 if invkind is not None: 0164 allArgs = (dispid,LCID,invkind,1) + args 0165 return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None) 0166 raise TypeError, "This dispatch object does not define a default method" 0167 0168 def __nonzero__(self): 0169 return 1 # ie "if object:" should always be "true" - without this, __len__ is tried. 0170 # _Possibly_ want to defer to __len__ if available, but Im not sure this is 0171 # desirable??? 0172 0173 def __repr__(self): 0174 return "<COMObject %s>" % (self._username_) 0175 0176 def __str__(self): 0177 # __str__ is used when the user does "print object", so we gracefully 0178 # fall back to the __repr__ if the object has no default method. 0179 try: 0180 return str(self.__call__()) 0181 except pythoncom.com_error, details: 0182 if details[0] not in ERRORS_BAD_CONTEXT: 0183 raise 0184 return self.__repr__() 0185 0186 # Delegate comparison to the oleobjs, as they know how to do identity. 0187 def __cmp__(self, other): 0188 other = getattr(other, "_oleobj_", other) 0189 return cmp(self._oleobj_, other) 0190 0191 def __int__(self): 0192 return int(self.__call__()) 0193 0194 def __len__(self): 0195 invkind, dispid = self._find_dispatch_type_("Count") 0196 if invkind: 0197 return self._oleobj_.Invoke(dispid, LCID, invkind, 1) 0198 raise TypeError, "This dispatch object does not define a Count method" 0199 0200 def _NewEnum(self): 0201 try: 0202 invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET 0203 enum = self._oleobj_.InvokeTypes(pythoncom.DISPID_NEWENUM,LCID,invkind,(13, 10),()) 0204 except pythoncom.com_error: 0205 return None # no enumerator for this object. 0206 import util 0207 return util.WrapEnum(enum, None) 0208 0209 def __getitem__(self, index): # syver modified 0210 # Improved __getitem__ courtesy Syver Enstad 0211 # Must check _NewEnum before Item, to ensure b/w compat. 0212 if isinstance(index, IntType): 0213 if self.__dict__['_enum_'] is None: 0214 self.__dict__['_enum_'] = self._NewEnum() 0215 if self.__dict__['_enum_'] is not None: 0216 return self._get_good_object_(self._enum_.__getitem__(index)) 0217 # See if we have an "Item" method/property we can use (goes hand in hand with Count() above!) 0218 invkind, dispid = self._find_dispatch_type_("Item") 0219 if invkind is not None: 0220 return self._get_good_object_(self._oleobj_.Invoke(dispid, LCID, invkind, 1, index)) 0221 raise TypeError, "This object does not support enumeration" 0222 0223 def __setitem__(self, index, *args): 0224 # XXX - todo - We should support calling Item() here too! 0225 # print "__setitem__ with", index, args 0226 if self._olerepr_.defaultDispatchName: 0227 invkind, dispid = self._find_dispatch_type_(self._olerepr_.defaultDispatchName) 0228 else: 0229 invkind, dispid = pythoncom.DISPATCH_PROPERTYPUT | pythoncom.DISPATCH_PROPERTYPUTREF, pythoncom.DISPID_VALUE 0230 if invkind is not None: 0231 allArgs = (dispid,LCID,invkind,0,index) + args 0232 return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None) 0233 raise TypeError, "This dispatch object does not define a default method" 0234 0235 def _find_dispatch_type_(self, methodName): 0236 if self._olerepr_.mapFuncs.has_key(methodName): 0237 item = self._olerepr_.mapFuncs[methodName] 0238 return item.desc[4], item.dispid 0239 0240 if self._olerepr_.propMapGet.has_key(methodName): 0241 item = self._olerepr_.propMapGet[methodName] 0242 return item.desc[4], item.dispid 0243 0244 try: 0245 dispid = self._oleobj_.GetIDsOfNames(0,methodName) 0246 except: ### what error? 0247 return None, None 0248 return pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET, dispid 0249 0250 def _ApplyTypes_(self, dispid, wFlags, retType, argTypes, user, resultCLSID, *args): 0251 result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args) 0252 return self._get_good_object_(result, user, resultCLSID) 0253 0254 def _wrap_dispatch_(self, ob, userName = None, returnCLSID = None, UnicodeToString = NeedUnicodeConversions): 0255 # Given a dispatch object, wrap it in a class 0256 return Dispatch(ob, userName, UnicodeToString=UnicodeToString) 0257 0258 def _get_good_single_object_(self,ob,userName = None, ReturnCLSID=None): 0259 if iunkType==type(ob): 0260 try: 0261 ob = ob.QueryInterface(pythoncom.IID_IDispatch) 0262 # If this works, we then enter the "is dispatch" test below. 0263 except pythoncom.com_error: 0264 # It is an IUnknown, but not an IDispatch, so just let it through. 0265 pass 0266 if dispatchType==type(ob): 0267 # make a new instance of (probably this) class. 0268 return self._wrap_dispatch_(ob, userName, ReturnCLSID) 0269 elif self._unicode_to_string_ and UnicodeType==type(ob): 0270 return str(ob) 0271 else: 0272 return ob 0273 0274 def _get_good_object_(self,ob,userName = None, ReturnCLSID=None): 0275 """Given an object (usually the retval from a method), make it a good object to return. 0276 Basically checks if it is a COM object, and wraps it up. 0277 Also handles the fact that a retval may be a tuple of retvals""" 0278 if ob is None: # Quick exit! 0279 return None 0280 elif type(ob)==TupleType: 0281 return tuple(map(lambda o, s=self, oun=userName, rc=ReturnCLSID: s._get_good_single_object_(o, oun, rc), ob)) 0282 else: 0283 return self._get_good_single_object_(ob) 0284 0285 def _make_method_(self, name): 0286 "Make a method object - Assumes in olerepr funcmap" 0287 methodName = build.MakePublicAttributeName(name) # translate keywords etc. 0288 methodCodeList = self._olerepr_.MakeFuncMethod(self._olerepr_.mapFuncs[name], methodName,0) 0289 methodCode = string.join(methodCodeList,"\n") 0290 try: 0291 # print "Method code for %s is:\n" % self._username_, methodCode 0292 # self._print_details_() 0293 codeObject = compile(methodCode, "<COMObject %s>" % self._username_,"exec") 0294 # Exec the code object 0295 tempNameSpace = {} 0296 # "Dispatch" in the exec'd code is win32com.client.Dispatch, not ours. 0297 globNameSpace = globals().copy() 0298 globNameSpace["Dispatch"] = win32com.client.Dispatch 0299 exec codeObject in globNameSpace, tempNameSpace # self.__dict__, self.__dict__ 0300 name = methodName 0301 # Save the function in map. 0302 fn = self._builtMethods_[name] = tempNameSpace[name] 0303 newMeth = new.instancemethod(fn, self, self.__class__) 0304 return newMeth 0305 except: 0306 debug_print("Error building OLE definition for code ", methodCode) 0307 traceback.print_exc() 0308 return None 0309 0310 def _Release_(self): 0311 """Cleanup object - like a close - to force cleanup when you dont 0312 want to rely on Python's reference counting.""" 0313 for childCont in self._mapCachedItems_.values(): 0314 childCont._Release_() 0315 self._mapCachedItems_ = {} 0316 if self._oleobj_: 0317 self._oleobj_.Release() 0318 self.__dict__['_oleobj_'] = None 0319 if self._olerepr_: 0320 self.__dict__['_olerepr_'] = None 0321 self._enum_ = None 0322 0323 def _proc_(self, name, *args): 0324 """Call the named method as a procedure, rather than function. 0325 Mainly used by Word.Basic, which whinges about such things.""" 0326 try: 0327 item = self._olerepr_.mapFuncs[name] 0328 dispId = item.dispid 0329 return self._get_good_object_(self._oleobj_.Invoke(*(dispId, LCID, item.desc[4], 0) + (args) )) 0330 except KeyError: 0331 raise AttributeError, name 0332 0333 def _print_details_(self): 0334 "Debug routine - dumps what it knows about an object." 0335 print "AxDispatch container",self._username_ 0336 try: 0337 print "Methods:" 0338 for method in self._olerepr_.mapFuncs.keys(): 0339 print "\t", method 0340 print "Props:" 0341 for prop, entry in self._olerepr_.propMap.items(): 0342 print "\t%s = 0x%x - %s" % (prop, entry.dispid, `entry`) 0343 print "Get Props:" 0344 for prop, entry in self._olerepr_.propMapGet.items(): 0345 print "\t%s = 0x%x - %s" % (prop, entry.dispid, `entry`) 0346 print "Put Props:" 0347 for prop, entry in self._olerepr_.propMapPut.items(): 0348 print "\t%s = 0x%x - %s" % (prop, entry.dispid, `entry`) 0349 except: 0350 traceback.print_exc() 0351 0352 def __LazyMap__(self, attr): 0353 try: 0354 if self._LazyAddAttr_(attr): 0355 debug_attr_print("%s.__LazyMap__(%s) added something" % (self._username_,attr)) 0356 return 1 0357 except AttributeError: 0358 return 0 0359 0360 # Using the typecomp, lazily create a new attribute definition. 0361 def _LazyAddAttr_(self,attr): 0362 if self._lazydata_ is None: return 0 0363 res = 0 0364 typeinfo, typecomp = self._lazydata_ 0365 olerepr = self._olerepr_ 0366 # We need to explicitly check each invoke type individually - simply 0367 # specifying '0' will bind to "any member", which may not be the one 0368 # we are actually after (ie, we may be after prop_get, but returned 0369 # the info for the prop_put.) 0370 for i in ALL_INVOKE_TYPES: 0371 try: 0372 x,t = typecomp.Bind(attr,i) 0373 if x==1: #it's a FUNCDESC 0374 r = olerepr._AddFunc_(typeinfo,t,0) 0375 elif x==2: #it's a VARDESC 0376 r = olerepr._AddVar_(typeinfo,t,0) 0377 else: #not found or TYPEDESC/IMPLICITAPP 0378 r=None 0379 if not r is None: 0380 key, map = r[0],r[1] 0381 item = map[key] 0382 if map==olerepr.propMapPut: 0383 olerepr._propMapPutCheck_(key,item) 0384 elif map==olerepr.propMapGet: 0385 olerepr._propMapGetCheck_(key,item) 0386 res = 1 0387 except: 0388 pass 0389 return res 0390 0391 def _FlagAsMethod(self, *methodNames): 0392 """Flag these attribute names as being methods. 0393 Some objects do not correctly differentiate methods and 0394 properties, leading to problems when calling these methods. 0395 0396 Specifically, trying to say: ob.SomeFunc() 0397 may yield an exception "None object is not callable" 0398 In this case, an attempt to fetch the *property*has worked 0399 and returned None, rather than indicating it is really a method. 0400 Calling: ob._FlagAsMethod("SomeFunc") 0401 should then allow this to work. 0402 """ 0403 for name in methodNames: 0404 details = build.MapEntry(self.__AttrToID__(name), (name,)) 0405 self._olerepr_.mapFuncs[name] = details 0406 0407 def __AttrToID__(self,attr): 0408 debug_attr_print("Calling GetIDsOfNames for property %s in Dispatch container %s" % (attr, self._username_)) 0409 return self._oleobj_.GetIDsOfNames(0,attr) 0410 0411 def __getattr__(self, attr): 0412 if attr=='__iter__': 0413 # We can't handle this as a normal method, as if the attribute 0414 # exists, then it must return an iterable object. 0415 try: 0416 invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET 0417 enum = self._oleobj_.InvokeTypes(pythoncom.DISPID_NEWENUM,LCID,invkind,(13, 10),()) 0418 except pythoncom.com_error: 0419 raise AttributeError, "This object can not function as an iterator" 0420 # We must return a callable object. 0421 class Factory: 0422 def __init__(self, ob): 0423 self.ob = ob 0424 def __call__(self): 0425 import win32com.client.util 0426 return win32com.client.util.Iterator(self.ob) 0427 return Factory(enum) 0428 0429 if attr[0]=='_' and attr[-1]=='_': # Fast-track. 0430 raise AttributeError, attr 0431 # If a known method, create new instance and return. 0432 try: 0433 return new.instancemethod(self._builtMethods_[attr], self, self.__class__) 0434 except KeyError: 0435 pass 0436 # XXX - Note that we current are case sensitive in the method. 0437 #debug_attr_print("GetAttr called for %s on DispatchContainer %s" % (attr,self._username_)) 0438 # First check if it is in the method map. Note that an actual method 0439 # must not yet exist, (otherwise we would not be here). This 0440 # means we create the actual method object - which also means 0441 # this code will never be asked for that method name again. 0442 if self._olerepr_.mapFuncs.has_key(attr): 0443 return self._make_method_(attr) 0444 0445 # Delegate to property maps/cached items 0446 retEntry = None 0447 if self._olerepr_ and self._oleobj_: 0448 # first check general property map, then specific "put" map. 0449 retEntry = self._olerepr_.propMap.get(attr) 0450 if retEntry is None: 0451 retEntry = self._olerepr_.propMapGet.get(attr) 0452 # Not found so far - See what COM says. 0453 if retEntry is None: 0454 try: 0455 if self.__LazyMap__(attr): 0456 if self._olerepr_.mapFuncs.has_key(attr): return self._make_method_(attr) 0457 retEntry = self._olerepr_.propMap.get(attr) 0458 if retEntry is None: 0459 retEntry = self._olerepr_.propMapGet.get(attr) 0460 if retEntry is None: 0461 retEntry = build.MapEntry(self.__AttrToID__(attr), (attr,)) 0462 except pythoncom.ole_error: 0463 pass # No prop by that name - retEntry remains None. 0464 0465 if not retEntry is None: # see if in my cache 0466 try: 0467 ret = self._mapCachedItems_[retEntry.dispid] 0468 debug_attr_print ("Cached items has attribute!", ret) 0469 return ret 0470 except (KeyError, AttributeError): 0471 debug_attr_print("Attribute %s not in cache" % attr) 0472 0473 # If we are still here, and have a retEntry, get the OLE item 0474 if not retEntry is None: 0475 invoke_type = _GetDescInvokeType(retEntry, pythoncom.INVOKE_PROPERTYGET) 0476 debug_attr_print("Getting property Id 0x%x from OLE object" % retEntry.dispid) 0477 try: 0478 ret = self._oleobj_.Invoke(retEntry.dispid,0,invoke_type,1) 0479 except pythoncom.com_error, details: 0480 if details[0] in ERRORS_BAD_CONTEXT: 0481 # May be a method. 0482 self._olerepr_.mapFuncs[attr] = retEntry 0483 return self._make_method_(attr) 0484 raise pythoncom.com_error, details 0485 debug_attr_print("OLE returned ", ret) 0486 return self._get_good_object_(ret) 0487 0488 # no where else to look. 0489 raise AttributeError, "%s.%s" % (self._username_, attr) 0490 0491 def __setattr__(self, attr, value): 0492 if self.__dict__.has_key(attr): # Fast-track - if already in our dict, just make the assignment. 0493 # XXX - should maybe check method map - if someone assigns to a method, 0494 # it could mean something special (not sure what, tho!) 0495 self.__dict__[attr] = value 0496 return 0497 # Allow property assignment. 0498 debug_attr_print("SetAttr called for %s.%s=%s on DispatchContainer" % (self._username_, attr, `value`)) 0499 0500 if self._olerepr_: 0501 # Check the "general" property map. 0502 if self._olerepr_.propMap.has_key(attr): 0503 entry = self._olerepr_.propMap[attr] 0504 invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT) 0505 self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value) 0506 return 0507 # Check the specific "put" map. 0508 if self._olerepr_.propMapPut.has_key(attr): 0509 entry = self._olerepr_.propMapPut[attr] 0510 invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT) 0511 self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value) 0512 return 0513 0514 # Try the OLE Object 0515 if self._oleobj_: 0516 if self.__LazyMap__(attr): 0517 # Check the "general" property map. 0518 if self._olerepr_.propMap.has_key(attr): 0519 entry = self._olerepr_.propMap[attr] 0520 invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT) 0521 self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value) 0522 return 0523 # Check the specific "put" map. 0524 if self._olerepr_.propMapPut.has_key(attr): 0525 entry = self._olerepr_.propMapPut[attr] 0526 invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT) 0527 self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value) 0528 return 0529 try: 0530 entry = build.MapEntry(self.__AttrToID__(attr),(attr,)) 0531 except pythoncom.com_error: 0532 # No attribute of that name 0533 entry = None 0534 if entry is not None: 0535 try: 0536 invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT) 0537 self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value) 0538 self._olerepr_.propMap[attr] = entry 0539 debug_attr_print("__setattr__ property %s (id=0x%x) in Dispatch container %s" % (attr, entry.dispid, self._username_)) 0540 return 0541 except pythoncom.com_error: 0542 pass 0543 raise AttributeError, "Property '%s.%s' can not be set." % (self._username_, attr) 0544
Generated by PyXR 0.9.4