分类: C/C++
2008-09-11 10:57:21
Stuart Lodge () February 5, 1999 |
This article follows on from the Active Script Hosting discussions of Andrew Garbuzov. Before you start on adding debugger support to your active script it's probably a good idea to have active scripts up and running.... Introduction
Whitepaper: Integrating Telephony Services into .NET Applications
Sponsored by Avaya
Learn how developers using Microsoft's .NET framework can use SIP Objects.NET to gain simple and flexible access to telephony networks. SIP Objects.NET enables developers to access a wide variety of enterprise or traditional carrier networks by leveraging technologies such as Avaya's SIP Application Server. »
Whitepaper: SIP—Creating Next-Generation Telecom Applications
Sponsored by Avaya
Developing applications to run on a telecommunications network has never been easier with Internet-based standards such as the Session Initiation Protocol (SIP). Combined with the power and simplicity of Java technology in the form of the SIP Servlet API, an application developer can create and deploy new services to users in a fraction of the time it previously took. »
Whitepaper: Event Driven Architectures in the Responsive Enterprise
Sponsored by Avaya
This whitepaper introduces the concept of Event Driven Architecture (EDA) and describes the key role it plays in enabling new business strategies for Communications Enabled Business Processes. Learn more. Download this whitepaper.»
Whitepaper: Developing Contact Center Telecom Applications
Sponsored by Avaya
SIP servlets make developing applications for telecommunications networks easier than ever before. Learn just how easy it is to create a basic telecommunications application using SIP servlets. The use of open standards such as SIP, together with Java programming, has radically simplified the task of creating complex applications. »
To experiment with the debugging interfaces, you will need an Active Script debugger installed like the IE4 one available from
A reference for the Active Script debugging interfaces was once provided in the online reference but this now seems to have been moved off the Microsoft site. Even with this documentation, implementing script debugging is far from trivial and the main aim of this article is to give you a working sample to play with.
Warning - Because the Active Script Debugging interfaces do not seem to be fully documented yet by Microsoft - in particular they have not provided any header files or type libraries, the sample project attached to this article includes a hand built header file, activscp_plus.h, which should be replaced with an offical MS version as soon as they provide one.
Before you start please
and also have the Microsoft Active Script Engines and the IE4 debugger installed.To view the debugger in action:
BroCon.Navigate " MsgBox "Hello World" Sub AButton_OnClick() MsgBox "Button A" End Sub Sub BButton_OnClick() MsgBox "Button B" End Sub
Note: Microsoft have set up the script debugging so that Visual Interdev will always be used in preference to the IE4 debugger. If you have Visual Interdev installed then you can attach to the script using "Debug|Processes" and then choosing the process "mfcaxsrvb.exe" in the dialog. The Interdev debugger gices you the benefits of watchpoints and a watch window, a "Set Next Statement" command, and generally better editing facilites.
To add debugging support to an Active Script Host, you need to perform the following steps:
1. Before you initialise any of the IActiveScript classes, manually create an IProcessDebugManager - this manager will control the debug process for you.
// Initialise the pdm hr = CoCreateInstance(CLSID_ProcessDebugManager, NULL, CLSCTX_INPROC_SERVER | /*CLSCTX_INPROC_HANLDER | */CLSCTX_LOCAL_SERVER, IID_IProcessDebugManager, (void**)&m_pdm);
2. Manually create an IDebugApplication, set its name and then add this application to the process manager.
hr = m_pdm->CreateApplication(&m_pDebugApp); if (!SUCCEEDED(hr)) { // .... } ASSERT(m_pDebugApp); hr = m_pDebugApp->SetName(L"MFC Scripting Application"); if (!SUCCEEDED(hr)) { // .... } hr = m_pdm->AddApplication(m_pDebugApp, &m_dwAppCookie); if (!SUCCEEDED(hr)) { // .... }
3. For each document (normally each script) you wish to run, create an IDebugDocumentHelper to wrap the document. Define the short and long names of the document and attach the document to your application
hr = m_pdm->CreateDebugDocumentHelper(NULL, &m_pDebugDocHelper); if (!SUCCEEDED(hr)) { // ... } hr = m_pDebugDocHelper->Init(m_pDebugApp, L"Doc Name", L"Long Doc Name", TEXT_DOC_ATTR_READONLY); if (!SUCCEEDED(hr)) { // ... } hr = m_pDebugDocHelper->Attach(NULL); if (!SUCCEEDED(hr)) { // ... }
4. Support the IActiveScriptSiteDebug in your script host. This interface provides a number of methods allowing a debugger to get the structure of the scripts in your documents and to get the text of those documents.
BEGIN_INTERFACE_MAP(CMfcaxscrvbDlg, CDialog) ... INTERFACE_PART(CMfcaxscrvbDlg,IID_IActiveScriptSiteDebug,ActiveScriptSiteDebug) ... END_INTERFACE_MAP() ... ///////////////////////////////////////////////////////////////////////////// // IActiveScriptSiteDebug Implementation STDMETHODIMP_(ULONG) CMfcaxscrvbDlg::XActiveScriptSiteDebug::AddRef() { METHOD_PROLOGUE_EX_(CMfcaxscrvbDlg, ActiveScriptSiteDebug) return pThis->ExternalAddRef(); } STDMETHODIMP_(ULONG) CMfcaxscrvbDlg::XActiveScriptSiteDebug::Release() { METHOD_PROLOGUE_EX_(CMfcaxscrvbDlg, ActiveScriptSiteDebug) return pThis->ExternalRelease(); } STDMETHODIMP CMfcaxscrvbDlg::XActiveScriptSiteDebug::QueryInterface(REFIID iid, LPVOID* ppvObj) { METHOD_PROLOGUE_EX_(CMfcaxscrvbDlg, ActiveScriptSiteDebug) return pThis->ExternalQueryInterface(&iid, ppvObj); } // Used by the language engine to delegate IDebugCodeContext::GetSourceContext. STDMETHODIMP CMfcaxscrvbDlg::XActiveScriptSiteDebug::GetDocumentContextFromPosition( DWORD dwSourceContext,// As provided to ParseScriptText // or AddScriptlet ULONG uCharacterOffset,// character offset relative // to start of script block or scriptlet ULONG uNumChars,// Number of characters in context // Returns the document context corresponding to this character-position range. IDebugDocumentContext **ppsc) { METHOD_PROLOGUE_EX_(CMfcaxscrvbDlg, ActiveScriptSiteDebug) ULONG ulStartPos = 0; HRESULT hr; if (pThis->m_pDebugDocHelper) { hr = pThis->m_pDebugDocHelper->GetScriptBlockInfo(dwSourceContext, NULL, &ulStartPos, NULL); hr = pThis->m_pDebugDocHelper->CreateDebugDocumentContext(ulStartPos + uCharacterOffset, uNumChars, ppsc); } else { hr = E_NOTIMPL; } return hr; } // Returns the debug application object associated with this script site. Provides // a means for a smart host to define what application object each script belongs to. // Script engines should attempt to call this method to get their containing application // and resort to IProcessDebugManager::GetDefaultApplication if this fails. STDMETHODIMP CMfcaxscrvbDlg::XActiveScriptSiteDebug::GetApplication( IDebugApplication **ppda) { METHOD_PROLOGUE_EX_(CMfcaxscrvbDlg, ActiveScriptSiteDebug) if (!ppda) { return E_INVALIDARG; } // bugbug - should addref to this ? if (pThis->m_pDebugApp) { ULONG ul = pThis->m_pDebugApp->AddRef(); } *ppda = pThis->m_pDebugApp; return S_OK; } // Gets the application node under which script documents should be added // can return NULL if script documents should be top-level. STDMETHODIMP CMfcaxscrvbDlg::XActiveScriptSiteDebug::GetRootApplicationNode( IDebugApplicationNode **ppdanRoot) { METHOD_PROLOGUE_EX_(CMfcaxscrvbDlg, ActiveScriptSiteDebug) if (!ppdanRoot) { return E_INVALIDARG; } if (pThis->m_pDebugDocHelper) { return pThis->m_pDebugDocHelper->GetDebugApplicationNode(ppdanRoot); } return E_NOTIMPL; } // Allows a smart host to control the handling of runtime errors STDMETHODIMP CMfcaxscrvbDlg::XActiveScriptSiteDebug::OnScriptErrorDebug( // the runtime error that occurred IActiveScriptErrorDebug *pErrorDebug, // whether to pass the error to the debugger to do JIT debugging BOOL*pfEnterDebugger, // whether to call IActiveScriptSite::OnScriptError() when the user // decides to continue without debugging BOOL *pfCallOnScriptErrorWhenContinuing) { METHOD_PROLOGUE_EX_(CMfcaxscrvbDlg, ActiveScriptSiteDebug) if (pfEnterDebugger) { *pfEnterDebugger = TRUE; } if (pfCallOnScriptErrorWhenContinuing) { *pfCallOnScriptErrorWhenContinuing = TRUE; } return S_OK; }
5. Before you parse the script text using IActiveScriptParse, add the script text to the IDebugDocumentHelper and define the script as a text.
hr = m_pDebugDocHelper->AddDBCSText(strScriptText); if (!SUCCEEDED(hr)) { // .... } DWORD dw; hr = m_pDebugDocHelper->DefineScriptBlock(0, strScriptText.GetLength(), m_axs, FALSE, &dw); if (!SUCCEEDED(hr)) { // .... }
6. When you have finished with the script, be sure to detach and release the IDebugDocumentHelper.
m_pDebugDocHelper->Detach();m_pDebugDocHelper->Release();
m_pDebugDocHelper = NULL;
7. [optional] The sample code included with this article also provides a simple IDebugDocumentHost implementation. This interface does not get used to its full extent by the IE4 debugger, but other Active Debuggers may use it more fully. Among the capabilities of this interface are customisation of script syntax coloring and provision of file path names and methods to react to the debugger changing document text.