Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
policy.py830 linesDownload Raw Back to server
1"""Policies 2 3Note that Dispatchers are now implemented in "dispatcher.py", but4are still documented here.5 6Policies7 8 A policy is an object which manages the interaction between a public 9 Python object, and COM .  In simple terms, the policy object is the 10 object which is actually called by COM, and it invokes the requested 11 method, fetches/sets the requested property, etc.  See the 12 @win32com.server.policy.CreateInstance@ method for a description of13 how a policy is specified or created.14 15 Exactly how a policy determines which underlying object method/property 16 is obtained is up to the policy.  A few policies are provided, but you 17 can build your own.  See each policy class for a description of how it 18 implements its policy.19 20 There is a policy that allows the object to specify exactly which 21 methods and properties will be exposed.  There is also a policy that 22 will dynamically expose all Python methods and properties - even those 23 added after the object has been instantiated.24 25Dispatchers26 27 A Dispatcher is a level in front of a Policy.  A dispatcher is the 28 thing which actually receives the COM calls, and passes them to the 29 policy object (which in turn somehow does something with the wrapped 30 object).31 32 It is important to note that a policy does not need to have a dispatcher.33 A dispatcher has the same interface as a policy, and simply steps in its 34 place, delegating to the real policy.  The primary use for a Dispatcher 35 is to support debugging when necessary, but without imposing overheads 36 when not (ie, by not using a dispatcher at all).37 38 There are a few dispatchers provided - "tracing" dispatchers which simply 39 prints calls and args (including a variation which uses 40 win32api.OutputDebugString), and a "debugger" dispatcher, which can 41 invoke the debugger when necessary.42 43Error Handling44 45 It is important to realise that the caller of these interfaces may46 not be Python.  Therefore, general Python exceptions and tracebacks aren't 47 much use.48 49 In general, there is an Exception class that should be raised, to allow 50 the framework to extract rich COM type error information.51 52 The general rule is that the **only** exception returned from Python COM 53 Server code should be an Exception instance.  Any other Python exception 54 should be considered an implementation bug in the server (if not, it 55 should be handled, and an appropriate Exception instance raised).  Any 56 other exception is considered "unexpected", and a dispatcher may take 57 special action (see Dispatchers above)58 59 Occasionally, the implementation will raise the policy.error error.  60 This usually means there is a problem in the implementation that the 61 Python programmer should fix.62 63 For example, if policy is asked to wrap an object which it can not 64 support (because, eg, it does not provide _public_methods_ or _dynamic_) 65 then policy.error will be raised, indicating it is a Python programmers 66 problem, rather than a COM error.67 68"""69__author__ = "Greg Stein and Mark Hammond"70 71import sys72import types73 74import pythoncom75import pywintypes76import win32api77import win32con78import winerror79 80# Import a few important constants to speed lookups.81from pythoncom import (82    DISPATCH_METHOD,83    DISPATCH_PROPERTYGET,84    DISPATCH_PROPERTYPUT,85    DISPATCH_PROPERTYPUTREF,86    DISPID_COLLECT,87    DISPID_CONSTRUCTOR,88    DISPID_DESTRUCTOR,89    DISPID_EVALUATE,90    DISPID_NEWENUM,91    DISPID_PROPERTYPUT,92    DISPID_STARTENUM,93    DISPID_UNKNOWN,94    DISPID_VALUE,95)96 97S_OK = 098 99# Few more globals to speed things.100IDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]101IUnknownType = pythoncom.TypeIIDs[pythoncom.IID_IUnknown]102 103from .exception import COMException104 105error = __name__ + " error"106 107regSpec = "CLSID\\%s\\PythonCOM"108regPolicy = "CLSID\\%s\\PythonCOMPolicy"109regDispatcher = "CLSID\\%s\\PythonCOMDispatcher"110regAddnPath = "CLSID\\%s\\PythonCOMPath"111 112 113def CreateInstance(clsid, reqIID):114    """Create a new instance of the specified IID115 116    The COM framework **always** calls this function to create a new117    instance for the specified CLSID.  This function looks up the118    registry for the name of a policy, creates the policy, and asks the119    policy to create the specified object by calling the _CreateInstance_ method.120 121    Exactly how the policy creates the instance is up to the policy.  See the122    specific policy documentation for more details.123    """124    # First see is sys.path should have something on it.125    try:126        addnPaths = win32api.RegQueryValue(127            win32con.HKEY_CLASSES_ROOT, regAddnPath % clsid128        ).split(";")129        for newPath in addnPaths:130            if newPath not in sys.path:131                sys.path.insert(0, newPath)132    except win32api.error:133        pass134    try:135        policy = win32api.RegQueryValue(win32con.HKEY_CLASSES_ROOT, regPolicy % clsid)136        policy = resolve_func(policy)137    except win32api.error:138        policy = DefaultPolicy139 140    try:141        dispatcher = win32api.RegQueryValue(142            win32con.HKEY_CLASSES_ROOT, regDispatcher % clsid143        )144        if dispatcher:145            dispatcher = resolve_func(dispatcher)146    except win32api.error:147        dispatcher = None148 149    if dispatcher:150        retObj = dispatcher(policy, None)151    else:152        retObj = policy(None)153    return retObj._CreateInstance_(clsid, reqIID)154 155 156class BasicWrapPolicy:157    """The base class of policies.158 159    Normally not used directly (use a child class, instead)160 161    This policy assumes we are wrapping another object162    as the COM server.  This supports the delegation of the core COM entry points163    to either the wrapped object, or to a child class.164 165    This policy supports the following special attributes on the wrapped object166 167    _query_interface_ -- A handler which can respond to the COM 'QueryInterface' call.168    _com_interfaces_ -- An optional list of IIDs which the interface will assume are169        valid for the object.170    _invoke_ -- A handler which can respond to the COM 'Invoke' call.  If this attribute171        is not provided, then the default policy implementation is used.  If this attribute172        does exist, it is responsible for providing all required functionality - ie, the173        policy _invoke_ method is not invoked at all (and nor are you able to call it!)174    _getidsofnames_ -- A handler which can respond to the COM 'GetIDsOfNames' call.  If this attribute175        is not provided, then the default policy implementation is used.  If this attribute176        does exist, it is responsible for providing all required functionality - ie, the177        policy _getidsofnames_ method is not invoked at all (and nor are you able to call it!)178 179    IDispatchEx functionality:180 181    _invokeex_ -- Very similar to _invoke_, except slightly different arguments are used.182        And the result is just the _real_ result (rather than the (hresult, argErr, realResult)183        tuple that _invoke_ uses.184        This is the new, prefered handler (the default _invoke_ handler simply called _invokeex_)185    _getdispid_ -- Very similar to _getidsofnames_, except slightly different arguments are used,186        and only 1 property at a time can be fetched (which is all we support in getidsofnames anyway!)187        This is the new, prefered handler (the default _invoke_ handler simply called _invokeex_)188    _getnextdispid_- uses self._name_to_dispid_ to enumerate the DISPIDs189    """190 191    def __init__(self, object):192        """Initialise the policy object193 194        Params:195 196        object -- The object to wrap.  May be None *iff* @BasicWrapPolicy._CreateInstance_@ will be197        called immediately after this to setup a brand new object198        """199        if object is not None:200            self._wrap_(object)201 202    def _CreateInstance_(self, clsid, reqIID):203        """Creates a new instance of a **wrapped** object204 205        This method looks up a "@win32com.server.policy.regSpec@" % clsid entry206        in the registry (using @DefaultPolicy@)207        """208        try:209            classSpec = win32api.RegQueryValue(210                win32con.HKEY_CLASSES_ROOT, regSpec % clsid211            )212        except win32api.error:213            raise error(214                "The object is not correctly registered - %s key can not be read"215                % (regSpec % clsid)216            )217        myob = call_func(classSpec)218        self._wrap_(myob)219        try:220            return pythoncom.WrapObject(self, reqIID)221        except pythoncom.com_error as xxx_todo_changeme:222            (hr, desc, exc, arg) = xxx_todo_changeme.args223            from win32com.util import IIDToInterfaceName224 225            desc = (226                "The object '%r' was created, but does not support the "227                "interface '%s'(%s): %s"228                % (myob, IIDToInterfaceName(reqIID), reqIID, desc)229            )230            raise pythoncom.com_error(hr, desc, exc, arg)231 232    def _wrap_(self, object):233        """Wraps up the specified object.234 235        This function keeps a reference to the passed236        object, and may interogate it to determine how to respond to COM requests, etc.237        """238        # We "clobber" certain of our own methods with ones239        # provided by the wrapped object, iff they exist.240        self._name_to_dispid_ = {}241        ob = self._obj_ = object242        if hasattr(ob, "_query_interface_"):243            self._query_interface_ = ob._query_interface_244 245        if hasattr(ob, "_invoke_"):246            self._invoke_ = ob._invoke_247 248        if hasattr(ob, "_invokeex_"):249            self._invokeex_ = ob._invokeex_250 251        if hasattr(ob, "_getidsofnames_"):252            self._getidsofnames_ = ob._getidsofnames_253 254        if hasattr(ob, "_getdispid_"):255            self._getdispid_ = ob._getdispid_256 257        # Allow for override of certain special attributes.258        if hasattr(ob, "_com_interfaces_"):259            self._com_interfaces_ = []260            # Allow interfaces to be specified by name.261            for i in ob._com_interfaces_:262                if type(i) != pywintypes.IIDType:263                    # Prolly a string!264                    if i[0] != "{":265                        i = pythoncom.InterfaceNames[i]266                    else:267                        i = pythoncom.MakeIID(i)268                self._com_interfaces_.append(i)269        else:270            self._com_interfaces_ = []271 272    # "QueryInterface" handling.273    def _QueryInterface_(self, iid):274        """The main COM entry-point for QueryInterface.275 276        This checks the _com_interfaces_ attribute and if the interface is not specified277        there, it calls the derived helper _query_interface_278        """279        if iid in self._com_interfaces_:280            return 1281        return self._query_interface_(iid)282 283    def _query_interface_(self, iid):284        """Called if the object does not provide the requested interface in _com_interfaces_,285        and does not provide a _query_interface_ handler.286 287        Returns a result to the COM framework indicating the interface is not supported.288        """289        return 0290 291    # "Invoke" handling.292    def _Invoke_(self, dispid, lcid, wFlags, args):293        """The main COM entry-point for Invoke.294 295        This calls the _invoke_ helper.296        """297        # Translate a possible string dispid to real dispid.298        if type(dispid) == type(""):299            try:300                dispid = self._name_to_dispid_[dispid.lower()]301            except KeyError:302                raise COMException(303                    scode=winerror.DISP_E_MEMBERNOTFOUND, desc="Member not found"304                )305        return self._invoke_(dispid, lcid, wFlags, args)306 307    def _invoke_(self, dispid, lcid, wFlags, args):308        # Delegates to the _invokeex_ implementation.  This allows309        # a custom policy to define _invokeex_, and automatically get _invoke_ too.310        return S_OK, -1, self._invokeex_(dispid, lcid, wFlags, args, None, None)311 312    # "GetIDsOfNames" handling.313    def _GetIDsOfNames_(self, names, lcid):314        """The main COM entry-point for GetIDsOfNames.315 316        This checks the validity of the arguments, and calls the _getidsofnames_ helper.317        """318        if len(names) > 1:319            raise COMException(320                scode=winerror.DISP_E_INVALID,321                desc="Cannot support member argument names",322            )323        return self._getidsofnames_(names, lcid)324 325    def _getidsofnames_(self, names, lcid):326        ### note: lcid is being ignored...327        return (self._getdispid_(names[0], 0),)328 329    # IDispatchEx support for policies.  Most of the IDispathEx functionality330    # by default will raise E_NOTIMPL.  Thus it is not necessary for derived331    # policies to explicitely implement all this functionality just to not implement it!332 333    def _GetDispID_(self, name, fdex):334        return self._getdispid_(name, fdex)335 336    def _getdispid_(self, name, fdex):337        try:338            ### TODO - look at the fdex flags!!!339            return self._name_to_dispid_[name.lower()]340        except KeyError:341            raise COMException(scode=winerror.DISP_E_UNKNOWNNAME)342 343    # "InvokeEx" handling.344    def _InvokeEx_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):345        """The main COM entry-point for InvokeEx.346 347        This calls the _invokeex_ helper.348        """349        # Translate a possible string dispid to real dispid.350        if type(dispid) == type(""):351            try:352                dispid = self._name_to_dispid_[dispid.lower()]353            except KeyError:354                raise COMException(355                    scode=winerror.DISP_E_MEMBERNOTFOUND, desc="Member not found"356                )357        return self._invokeex_(dispid, lcid, wFlags, args, kwargs, serviceProvider)358 359    def _invokeex_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):360        """A stub for _invokeex_ - should never be called.361 362        Simply raises an exception.363        """364        # Base classes should override this method (and not call the base)365        raise error("This class does not provide _invokeex_ semantics")366 367    def _DeleteMemberByName_(self, name, fdex):368        return self._deletememberbyname_(name, fdex)369 370    def _deletememberbyname_(self, name, fdex):371        raise COMException(scode=winerror.E_NOTIMPL)372 373    def _DeleteMemberByDispID_(self, id):374        return self._deletememberbydispid(id)375 376    def _deletememberbydispid_(self, id):377        raise COMException(scode=winerror.E_NOTIMPL)378 379    def _GetMemberProperties_(self, id, fdex):380        return self._getmemberproperties_(id, fdex)381 382    def _getmemberproperties_(self, id, fdex):383        raise COMException(scode=winerror.E_NOTIMPL)384 385    def _GetMemberName_(self, dispid):386        return self._getmembername_(dispid)387 388    def _getmembername_(self, dispid):389        raise COMException(scode=winerror.E_NOTIMPL)390 391    def _GetNextDispID_(self, fdex, dispid):392        return self._getnextdispid_(fdex, dispid)393 394    def _getnextdispid_(self, fdex, dispid):395        ids = list(self._name_to_dispid_.values())396        ids.sort()397        if DISPID_STARTENUM in ids:398            ids.remove(DISPID_STARTENUM)399        if dispid == DISPID_STARTENUM:400            return ids[0]401        else:402            try:403                return ids[ids.index(dispid) + 1]404            except ValueError:  # dispid not in list?405                raise COMException(scode=winerror.E_UNEXPECTED)406            except IndexError:  # No more items407                raise COMException(scode=winerror.S_FALSE)408 409    def _GetNameSpaceParent_(self):410        return self._getnamespaceparent()411 412    def _getnamespaceparent_(self):413        raise COMException(scode=winerror.E_NOTIMPL)414 415 416class MappedWrapPolicy(BasicWrapPolicy):417    """Wraps an object using maps to do its magic418 419    This policy wraps up a Python object, using a number of maps420    which translate from a Dispatch ID and flags, into an object to call/getattr, etc.421 422    It is the responsibility of derived classes to determine exactly how the423    maps are filled (ie, the derived classes determine the map filling policy.424 425    This policy supports the following special attributes on the wrapped object426 427    _dispid_to_func_/_dispid_to_get_/_dispid_to_put_ -- These are dictionaries428      (keyed by integer dispid, values are string attribute names) which the COM429      implementation uses when it is processing COM requests.  Note that the implementation430      uses this dictionary for its own purposes - not a copy - which means the contents of431      these dictionaries will change as the object is used.432 433    """434 435    def _wrap_(self, object):436        BasicWrapPolicy._wrap_(self, object)437        ob = self._obj_438        if hasattr(ob, "_dispid_to_func_"):439            self._dispid_to_func_ = ob._dispid_to_func_440        else:441            self._dispid_to_func_ = {}442        if hasattr(ob, "_dispid_to_get_"):443            self._dispid_to_get_ = ob._dispid_to_get_444        else:445            self._dispid_to_get_ = {}446        if hasattr(ob, "_dispid_to_put_"):447            self._dispid_to_put_ = ob._dispid_to_put_448        else:449            self._dispid_to_put_ = {}450 451    def _getmembername_(self, dispid):452        if dispid in self._dispid_to_func_:453            return self._dispid_to_func_[dispid]454        elif dispid in self._dispid_to_get_:455            return self._dispid_to_get_[dispid]456        elif dispid in self._dispid_to_put_:457            return self._dispid_to_put_[dispid]458        else:459            raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)460 461 462class DesignatedWrapPolicy(MappedWrapPolicy):463    """A policy which uses a mapping to link functions and dispid464 465     A MappedWrappedPolicy which allows the wrapped object to specify, via certain466     special named attributes, exactly which methods and properties are exposed.467 468     All a wrapped object need do is provide the special attributes, and the policy469     will handle everything else.470 471     Attributes:472 473     _public_methods_ -- Required, unless a typelib GUID is given -- A list474                  of strings, which must be the names of methods the object475                  provides.  These methods will be exposed and callable476                  from other COM hosts.477     _public_attrs_ A list of strings, which must be the names of attributes on the object.478                  These attributes will be exposed and readable and possibly writeable from other COM hosts.479     _readonly_attrs_ -- A list of strings, which must also appear in _public_attrs.  These480                  attributes will be readable, but not writable, by other COM hosts.481     _value_ -- A method that will be called if the COM host requests the "default" method482                  (ie, calls Invoke with dispid==DISPID_VALUE)483     _NewEnum -- A method that will be called if the COM host requests an enumerator on the484                  object (ie, calls Invoke with dispid==DISPID_NEWENUM.)485                  It is the responsibility of the method to ensure the returned486                  object conforms to the required Enum interface.487 488    _typelib_guid_ -- The GUID of the typelibrary with interface definitions we use.489    _typelib_version_ -- A tuple of (major, minor) with a default of 1,1490    _typelib_lcid_ -- The LCID of the typelib, default = LOCALE_USER_DEFAULT491 492     _Evaluate -- Dunno what this means, except the host has called Invoke with dispid==DISPID_EVALUATE!493                  See the COM documentation for details.494    """495 496    def _wrap_(self, ob):497        # If we have nominated universal interfaces to support, load them now498        tlb_guid = getattr(ob, "_typelib_guid_", None)499        if tlb_guid is not None:500            tlb_major, tlb_minor = getattr(ob, "_typelib_version_", (1, 0))501            tlb_lcid = getattr(ob, "_typelib_lcid_", 0)502            from win32com import universal503 504            # XXX - what if the user wants to implement interfaces from multiple505            # typelibs?506            # Filter out all 'normal' IIDs (ie, IID objects and strings starting with {507            interfaces = [508                i509                for i in getattr(ob, "_com_interfaces_", [])510                if type(i) != pywintypes.IIDType and not i.startswith("{")511            ]512            universal_data = universal.RegisterInterfaces(513                tlb_guid, tlb_lcid, tlb_major, tlb_minor, interfaces514            )515        else:516            universal_data = []517        MappedWrapPolicy._wrap_(self, ob)518        if not hasattr(ob, "_public_methods_") and not hasattr(ob, "_typelib_guid_"):519            raise error(520                "Object does not support DesignatedWrapPolicy, as it does not have either _public_methods_ or _typelib_guid_ attributes."521            )522 523        # Copy existing _dispid_to_func_ entries to _name_to_dispid_524        for dispid, name in self._dispid_to_func_.items():525            self._name_to_dispid_[name.lower()] = dispid526        for dispid, name in self._dispid_to_get_.items():527            self._name_to_dispid_[name.lower()] = dispid528        for dispid, name in self._dispid_to_put_.items():529            self._name_to_dispid_[name.lower()] = dispid530 531        # Patch up the universal stuff.532        for dispid, invkind, name in universal_data:533            self._name_to_dispid_[name.lower()] = dispid534            if invkind == DISPATCH_METHOD:535                self._dispid_to_func_[dispid] = name536            elif invkind in (DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF):537                self._dispid_to_put_[dispid] = name538            elif invkind == DISPATCH_PROPERTYGET:539                self._dispid_to_get_[dispid] = name540            else:541                raise ValueError("unexpected invkind: %d (%s)" % (invkind, name))542 543        # look for reserved methods544        if hasattr(ob, "_value_"):545            self._dispid_to_get_[DISPID_VALUE] = "_value_"546            self._dispid_to_put_[DISPID_PROPERTYPUT] = "_value_"547        if hasattr(ob, "_NewEnum"):548            self._name_to_dispid_["_newenum"] = DISPID_NEWENUM549            self._dispid_to_func_[DISPID_NEWENUM] = "_NewEnum"550        if hasattr(ob, "_Evaluate"):551            self._name_to_dispid_["_evaluate"] = DISPID_EVALUATE552            self._dispid_to_func_[DISPID_EVALUATE] = "_Evaluate"553 554        next_dispid = self._allocnextdispid(999)555        # note: funcs have precedence over attrs (install attrs first)556        if hasattr(ob, "_public_attrs_"):557            if hasattr(ob, "_readonly_attrs_"):558                readonly = ob._readonly_attrs_559            else:560                readonly = []561            for name in ob._public_attrs_:562                dispid = self._name_to_dispid_.get(name.lower())563                if dispid is None:564                    dispid = next_dispid565                    self._name_to_dispid_[name.lower()] = dispid566                    next_dispid = self._allocnextdispid(next_dispid)567                self._dispid_to_get_[dispid] = name568                if name not in readonly:569                    self._dispid_to_put_[dispid] = name570        for name in getattr(ob, "_public_methods_", []):571            dispid = self._name_to_dispid_.get(name.lower())572            if dispid is None:573                dispid = next_dispid574                self._name_to_dispid_[name.lower()] = dispid575                next_dispid = self._allocnextdispid(next_dispid)576            self._dispid_to_func_[dispid] = name577        self._typeinfos_ = None  # load these on demand.578 579    def _build_typeinfos_(self):580        # Can only ever be one for now.581        tlb_guid = getattr(self._obj_, "_typelib_guid_", None)582        if tlb_guid is None:583            return []584        tlb_major, tlb_minor = getattr(self._obj_, "_typelib_version_", (1, 0))585        tlb = pythoncom.LoadRegTypeLib(tlb_guid, tlb_major, tlb_minor)586        typecomp = tlb.GetTypeComp()587        # Not 100% sure what semantics we should use for the default interface.588        # Look for the first name in _com_interfaces_ that exists in the typelib.589        for iname in self._obj_._com_interfaces_:590            try:591                type_info, type_comp = typecomp.BindType(iname)592                if type_info is not None:593                    return [type_info]594            except pythoncom.com_error:595                pass596        return []597 598    def _GetTypeInfoCount_(self):599        if self._typeinfos_ is None:600            self._typeinfos_ = self._build_typeinfos_()601        return len(self._typeinfos_)602 603    def _GetTypeInfo_(self, index, lcid):604        if self._typeinfos_ is None:605            self._typeinfos_ = self._build_typeinfos_()606        if index < 0 or index >= len(self._typeinfos_):607            raise COMException(scode=winerror.DISP_E_BADINDEX)608        return 0, self._typeinfos_[index]609 610    def _allocnextdispid(self, last_dispid):611        while 1:612            last_dispid = last_dispid + 1613            if (614                last_dispid not in self._dispid_to_func_615                and last_dispid not in self._dispid_to_get_616                and last_dispid not in self._dispid_to_put_617            ):618                return last_dispid619 620    def _invokeex_(self, dispid, lcid, wFlags, args, kwArgs, serviceProvider):621        ### note: lcid is being ignored...622 623        if wFlags & DISPATCH_METHOD:624            try:625                funcname = self._dispid_to_func_[dispid]626            except KeyError:627                if not wFlags & DISPATCH_PROPERTYGET:628                    raise COMException(629                        scode=winerror.DISP_E_MEMBERNOTFOUND630                    )  # not found631            else:632                try:633                    func = getattr(self._obj_, funcname)634                except AttributeError:635                    # May have a dispid, but that doesnt mean we have the function!636                    raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)637                # Should check callable here638                try:639                    return func(*args)640                except TypeError as v:641                    # Particularly nasty is "wrong number of args" type error642                    # This helps you see what 'func' and 'args' actually is643                    if str(v).find("arguments") >= 0:644                        print(645                            "** TypeError %s calling function %r(%r)" % (v, func, args)646                        )647                    raise648 649        if wFlags & DISPATCH_PROPERTYGET:650            try:651                name = self._dispid_to_get_[dispid]652            except KeyError:653                raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)  # not found654            retob = getattr(self._obj_, name)655            if type(retob) == types.MethodType:  # a method as a property - call it.656                retob = retob(*args)657            return retob658 659        if wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF):  ### correct?660            try:661                name = self._dispid_to_put_[dispid]662            except KeyError:663                raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND)  # read-only664            # If we have a method of that name (ie, a property get function), and665            # we have an equiv. property set function, use that instead.666            if (667                type(getattr(self._obj_, name, None)) == types.MethodType668                and type(getattr(self._obj_, "Set" + name, None)) == types.MethodType669            ):670                fn = getattr(self._obj_, "Set" + name)671                fn(*args)672            else:673                # just set the attribute674                setattr(self._obj_, name, args[0])675            return676 677        raise COMException(scode=winerror.E_INVALIDARG, desc="invalid wFlags")678 679 680class EventHandlerPolicy(DesignatedWrapPolicy):681    """The default policy used by event handlers in the win32com.client package.682 683    In addition to the base policy, this provides argument conversion semantics for684    params685      * dispatch params are converted to dispatch objects.686      * Unicode objects are converted to strings (1.5.2 and earlier)687 688    NOTE: Later, we may allow the object to override this process??689    """690 691    def _transform_args_(self, args, kwArgs, dispid, lcid, wFlags, serviceProvider):692        ret = []693        for arg in args:694            arg_type = type(arg)695            if arg_type == IDispatchType:696                import win32com.client697 698                arg = win32com.client.Dispatch(arg)699            elif arg_type == IUnknownType:700                try:701                    import win32com.client702 703                    arg = win32com.client.Dispatch(704                        arg.QueryInterface(pythoncom.IID_IDispatch)705                    )706                except pythoncom.error:707                    pass  # Keep it as IUnknown708            ret.append(arg)709        return tuple(ret), kwArgs710 711    def _invokeex_(self, dispid, lcid, wFlags, args, kwArgs, serviceProvider):712        # transform the args.713        args, kwArgs = self._transform_args_(714            args, kwArgs, dispid, lcid, wFlags, serviceProvider715        )716        return DesignatedWrapPolicy._invokeex_(717            self, dispid, lcid, wFlags, args, kwArgs, serviceProvider718        )719 720 721class DynamicPolicy(BasicWrapPolicy):722    """A policy which dynamically (ie, at run-time) determines public interfaces.723 724    A dynamic policy is used to dynamically dispatch methods and properties to the725    wrapped object.  The list of objects and properties does not need to be known in726    advance, and methods or properties added to the wrapped object after construction727    are also handled.728 729    The wrapped object must provide the following attributes:730 731    _dynamic_ -- A method that will be called whenever an invoke on the object732           is called.  The method is called with the name of the underlying method/property733           (ie, the mapping of dispid to/from name has been resolved.)  This name property734           may also be '_value_' to indicate the default, and '_NewEnum' to indicate a new735           enumerator is requested.736 737    """738 739    def _wrap_(self, object):740        BasicWrapPolicy._wrap_(self, object)741        if not hasattr(self._obj_, "_dynamic_"):742            raise error("Object does not support Dynamic COM Policy")743        self._next_dynamic_ = self._min_dynamic_ = 1000744        self._dyn_dispid_to_name_ = {745            DISPID_VALUE: "_value_",746            DISPID_NEWENUM: "_NewEnum",747        }748 749    def _getdispid_(self, name, fdex):750        # TODO - Look at fdex flags.751        lname = name.lower()752        try:753            return self._name_to_dispid_[lname]754        except KeyError:755            dispid = self._next_dynamic_ = self._next_dynamic_ + 1756            self._name_to_dispid_[lname] = dispid757            self._dyn_dispid_to_name_[dispid] = name  # Keep case in this map...758            return dispid759 760    def _invoke_(self, dispid, lcid, wFlags, args):761        return S_OK, -1, self._invokeex_(dispid, lcid, wFlags, args, None, None)762 763    def _invokeex_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):764        ### note: lcid is being ignored...765        ### note: kwargs is being ignored...766        ### note: serviceProvider is being ignored...767        ### there might be assigned DISPID values to properties, too...768        try:769            name = self._dyn_dispid_to_name_[dispid]770        except KeyError:771            raise COMException(772                scode=winerror.DISP_E_MEMBERNOTFOUND, desc="Member not found"773            )774        return self._obj_._dynamic_(name, lcid, wFlags, args)775 776 777DefaultPolicy = DesignatedWrapPolicy778 779 780def resolve_func(spec):781    """Resolve a function by name782 783    Given a function specified by 'module.function', return a callable object784    (ie, the function itself)785    """786    try:787        idx = spec.rindex(".")788        mname = spec[:idx]789        fname = spec[idx + 1 :]790        # Dont attempt to optimize by looking in sys.modules,791        # as another thread may also be performing the import - this792        # way we take advantage of the built-in import lock.793        module = _import_module(mname)794        return getattr(module, fname)795    except ValueError:  # No "." in name - assume in this module796        return globals()[spec]797 798 799def call_func(spec, *args):800    """Call a function specified by name.801 802    Call a function specified by 'module.function' and return the result.803    """804 805    return resolve_func(spec)(*args)806 807 808def _import_module(mname):809    """Import a module just like the 'import' statement.810 811    Having this function is much nicer for importing arbitrary modules than812    using the 'exec' keyword.  It is more efficient and obvious to the reader.813    """814    __import__(mname)815    # Eeek - result of _import_ is "win32com" - not "win32com.a.b.c"816    # Get the full module from sys.modules817    return sys.modules[mname]818 819 820#######821#822# Temporary hacks until all old code moves.823#824# These have been moved to a new source file, but some code may825# still reference them here.  These will end up being removed.826try:827    from .dispatcher import DispatcherTrace, DispatcherWin32trace828except ImportError:  # Quite likely a frozen executable that doesnt need dispatchers829    pass830 
codekingpro/portable-devtools · Team Ai