"""dynamic dispatch objects for AX Script. This is an IDispatch object that a scripting host may use to query and invoke methods on the main script. Not may hosts use this yet, so it is not well tested! """ import winerror import types from win32com.server.exception import COMException import win32com.server.policy import win32com.server.util from win32com.client import Dispatch import pythoncom from win32com.axscript import axscript debugging = 0 PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch] def _is_callable(obj): return type(obj) in [types.FunctionType, types.MethodType] # ignore hasattr(obj, "__call__") as this means all COM objects! class ScriptDispatch: _public_methods_ = [] def __init__(self, engine, scriptNamespace): self.engine = engine self.scriptNamespace = scriptNamespace def _dynamic_(self, name, lcid, wFlags, args): # Ensure any newly added items are available. self.engine.RegisterNewNamedItems() self.engine.ProcessNewNamedItemsConnections() if wFlags & pythoncom.INVOKE_FUNC: # attempt to call a function try: func = getattr(self.scriptNamespace, name) if not _is_callable(func): raise AttributeError(name) # Not a function. realArgs = [] for arg in args: if type(arg)==PyIDispatchType: realArgs.append(Dispatch(arg)) else: realArgs.append(arg) try: # xxx - todo - work out what code block to pass??? return self.engine.ApplyInScriptedSection(None, func, tuple(realArgs)) except COMException as xxx_todo_changeme: (hr, msg, exc, arg) = xxx_todo_changeme.args raise except AttributeError: if not wFlags & pythoncom.DISPATCH_PROPERTYGET: raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND) if wFlags & pythoncom.DISPATCH_PROPERTYGET: # attempt to get a property try: ret = getattr(self.scriptNamespace, name) if _is_callable(ret): raise AttributeError(name) # Not a property. except AttributeError: raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND) except COMException as instance: raise except: ret = self.engine.HandleException() return ret raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND) class StrictDynamicPolicy(win32com.server.policy.DynamicPolicy): def _wrap_(self, object): win32com.server.policy.DynamicPolicy._wrap_(self, object) if hasattr(self._obj_, 'scriptNamespace'): for name in dir(self._obj_.scriptNamespace): self._dyn_dispid_to_name_[self._getdispid_(name,0)] = name def _getmembername_(self, dispid): try: return str(self._dyn_dispid_to_name_[dispid]) except KeyError: raise COMException(scode=winerror.DISP_E_UNKNOWNNAME, desc="Name not found") def _getdispid_(self, name, fdex): try: func = getattr(self._obj_.scriptNamespace, str(name)) except AttributeError: raise COMException(scode=winerror.DISP_E_MEMBERNOTFOUND) # if not _is_callable(func): return win32com.server.policy.DynamicPolicy._getdispid_(self, name, fdex) def _wrap_debug(obj): return win32com.server.util.wrap(obj, usePolicy=StrictDynamicPolicy, useDispatcher=win32com.server.policy.DispatcherWin32trace) def _wrap_nodebug(obj): return win32com.server.util.wrap(obj, usePolicy=StrictDynamicPolicy) if debugging: _wrap = _wrap_debug else: _wrap = _wrap_nodebug def MakeScriptDispatch(engine, namespace): return _wrap(ScriptDispatch(engine, namespace))