Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
dynamic.py709 linesDownload Raw Back to client
1"""Support for dynamic COM client support.2 3Introduction4 Dynamic COM client support is the ability to use a COM server without5 prior knowledge of the server.  This can be used to talk to almost all6 COM servers, including much of MS Office.7 8 In general, you should not use this module directly - see below.9 10Example11 >>> import win32com.client12 >>> xl = win32com.client.Dispatch("Excel.Application")13 # The line above invokes the functionality of this class.14 # xl is now an object we can use to talk to Excel.15 >>> xl.Visible = 1 # The Excel window becomes visible.16 17"""18import traceback19import types20 21import pythoncom  # Needed as code we eval() references it.22import win32com.client23import winerror24from pywintypes import IIDType25 26from . import build27 28debugging = 0  # General debugging29debugging_attr = 0  # Debugging dynamic attribute lookups.30 31LCID = 0x032 33# These errors generally mean the property or method exists,34# but can't be used in this context - eg, property instead of a method, etc.35# Used to determine if we have a real error or not.36ERRORS_BAD_CONTEXT = [37    winerror.DISP_E_MEMBERNOTFOUND,38    winerror.DISP_E_BADPARAMCOUNT,39    winerror.DISP_E_PARAMNOTOPTIONAL,40    winerror.DISP_E_TYPEMISMATCH,41    winerror.E_INVALIDARG,42]43 44ALL_INVOKE_TYPES = [45    pythoncom.INVOKE_PROPERTYGET,46    pythoncom.INVOKE_PROPERTYPUT,47    pythoncom.INVOKE_PROPERTYPUTREF,48    pythoncom.INVOKE_FUNC,49]50 51 52def debug_print(*args):53    if debugging:54        for arg in args:55            print(arg, end=" ")56        print()57 58 59def debug_attr_print(*args):60    if debugging_attr:61        for arg in args:62            print(arg, end=" ")63        print()64 65 66def MakeMethod(func, inst, cls):67    return types.MethodType(func, inst)68 69 70# get the type objects for IDispatch and IUnknown71PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]72PyIUnknownType = pythoncom.TypeIIDs[pythoncom.IID_IUnknown]73 74_GoodDispatchTypes = (str, IIDType)75_defaultDispatchItem = build.DispatchItem76 77 78def _GetGoodDispatch(IDispatch, clsctx=pythoncom.CLSCTX_SERVER):79    # quick return for most common case80    if isinstance(IDispatch, PyIDispatchType):81        return IDispatch82    if isinstance(IDispatch, _GoodDispatchTypes):83        try:84            IDispatch = pythoncom.connect(IDispatch)85        except pythoncom.ole_error:86            IDispatch = pythoncom.CoCreateInstance(87                IDispatch, None, clsctx, pythoncom.IID_IDispatch88            )89    else:90        # may already be a wrapped class.91        IDispatch = getattr(IDispatch, "_oleobj_", IDispatch)92    return IDispatch93 94 95def _GetGoodDispatchAndUserName(IDispatch, userName, clsctx):96    # Get a dispatch object, and a 'user name' (ie, the name as97    # displayed to the user in repr() etc.98    if userName is None:99        if isinstance(IDispatch, str):100            userName = IDispatch101        ## ??? else userName remains None ???102    else:103        userName = str(userName)104    return (_GetGoodDispatch(IDispatch, clsctx), userName)105 106 107def _GetDescInvokeType(entry, invoke_type):108    # determine the wFlags argument passed as input to IDispatch::Invoke109    # Only ever called by __getattr__ and __setattr__ from dynamic objects!110    # * `entry` is a MapEntry with whatever typeinfo we have about the property we are getting/setting.111    # * `invoke_type` is either INVOKE_PROPERTYGET | INVOKE_PROPERTYSET and really just112    #   means "called by __getattr__" or "called by __setattr__"113    if not entry or not entry.desc:114        return invoke_type115 116    if entry.desc.desckind == pythoncom.DESCKIND_VARDESC:117        return invoke_type118 119    # So it's a FUNCDESC - just use what it specifies.120    return entry.desc.invkind121 122 123def Dispatch(124    IDispatch,125    userName=None,126    createClass=None,127    typeinfo=None,128    UnicodeToString=None,129    clsctx=pythoncom.CLSCTX_SERVER,130):131    assert UnicodeToString is None, "this is deprecated and will go away"132    IDispatch, userName = _GetGoodDispatchAndUserName(IDispatch, userName, clsctx)133    if createClass is None:134        createClass = CDispatch135    lazydata = None136    try:137        if typeinfo is None:138            typeinfo = IDispatch.GetTypeInfo()139        if typeinfo is not None:140            try:141                # try for a typecomp142                typecomp = typeinfo.GetTypeComp()143                lazydata = typeinfo, typecomp144            except pythoncom.com_error:145                pass146    except pythoncom.com_error:147        typeinfo = None148    olerepr = MakeOleRepr(IDispatch, typeinfo, lazydata)149    return createClass(IDispatch, olerepr, userName, lazydata=lazydata)150 151 152def MakeOleRepr(IDispatch, typeinfo, typecomp):153    olerepr = None154    if typeinfo is not None:155        try:156            attr = typeinfo.GetTypeAttr()157            # If the type info is a special DUAL interface, magically turn it into158            # a DISPATCH typeinfo.159            if (160                attr[5] == pythoncom.TKIND_INTERFACE161                and attr[11] & pythoncom.TYPEFLAG_FDUAL162            ):163                # Get corresponding Disp interface;164                # -1 is a special value which does this for us.165                href = typeinfo.GetRefTypeOfImplType(-1)166                typeinfo = typeinfo.GetRefTypeInfo(href)167                attr = typeinfo.GetTypeAttr()168            if typecomp is None:169                olerepr = build.DispatchItem(typeinfo, attr, None, 0)170            else:171                olerepr = build.LazyDispatchItem(attr, None)172        except pythoncom.ole_error:173            pass174    if olerepr is None:175        olerepr = build.DispatchItem()176    return olerepr177 178 179def DumbDispatch(180    IDispatch,181    userName=None,182    createClass=None,183    UnicodeToString=None,184    clsctx=pythoncom.CLSCTX_SERVER,185):186    "Dispatch with no type info"187    assert UnicodeToString is None, "this is deprecated and will go away"188    IDispatch, userName = _GetGoodDispatchAndUserName(IDispatch, userName, clsctx)189    if createClass is None:190        createClass = CDispatch191    return createClass(IDispatch, build.DispatchItem(), userName)192 193 194class CDispatch:195    def __init__(196        self, IDispatch, olerepr, userName=None, UnicodeToString=None, lazydata=None197    ):198        assert UnicodeToString is None, "this is deprecated and will go away"199        if userName is None:200            userName = "<unknown>"201        self.__dict__["_oleobj_"] = IDispatch202        self.__dict__["_username_"] = userName203        self.__dict__["_olerepr_"] = olerepr204        self.__dict__["_mapCachedItems_"] = {}205        self.__dict__["_builtMethods_"] = {}206        self.__dict__["_enum_"] = None207        self.__dict__["_unicode_to_string_"] = None208        self.__dict__["_lazydata_"] = lazydata209 210    def __call__(self, *args):211        "Provide 'default dispatch' COM functionality - allow instance to be called"212        if self._olerepr_.defaultDispatchName:213            invkind, dispid = self._find_dispatch_type_(214                self._olerepr_.defaultDispatchName215            )216        else:217            invkind, dispid = (218                pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET,219                pythoncom.DISPID_VALUE,220            )221        if invkind is not None:222            allArgs = (dispid, LCID, invkind, 1) + args223            return self._get_good_object_(224                self._oleobj_.Invoke(*allArgs), self._olerepr_.defaultDispatchName, None225            )226        raise TypeError("This dispatch object does not define a default method")227 228    def __bool__(self):229        return True  # ie "if object:" should always be "true" - without this, __len__ is tried.230        # _Possibly_ want to defer to __len__ if available, but Im not sure this is231        # desirable???232 233    def __repr__(self):234        return "<COMObject %s>" % (self._username_)235 236    def __str__(self):237        # __str__ is used when the user does "print object", so we gracefully238        # fall back to the __repr__ if the object has no default method.239        try:240            return str(self.__call__())241        except pythoncom.com_error as details:242            if details.hresult not in ERRORS_BAD_CONTEXT:243                raise244            return self.__repr__()245 246    def __dir__(self):247        lst = list(self.__dict__.keys()) + dir(self.__class__) + self._dir_ole_()248        try:249            lst += [p.Name for p in self.Properties_]250        except AttributeError:251            pass252        return list(set(lst))253 254    def _dir_ole_(self):255        items_dict = {}256        for iTI in range(0, self._oleobj_.GetTypeInfoCount()):257            typeInfo = self._oleobj_.GetTypeInfo(iTI)258            self._UpdateWithITypeInfo_(items_dict, typeInfo)259        return list(items_dict.keys())260 261    def _UpdateWithITypeInfo_(self, items_dict, typeInfo):262        typeInfos = [typeInfo]263        # suppress IDispatch and IUnknown methods264        inspectedIIDs = {pythoncom.IID_IDispatch: None}265 266        while len(typeInfos) > 0:267            typeInfo = typeInfos.pop()268            typeAttr = typeInfo.GetTypeAttr()269 270            if typeAttr.iid not in inspectedIIDs:271                inspectedIIDs[typeAttr.iid] = None272                for iFun in range(0, typeAttr.cFuncs):273                    funDesc = typeInfo.GetFuncDesc(iFun)274                    funName = typeInfo.GetNames(funDesc.memid)[0]275                    if funName not in items_dict:276                        items_dict[funName] = None277 278                # Inspect the type info of all implemented types279                # E.g. IShellDispatch5 implements IShellDispatch4 which implements IShellDispatch3 ...280                for iImplType in range(0, typeAttr.cImplTypes):281                    iRefType = typeInfo.GetRefTypeOfImplType(iImplType)282                    refTypeInfo = typeInfo.GetRefTypeInfo(iRefType)283                    typeInfos.append(refTypeInfo)284 285    # Delegate comparison to the oleobjs, as they know how to do identity.286    def __eq__(self, other):287        other = getattr(other, "_oleobj_", other)288        return self._oleobj_ == other289 290    def __ne__(self, other):291        other = getattr(other, "_oleobj_", other)292        return self._oleobj_ != other293 294    def __int__(self):295        return int(self.__call__())296 297    def __len__(self):298        invkind, dispid = self._find_dispatch_type_("Count")299        if invkind:300            return self._oleobj_.Invoke(dispid, LCID, invkind, 1)301        raise TypeError("This dispatch object does not define a Count method")302 303    def _NewEnum(self):304        try:305            invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET306            enum = self._oleobj_.InvokeTypes(307                pythoncom.DISPID_NEWENUM, LCID, invkind, (13, 10), ()308            )309        except pythoncom.com_error:310            return None  # no enumerator for this object.311        from . import util312 313        return util.WrapEnum(enum, None)314 315    def __getitem__(self, index):  # syver modified316        # Improved __getitem__ courtesy Syver Enstad317        # Must check _NewEnum before Item, to ensure b/w compat.318        if isinstance(index, int):319            if self.__dict__["_enum_"] is None:320                self.__dict__["_enum_"] = self._NewEnum()321            if self.__dict__["_enum_"] is not None:322                return self._get_good_object_(self._enum_.__getitem__(index))323        # See if we have an "Item" method/property we can use (goes hand in hand with Count() above!)324        invkind, dispid = self._find_dispatch_type_("Item")325        if invkind is not None:326            return self._get_good_object_(327                self._oleobj_.Invoke(dispid, LCID, invkind, 1, index)328            )329        raise TypeError("This object does not support enumeration")330 331    def __setitem__(self, index, *args):332        # XXX - todo - We should support calling Item() here too!333        # 		print "__setitem__ with", index, args334        if self._olerepr_.defaultDispatchName:335            invkind, dispid = self._find_dispatch_type_(336                self._olerepr_.defaultDispatchName337            )338        else:339            invkind, dispid = (340                pythoncom.DISPATCH_PROPERTYPUT | pythoncom.DISPATCH_PROPERTYPUTREF,341                pythoncom.DISPID_VALUE,342            )343        if invkind is not None:344            allArgs = (dispid, LCID, invkind, 0, index) + args345            return self._get_good_object_(346                self._oleobj_.Invoke(*allArgs), self._olerepr_.defaultDispatchName, None347            )348        raise TypeError("This dispatch object does not define a default method")349 350    def _find_dispatch_type_(self, methodName):351        if methodName in self._olerepr_.mapFuncs:352            item = self._olerepr_.mapFuncs[methodName]353            return item.desc[4], item.dispid354 355        if methodName in self._olerepr_.propMapGet:356            item = self._olerepr_.propMapGet[methodName]357            return item.desc[4], item.dispid358 359        try:360            dispid = self._oleobj_.GetIDsOfNames(0, methodName)361        except:  ### what error?362            return None, None363        return pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET, dispid364 365    def _ApplyTypes_(self, dispid, wFlags, retType, argTypes, user, resultCLSID, *args):366        result = self._oleobj_.InvokeTypes(367            *(dispid, LCID, wFlags, retType, argTypes) + args368        )369        return self._get_good_object_(result, user, resultCLSID)370 371    def _wrap_dispatch_(372        self, ob, userName=None, returnCLSID=None, UnicodeToString=None373    ):374        # Given a dispatch object, wrap it in a class375        assert UnicodeToString is None, "this is deprecated and will go away"376        return Dispatch(ob, userName)377 378    def _get_good_single_object_(self, ob, userName=None, ReturnCLSID=None):379        if isinstance(ob, PyIDispatchType):380            # make a new instance of (probably this) class.381            return self._wrap_dispatch_(ob, userName, ReturnCLSID)382        if isinstance(ob, PyIUnknownType):383            try:384                ob = ob.QueryInterface(pythoncom.IID_IDispatch)385            except pythoncom.com_error:386                # It is an IUnknown, but not an IDispatch, so just let it through.387                return ob388            return self._wrap_dispatch_(ob, userName, ReturnCLSID)389        return ob390 391    def _get_good_object_(self, ob, userName=None, ReturnCLSID=None):392        """Given an object (usually the retval from a method), make it a good object to return.393        Basically checks if it is a COM object, and wraps it up.394        Also handles the fact that a retval may be a tuple of retvals"""395        if ob is None:  # Quick exit!396            return None397        elif isinstance(ob, tuple):398            return tuple(399                map(400                    lambda o, s=self, oun=userName, rc=ReturnCLSID: s._get_good_single_object_(401                        o, oun, rc402                    ),403                    ob,404                )405            )406        else:407            return self._get_good_single_object_(ob)408 409    def _make_method_(self, name):410        "Make a method object - Assumes in olerepr funcmap"411        methodName = build.MakePublicAttributeName(name)  # translate keywords etc.412        methodCodeList = self._olerepr_.MakeFuncMethod(413            self._olerepr_.mapFuncs[name], methodName, 0414        )415        methodCode = "\n".join(methodCodeList)416        try:417            # 			print "Method code for %s is:\n" % self._username_, methodCode418            # 			self._print_details_()419            codeObject = compile(methodCode, "<COMObject %s>" % self._username_, "exec")420            # Exec the code object421            tempNameSpace = {}422            # "Dispatch" in the exec'd code is win32com.client.Dispatch, not ours.423            globNameSpace = globals().copy()424            globNameSpace["Dispatch"] = win32com.client.Dispatch425            exec(426                codeObject, globNameSpace, tempNameSpace427            )  # self.__dict__, self.__dict__428            name = methodName429            # Save the function in map.430            fn = self._builtMethods_[name] = tempNameSpace[name]431            newMeth = MakeMethod(fn, self, self.__class__)432            return newMeth433        except:434            debug_print("Error building OLE definition for code ", methodCode)435            traceback.print_exc()436        return None437 438    def _Release_(self):439        """Cleanup object - like a close - to force cleanup when you dont440        want to rely on Python's reference counting."""441        for childCont in self._mapCachedItems_.values():442            childCont._Release_()443        self._mapCachedItems_ = {}444        if self._oleobj_:445            self._oleobj_.Release()446            self.__dict__["_oleobj_"] = None447        if self._olerepr_:448            self.__dict__["_olerepr_"] = None449        self._enum_ = None450 451    def _proc_(self, name, *args):452        """Call the named method as a procedure, rather than function.453        Mainly used by Word.Basic, which whinges about such things."""454        try:455            item = self._olerepr_.mapFuncs[name]456            dispId = item.dispid457            return self._get_good_object_(458                self._oleobj_.Invoke(*(dispId, LCID, item.desc[4], 0) + (args))459            )460        except KeyError:461            raise AttributeError(name)462 463    def _print_details_(self):464        "Debug routine - dumps what it knows about an object."465        print("AxDispatch container", self._username_)466        try:467            print("Methods:")468            for method in self._olerepr_.mapFuncs.keys():469                print("\t", method)470            print("Props:")471            for prop, entry in self._olerepr_.propMap.items():472                print("\t%s = 0x%x - %s" % (prop, entry.dispid, repr(entry)))473            print("Get Props:")474            for prop, entry in self._olerepr_.propMapGet.items():475                print("\t%s = 0x%x - %s" % (prop, entry.dispid, repr(entry)))476            print("Put Props:")477            for prop, entry in self._olerepr_.propMapPut.items():478                print("\t%s = 0x%x - %s" % (prop, entry.dispid, repr(entry)))479        except:480            traceback.print_exc()481 482    def __LazyMap__(self, attr):483        try:484            if self._LazyAddAttr_(attr):485                debug_attr_print(486                    "%s.__LazyMap__(%s) added something" % (self._username_, attr)487                )488                return 1489        except AttributeError:490            return 0491 492    # Using the typecomp, lazily create a new attribute definition.493    def _LazyAddAttr_(self, attr):494        if self._lazydata_ is None:495            return 0496        res = 0497        typeinfo, typecomp = self._lazydata_498        olerepr = self._olerepr_499        # We need to explicitly check each invoke type individually - simply500        # specifying '0' will bind to "any member", which may not be the one501        # we are actually after (ie, we may be after prop_get, but returned502        # the info for the prop_put.)503        for i in ALL_INVOKE_TYPES:504            try:505                x, t = typecomp.Bind(attr, i)506                # Support 'Get' and 'Set' properties - see507                # bug 1587023508                if x == 0 and attr[:3] in ("Set", "Get"):509                    x, t = typecomp.Bind(attr[3:], i)510                if x == pythoncom.DESCKIND_FUNCDESC:  # it's a FUNCDESC511                    r = olerepr._AddFunc_(typeinfo, t, 0)512                elif x == pythoncom.DESCKIND_VARDESC:  # it's a VARDESC513                    r = olerepr._AddVar_(typeinfo, t, 0)514                else:  # not found or TYPEDESC/IMPLICITAPP515                    r = None516                if not r is None:517                    key, map = r[0], r[1]518                    item = map[key]519                    if map == olerepr.propMapPut:520                        olerepr._propMapPutCheck_(key, item)521                    elif map == olerepr.propMapGet:522                        olerepr._propMapGetCheck_(key, item)523                    res = 1524            except:525                pass526        return res527 528    def _FlagAsMethod(self, *methodNames):529        """Flag these attribute names as being methods.530        Some objects do not correctly differentiate methods and531        properties, leading to problems when calling these methods.532 533        Specifically, trying to say: ob.SomeFunc()534        may yield an exception "None object is not callable"535        In this case, an attempt to fetch the *property* has worked536        and returned None, rather than indicating it is really a method.537        Calling: ob._FlagAsMethod("SomeFunc")538        should then allow this to work.539        """540        for name in methodNames:541            details = build.MapEntry(self.__AttrToID__(name), (name,))542            self._olerepr_.mapFuncs[name] = details543 544    def __AttrToID__(self, attr):545        debug_attr_print(546            "Calling GetIDsOfNames for property %s in Dispatch container %s"547            % (attr, self._username_)548        )549        return self._oleobj_.GetIDsOfNames(0, attr)550 551    def __getattr__(self, attr):552        if attr == "__iter__":553            # We can't handle this as a normal method, as if the attribute554            # exists, then it must return an iterable object.555            try:556                invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET557                enum = self._oleobj_.InvokeTypes(558                    pythoncom.DISPID_NEWENUM, LCID, invkind, (13, 10), ()559                )560            except pythoncom.com_error:561                raise AttributeError("This object can not function as an iterator")562 563            # We must return a callable object.564            class Factory:565                def __init__(self, ob):566                    self.ob = ob567 568                def __call__(self):569                    import win32com.client.util570 571                    return win32com.client.util.Iterator(self.ob)572 573            return Factory(enum)574 575        if attr.startswith("_") and attr.endswith("_"):  # Fast-track.576            raise AttributeError(attr)577        # If a known method, create new instance and return.578        try:579            return MakeMethod(self._builtMethods_[attr], self, self.__class__)580        except KeyError:581            pass582        # XXX - Note that we current are case sensitive in the method.583        # debug_attr_print("GetAttr called for %s on DispatchContainer %s" % (attr,self._username_))584        # First check if it is in the method map.  Note that an actual method585        # must not yet exist, (otherwise we would not be here).  This586        # means we create the actual method object - which also means587        # this code will never be asked for that method name again.588        if attr in self._olerepr_.mapFuncs:589            return self._make_method_(attr)590 591        # Delegate to property maps/cached items592        retEntry = None593        if self._olerepr_ and self._oleobj_:594            # first check general property map, then specific "put" map.595            retEntry = self._olerepr_.propMap.get(attr)596            if retEntry is None:597                retEntry = self._olerepr_.propMapGet.get(attr)598            # Not found so far - See what COM says.599            if retEntry is None:600                try:601                    if self.__LazyMap__(attr):602                        if attr in self._olerepr_.mapFuncs:603                            return self._make_method_(attr)604                        retEntry = self._olerepr_.propMap.get(attr)605                        if retEntry is None:606                            retEntry = self._olerepr_.propMapGet.get(attr)607                    if retEntry is None:608                        retEntry = build.MapEntry(self.__AttrToID__(attr), (attr,))609                except pythoncom.ole_error:610                    pass  # No prop by that name - retEntry remains None.611 612        if retEntry is not None:  # see if in my cache613            try:614                ret = self._mapCachedItems_[retEntry.dispid]615                debug_attr_print("Cached items has attribute!", ret)616                return ret617            except (KeyError, AttributeError):618                debug_attr_print("Attribute %s not in cache" % attr)619 620        # If we are still here, and have a retEntry, get the OLE item621        if retEntry is not None:622            invoke_type = _GetDescInvokeType(retEntry, pythoncom.INVOKE_PROPERTYGET)623            debug_attr_print(624                "Getting property Id 0x%x from OLE object" % retEntry.dispid625            )626            try:627                ret = self._oleobj_.Invoke(retEntry.dispid, 0, invoke_type, 1)628            except pythoncom.com_error as details:629                if details.hresult in ERRORS_BAD_CONTEXT:630                    # May be a method.631                    self._olerepr_.mapFuncs[attr] = retEntry632                    return self._make_method_(attr)633                raise634            debug_attr_print("OLE returned ", ret)635            return self._get_good_object_(ret)636 637        # no where else to look.638        raise AttributeError("%s.%s" % (self._username_, attr))639 640    def __setattr__(self, attr, value):641        if (642            attr in self.__dict__643        ):  # Fast-track - if already in our dict, just make the assignment.644            # XXX - should maybe check method map - if someone assigns to a method,645            # it could mean something special (not sure what, tho!)646            self.__dict__[attr] = value647            return648        # Allow property assignment.649        debug_attr_print(650            "SetAttr called for %s.%s=%s on DispatchContainer"651            % (self._username_, attr, repr(value))652        )653 654        if self._olerepr_:655            # Check the "general" property map.656            if attr in self._olerepr_.propMap:657                entry = self._olerepr_.propMap[attr]658                invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT)659                self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)660                return661            # Check the specific "put" map.662            if attr in self._olerepr_.propMapPut:663                entry = self._olerepr_.propMapPut[attr]664                invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT)665                self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)666                return667 668        # Try the OLE Object669        if self._oleobj_:670            if self.__LazyMap__(attr):671                # Check the "general" property map.672                if attr in self._olerepr_.propMap:673                    entry = self._olerepr_.propMap[attr]674                    invoke_type = _GetDescInvokeType(675                        entry, pythoncom.INVOKE_PROPERTYPUT676                    )677                    self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)678                    return679                # Check the specific "put" map.680                if attr in self._olerepr_.propMapPut:681                    entry = self._olerepr_.propMapPut[attr]682                    invoke_type = _GetDescInvokeType(683                        entry, pythoncom.INVOKE_PROPERTYPUT684                    )685                    self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)686                    return687            try:688                entry = build.MapEntry(self.__AttrToID__(attr), (attr,))689            except pythoncom.com_error:690                # No attribute of that name691                entry = None692            if entry is not None:693                try:694                    invoke_type = _GetDescInvokeType(695                        entry, pythoncom.INVOKE_PROPERTYPUT696                    )697                    self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)698                    self._olerepr_.propMap[attr] = entry699                    debug_attr_print(700                        "__setattr__ property %s (id=0x%x) in Dispatch container %s"701                        % (attr, entry.dispid, self._username_)702                    )703                    return704                except pythoncom.com_error:705                    pass706        raise AttributeError(707            "Property '%s.%s' can not be set." % (self._username_, attr)708        )709 
codekingpro/portable-devtools · Team Ai