|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- """Dispatcher
-
- Please see policy.py for a discussion on dispatchers and policies
- """
- import traceback
- from sys import exc_info
-
- import pythoncom
- import win32api
- import win32com
-
- #
- from win32com.server.exception import IsCOMServerException
- from win32com.util import IIDToInterfaceName
-
-
- class DispatcherBase:
- """The base class for all Dispatchers.
-
- This dispatcher supports wrapping all operations in exception handlers,
- and all the necessary delegation to the policy.
-
- This base class supports the printing of "unexpected" exceptions. Note, however,
- that exactly where the output of print goes may not be useful! A derived class may
- provide additional semantics for this.
- """
-
- def __init__(self, policyClass, object):
- self.policy = policyClass(object)
- # The logger we should dump to. If None, we should send to the
- # default location (typically 'print')
- self.logger = getattr(win32com, "logger", None)
-
- # Note the "return self._HandleException_()" is purely to stop pychecker
- # complaining - _HandleException_ will itself raise an exception for the
- # pythoncom framework, so the result will never be seen.
- def _CreateInstance_(self, clsid, reqIID):
- try:
- self.policy._CreateInstance_(clsid, reqIID)
- return pythoncom.WrapObject(self, reqIID)
- except:
- return self._HandleException_()
-
- def _QueryInterface_(self, iid):
- try:
- return self.policy._QueryInterface_(iid)
- except:
- return self._HandleException_()
-
- def _Invoke_(self, dispid, lcid, wFlags, args):
- try:
- return self.policy._Invoke_(dispid, lcid, wFlags, args)
- except:
- return self._HandleException_()
-
- def _GetIDsOfNames_(self, names, lcid):
- try:
- return self.policy._GetIDsOfNames_(names, lcid)
- except:
- return self._HandleException_()
-
- def _GetTypeInfo_(self, index, lcid):
- try:
- return self.policy._GetTypeInfo_(index, lcid)
- except:
- return self._HandleException_()
-
- def _GetTypeInfoCount_(self):
- try:
- return self.policy._GetTypeInfoCount_()
- except:
- return self._HandleException_()
-
- def _GetDispID_(self, name, fdex):
- try:
- return self.policy._GetDispID_(name, fdex)
- except:
- return self._HandleException_()
-
- def _InvokeEx_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):
- try:
- return self.policy._InvokeEx_(
- dispid, lcid, wFlags, args, kwargs, serviceProvider
- )
- except:
- return self._HandleException_()
-
- def _DeleteMemberByName_(self, name, fdex):
- try:
- return self.policy._DeleteMemberByName_(name, fdex)
- except:
- return self._HandleException_()
-
- def _DeleteMemberByDispID_(self, id):
- try:
- return self.policy._DeleteMemberByDispID_(id)
- except:
- return self._HandleException_()
-
- def _GetMemberProperties_(self, id, fdex):
- try:
- return self.policy._GetMemberProperties_(id, fdex)
- except:
- return self._HandleException_()
-
- def _GetMemberName_(self, dispid):
- try:
- return self.policy._GetMemberName_(dispid)
- except:
- return self._HandleException_()
-
- def _GetNextDispID_(self, fdex, flags):
- try:
- return self.policy._GetNextDispID_(fdex, flags)
- except:
- return self._HandleException_()
-
- def _GetNameSpaceParent_(self):
- try:
- return self.policy._GetNameSpaceParent_()
- except:
- return self._HandleException_()
-
- def _HandleException_(self):
- """Called whenever an exception is raised.
-
- Default behaviour is to print the exception.
- """
- # If not a COM exception, print it for the developer.
- if not IsCOMServerException():
- if self.logger is not None:
- self.logger.exception("pythoncom server error")
- else:
- traceback.print_exc()
- # But still raise it for the framework.
- raise
-
- def _trace_(self, *args):
- if self.logger is not None:
- record = " ".join(map(str, args))
- self.logger.debug(record)
- else:
- for arg in args[:-1]:
- print(arg, end=" ")
- print(args[-1])
-
-
- class DispatcherTrace(DispatcherBase):
- """A dispatcher, which causes a 'print' line for each COM function called."""
-
- def _QueryInterface_(self, iid):
- rc = DispatcherBase._QueryInterface_(self, iid)
- if not rc:
- self._trace_(
- "in %s._QueryInterface_ with unsupported IID %s (%s)"
- % (repr(self.policy._obj_), IIDToInterfaceName(iid), iid)
- )
- return rc
-
- def _GetIDsOfNames_(self, names, lcid):
- self._trace_("in _GetIDsOfNames_ with '%s' and '%d'\n" % (names, lcid))
- return DispatcherBase._GetIDsOfNames_(self, names, lcid)
-
- def _GetTypeInfo_(self, index, lcid):
- self._trace_("in _GetTypeInfo_ with index=%d, lcid=%d\n" % (index, lcid))
- return DispatcherBase._GetTypeInfo_(self, index, lcid)
-
- def _GetTypeInfoCount_(self):
- self._trace_("in _GetTypeInfoCount_\n")
- return DispatcherBase._GetTypeInfoCount_(self)
-
- def _Invoke_(self, dispid, lcid, wFlags, args):
- self._trace_("in _Invoke_ with", dispid, lcid, wFlags, args)
- return DispatcherBase._Invoke_(self, dispid, lcid, wFlags, args)
-
- def _GetDispID_(self, name, fdex):
- self._trace_("in _GetDispID_ with", name, fdex)
- return DispatcherBase._GetDispID_(self, name, fdex)
-
- def _InvokeEx_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):
- self._trace_(
- "in %r._InvokeEx_-%s%r [%x,%s,%r]"
- % (self.policy._obj_, dispid, args, wFlags, lcid, serviceProvider)
- )
- return DispatcherBase._InvokeEx_(
- self, dispid, lcid, wFlags, args, kwargs, serviceProvider
- )
-
- def _DeleteMemberByName_(self, name, fdex):
- self._trace_("in _DeleteMemberByName_ with", name, fdex)
- return DispatcherBase._DeleteMemberByName_(self, name, fdex)
-
- def _DeleteMemberByDispID_(self, id):
- self._trace_("in _DeleteMemberByDispID_ with", id)
- return DispatcherBase._DeleteMemberByDispID_(self, id)
-
- def _GetMemberProperties_(self, id, fdex):
- self._trace_("in _GetMemberProperties_ with", id, fdex)
- return DispatcherBase._GetMemberProperties_(self, id, fdex)
-
- def _GetMemberName_(self, dispid):
- self._trace_("in _GetMemberName_ with", dispid)
- return DispatcherBase._GetMemberName_(self, dispid)
-
- def _GetNextDispID_(self, fdex, flags):
- self._trace_("in _GetNextDispID_ with", fdex, flags)
- return DispatcherBase._GetNextDispID_(self, fdex, flags)
-
- def _GetNameSpaceParent_(self):
- self._trace_("in _GetNameSpaceParent_")
- return DispatcherBase._GetNameSpaceParent_(self)
-
-
- class DispatcherWin32trace(DispatcherTrace):
- """A tracing dispatcher that sends its output to the win32trace remote collector."""
-
- def __init__(self, policyClass, object):
- DispatcherTrace.__init__(self, policyClass, object)
- if self.logger is None:
- # If we have no logger, setup our output.
- import win32traceutil # Sets up everything.
- self._trace_(
- "Object with win32trace dispatcher created (object=%s)" % repr(object)
- )
-
-
- class DispatcherOutputDebugString(DispatcherTrace):
- """A tracing dispatcher that sends its output to win32api.OutputDebugString"""
-
- def _trace_(self, *args):
- for arg in args[:-1]:
- win32api.OutputDebugString(str(arg) + " ")
- win32api.OutputDebugString(str(args[-1]) + "\n")
-
-
- class DispatcherWin32dbg(DispatcherBase):
- """A source-level debugger dispatcher
-
- A dispatcher which invokes the debugger as an object is instantiated, or
- when an unexpected exception occurs.
-
- Requires Pythonwin.
- """
-
- def __init__(self, policyClass, ob):
- # No one uses this, and it just causes py2exe to drag all of
- # pythonwin in.
- # import pywin.debugger
- pywin.debugger.brk()
- print("The DispatcherWin32dbg dispatcher is deprecated!")
- print("Please let me know if this is a problem.")
- print("Uncomment the relevant lines in dispatcher.py to re-enable")
- # DEBUGGER Note - You can either:
- # * Hit Run and wait for a (non Exception class) exception to occur!
- # * Set a breakpoint and hit run.
- # * Step into the object creation (a few steps away!)
- DispatcherBase.__init__(self, policyClass, ob)
-
- def _HandleException_(self):
- """Invoke the debugger post mortem capability"""
- # Save details away.
- typ, val, tb = exc_info()
- # import pywin.debugger, pywin.debugger.dbgcon
- debug = 0
- try:
- raise typ(val)
- except Exception: # AARG - What is this Exception???
- # Use some inside knowledge to borrow a Debugger option which dictates if we
- # stop at "expected" exceptions.
- debug = pywin.debugger.GetDebugger().get_option(
- pywin.debugger.dbgcon.OPT_STOP_EXCEPTIONS
- )
- except:
- debug = 1
- if debug:
- try:
- pywin.debugger.post_mortem(tb, typ, val) # The original exception
- except:
- traceback.print_exc()
-
- # But still raise it.
- del tb
- raise
-
-
- try:
- import win32trace
-
- DefaultDebugDispatcher = DispatcherWin32trace
- except ImportError: # no win32trace module - just use a print based one.
- DefaultDebugDispatcher = DispatcherTrace
|