debug.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import traceback, sys, string
  2. import win32com.server.util
  3. from win32com.util import IIDToInterfaceName
  4. from win32com.client.util import Enumerator
  5. from win32com.server.exception import COMException
  6. import pythoncom
  7. from .framework import trace
  8. from win32com.axdebug import axdebug, gateways, contexts, stackframe, documents, adb
  9. from win32com.axdebug.codecontainer import SourceCodeContainer
  10. from win32com.axdebug.util import _wrap, _wrap_remove
  11. import win32com.client.connect
  12. import win32api, winerror
  13. import os
  14. try:
  15. os.environ["DEBUG_AXDEBUG"]
  16. debuggingTrace = 1 # Should we print "trace" output?
  17. except KeyError:
  18. debuggingTrace = 0
  19. def trace(*args):
  20. """A function used instead of "print" for debugging output.
  21. """
  22. if not debuggingTrace:
  23. return
  24. print(win32api.GetCurrentThreadId(), end=' ')
  25. for arg in args:
  26. print(arg, end=' ')
  27. print()
  28. # Note that the DebugManager is not a COM gateway class for the
  29. # debugger - but it does create and manage them.
  30. class DebugManager:
  31. _debugger_interfaces_ = [axdebug.IID_IActiveScriptDebug]
  32. def __init__(self, scriptEngine):
  33. self.scriptEngine = scriptEngine
  34. self.adb = adb.Debugger()
  35. self.rootNode = None
  36. self.debugApplication = None
  37. self.ccProvider = documents.CodeContainerProvider()
  38. try:
  39. self.scriptSiteDebug = scriptEngine.GetScriptSite(axdebug.IID_IActiveScriptSiteDebug)
  40. except pythoncom.com_error:
  41. # No debugger interface (ie, dumb host). Do the extra work.
  42. trace("Scripting site has no debugger interface")
  43. self.scriptSiteDebug = None
  44. # Get the debug application object.
  45. self.debugApplication = None
  46. if self.scriptSiteDebug is not None:
  47. # Spec says that we should test for this, and if it fails revert to
  48. # PDM application.
  49. try:
  50. self.debugApplication = self.scriptSiteDebug.GetApplication()
  51. self.rootNode = self.scriptSiteDebug.GetRootApplicationNode()
  52. except pythoncom.com_error:
  53. self.debugApplication = None
  54. if self.debugApplication is None:
  55. # Try to get/create the default one
  56. # NOTE - Dont catch exceptions here - let the parent do it,
  57. # so it knows debug support is available.
  58. pdm=pythoncom.CoCreateInstance(axdebug.CLSID_ProcessDebugManager,None,pythoncom.CLSCTX_ALL, axdebug.IID_IProcessDebugManager)
  59. self.debugApplication = pdm.GetDefaultApplication()
  60. self.rootNode = self.debugApplication.GetRootNode()
  61. assert self.debugApplication is not None, "Need to have a DebugApplication object by now!"
  62. self.activeScriptDebug = None
  63. if self.debugApplication is not None:
  64. self.adb.AttachApp(self.debugApplication, self.ccProvider)
  65. self.codeContainers = {}
  66. self.activeScriptDebug = _wrap(ActiveScriptDebug(self, self.codeContainers), axdebug.IID_IActiveScriptDebug)
  67. def Close(self):
  68. # Called by the language engine when it receives a close request
  69. if self.activeScriptDebug is not None:
  70. _wrap_remove(self.activeScriptDebug)
  71. self.activeScriptDebug = None
  72. self.scriptEngine = None
  73. self.rootNode = None
  74. self.debugApplication = None
  75. self.scriptSiteDebug = None
  76. if self.ccProvider is not None:
  77. self.ccProvider.Close()
  78. self.ccProvider = None
  79. self.codeContainers = {}
  80. if self.adb:
  81. self.adb.CloseApp()
  82. self.adb = None
  83. # print "Close complete"
  84. def IsAnyHost(self):
  85. "Do we have _any_ debugging interfaces installed?"
  86. return self.debugApplication is not None
  87. def IsSimpleHost(self):
  88. return self.scriptSiteDebug is None
  89. def HandleRuntimeError( self ):
  90. """Called by the engine when a runtime error occurs. If we have a debugger,
  91. we let it know.
  92. The result is a boolean which indicates if the error handler should call
  93. IActiveScriptSite::OnScriptError()
  94. """
  95. # if self.IsAnyHost:
  96. # site = _wrap(self, axdebug.IID_IActiveScriptSite)
  97. # breakResume, errorResume, fCallOnError = self.debugApplication(activeScriptErrorDebug, site)
  98. # Do something with these!
  99. # else:
  100. trace("HandleRuntimeError")
  101. fCallOnError = 1
  102. return fCallOnError
  103. def _query_interface_for_debugger_(self, iid):
  104. if iid in self._debugger_interfaces_:
  105. return self.activeScriptDebug
  106. trace("DebugManager QI - unknown IID", iid)
  107. return 0
  108. def OnEnterScript(self):
  109. trace("OnEnterScript")
  110. try:
  111. 1/0
  112. except:
  113. # Bit of a hack - reach into engine.
  114. baseFrame = sys.exc_info()[2].tb_frame.f_back
  115. self.adb.SetupAXDebugging(baseFrame)
  116. def OnLeaveScript(self):
  117. trace("OnLeaveScript")
  118. self.adb.ResetAXDebugging()
  119. def AddScriptBlock(self, codeBlock):
  120. # If we dont have debugging support, dont bother.
  121. cc = DebugCodeBlockContainer(codeBlock, self.scriptSiteDebug)
  122. if self.IsSimpleHost():
  123. document = documents.DebugDocumentText(cc)
  124. document = _wrap(document, axdebug.IID_IDebugDocument)
  125. provider = documents.DebugDocumentProvider(document)
  126. provider = _wrap(provider, axdebug.IID_IDebugDocumentProvider)
  127. cc.debugDocument = document
  128. newNode = self.debugApplication.CreateApplicationNode()
  129. newNode.SetDocumentProvider(provider)
  130. newNode.Attach(self.rootNode)
  131. else:
  132. newNode = None # Managed by smart host.
  133. self.codeContainers[cc.sourceContext] = cc
  134. self.ccProvider.AddCodeContainer(cc, newNode)
  135. class DebugCodeBlockContainer(SourceCodeContainer):
  136. def __init__(self, codeBlock, site):
  137. self.codeBlock = codeBlock
  138. SourceCodeContainer.__init__(self, codeBlock.codeText, codeBlock.GetFileName(), codeBlock.sourceContextCookie, codeBlock.startLineNumber, site)
  139. def GetName(self, dnt):
  140. if dnt==axdebug.DOCUMENTNAMETYPE_APPNODE:
  141. return self.codeBlock.GetDisplayName()
  142. elif dnt==axdebug.DOCUMENTNAMETYPE_TITLE:
  143. return self.codeBlock.GetDisplayName()
  144. # elif dnt==axdebug.DOCUMENTNAMETYPE_FILE_TAIL:
  145. # elif dnt==axdebug.DOCUMENTNAMETYPE_URL:
  146. else:
  147. raise COMException(scode=winerror.S_FALSE)
  148. class EnumDebugCodeContexts(gateways.EnumDebugCodeContexts):
  149. def _wrap(self, ob):
  150. return ob
  151. class ActiveScriptDebug:
  152. """The class which implements the IActiveScriptDebug interface for the Active Script engine.
  153. Only ever used by smart hosts.
  154. """
  155. _public_methods_ = ["GetScriptTextAttributes", "GetScriptletTextAttributes", "EnumCodeContextsOfPosition"]
  156. _com_interfaces_ = [axdebug.IID_IActiveScriptDebug]
  157. def __init__(self, debugMgr, codeContainers):
  158. self.debugMgr = debugMgr
  159. self.scriptSiteDebug = debugMgr.scriptSiteDebug
  160. self.codeContainers = codeContainers
  161. def _Close(self):
  162. self.debugMgr = None
  163. self.scriptSiteDebug = None
  164. self.codeContainers = {}
  165. def _query_interface_(self, iid):
  166. trace("DebuggerQI with", iid)
  167. return _wrap(self.debugMgr.scriptEngine, iid)
  168. def GetScriptTextAttributes(self, code, delim, flags):
  169. container = SourceCodeContainer(code, "<Temp Code Block>")
  170. return container.GetSyntaxColorAttributes()
  171. def GetScriptletTextAttributes(self, code, delim, flags):
  172. trace ("GetScriptletTextAttributes", code, delim, flags)
  173. container = SourceCodeContainer(code, "<Temp Code Block>")
  174. return container.GetSyntaxColorAttributes()
  175. def EnumCodeContextsOfPosition(self, context, charOffset, numChars):
  176. trace("EnumCodeContextsOfPosition", context, charOffset, numChars)
  177. try:
  178. context = self.codeContainers[context].GetCodeContextAtPosition(charOffset)
  179. except KeyError:
  180. raise COMException(scode=winerror.E_UNEXPECTED)
  181. enum = EnumDebugCodeContexts([context])
  182. return _wrap(enum, axdebug.IID_IEnumDebugCodeContexts)