|
C++ implementationRemember, the general strategy is to create a
component that:
So the core part is actually writing the code that records method calls. Here we go. The constructor and the destructor take care of member variables:
CNullScript::CNullScript()
: m_scriptState(SCRIPTSTATE_UNINITIALIZED),
m_site(NULL)
{
m_fp = fopen ("c:\\NullScript.txt", "w");
}
CNullScript::~CNullScript()
{
if (NULL != m_fp)
{
fclose (m_fp);
m_fp = NULL;
}
if (NULL != m_site)
{
m_site->Release ();
m_site = NULL;
}
}
The constructor opens a FILE named NullScript.txt for write. This foreshadows what's to come: lots of code that logs method calls to this file. The IDispatch methods report their method calls:
HRESULT CNullScript::GetIDsOfNames(
REFIID riid,
OLECHAR FAR* FAR* rgszNames,
unsigned int cNames,
LCID lcid,
DISPID FAR* rgDispId)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IDispatch::GetIDsOfNames\n");
fflush (m_fp);
return hr;
}
HRESULT CNullScript::GetTypeInfo(
unsigned int iTInfo,
LCID lcid,
ITypeInfo FAR* FAR* ppTInfo)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IDispatch::GetTypeInfo\n");
fflush (m_fp);
return hr;
}
HRESULT CNullScript::GetTypeInfoCount(
unsigned int FAR* pctinfo)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IDispatch::GetTypeInfoCount\n");
fflush (m_fp);
*pctinfo = 1;
return hr;
}
HRESULT CNullScript::Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult,
EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IDispatch::Invoke\n");
fflush (m_fp);
return hr;
}
The IActiveScript declare their method calls. Since the SetScriptState controls the start of the scripting engine, requesting it to start or stop execution, I did some extra stuff to record the state. Adding named items is also important, so I dumped the flags sent from the scripting host.
HRESULT CNullScript::SetScriptSite(
/* [in] */ IActiveScriptSite *pass)
{
fprintf (m_fp, "IActiveScript::SetScriptSite\n");
fflush (m_fp);
HRESULT hr = pass->QueryInterface (IID_IActiveScriptSite,
reinterpret_cast<void **>(&m_site));
return hr;
}
HRESULT CNullScript::GetScriptSite(
/* [in] */ REFIID riid,
/*[out, iid_is(riid)]*/ void **ppvObject)
{
fprintf (m_fp, "IActiveScript::GetScriptSite\n");
fflush (m_fp);
*ppvObject = NULL;
HRESULT hr = m_site->QueryInterface (riid, ppvObject);
return hr;
}
HRESULT CNullScript::SetScriptState(
/* [in] */ SCRIPTSTATE ss)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScript::SetScriptState(%08lx)\n",
(DWORD) ss);
fflush (m_fp);
m_scriptState = ss;
return hr;
}
HRESULT CNullScript::GetScriptState(
/* [out] */ SCRIPTSTATE *pssState)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScript::GetScriptState\n");
fflush (m_fp);
*pssState = m_scriptState;
return hr;
}
HRESULT CNullScript::Close(void)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScript::Close\n");
fflush (m_fp);
return hr;
}
HRESULT CNullScript::AddNamedItem(
/* [in] */ LPCOLESTR pstrName,
/* [in] */ DWORD dwFlags)
{
USES_CONVERSION;
HRESULT hr = S_OK;
const TCHAR *cp = OLE2T(pstrName);
typedef struct
{
DWORD f;
char *name;
} Flags;
const Flags flags[] =
{
{SCRIPTITEM_CODEONLY, "SCRIPTITEM_CODEONLY"},
{SCRIPTITEM_GLOBALMEMBERS, "SCRIPTITEM_GLOBALMEMBERS"},
{SCRIPTITEM_ISPERSISTENT, "SCRIPTITEM_ISPERSISTENT"},
{SCRIPTITEM_ISSOURCE, "SCRIPTITEM_ISSOURCE"},
{SCRIPTITEM_ISVISIBLE, "SCRIPTITEM_ISVISIBLE"},
{SCRIPTITEM_NOCODE, "SCRIPTITEM_NOCODE"},
};
fprintf (m_fp, "IActiveScript::AddNamedItem('%s', %08lx)\n",
cp, dwFlags);
for (unsigned i = 0; i < sizeof(flags)/sizeof(flags[0]); i++)
{
if (dwFlags & flags[i].f)
fprintf (m_fp, "\t%s\n", flags[i].name);
}
fflush (m_fp);
return hr;
}
HRESULT CNullScript::AddTypeLib(
/* [in] */ REFGUID rguidTypeLib,
/* [in] */ DWORD dwMajor,
/* [in] */ DWORD dwMinor,
/* [in] */ DWORD dwFlags)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScript::AddTypeLib\n");
fflush (m_fp);
return hr;
}
// S_FALSE
// The scripting engine does not support a dispatch object;
// the ppdisp parameter is set to NULL.
HRESULT CNullScript::GetScriptDispatch(
/* [in] */ LPCOLESTR pstrItemName,
/* [out] */ IDispatch **ppdisp)
{
USES_CONVERSION;
HRESULT hr = S_OK;
TCHAR *cp = OLE2T(pstrItemName);
if (NULL == cp)
cp = "NULL";
fprintf (m_fp, "IActiveScript::GetScriptDispatch(%s)\n", cp);
fflush (m_fp);
hr = this->QueryInterface (IID_IDispatch,
reinterpret_cast<void **>(ppdisp));
return hr;
}
HRESULT CNullScript::GetCurrentScriptThreadID(
/* [out] */ SCRIPTTHREADID *pstidThread)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScript::GetCurrentScriptThreadID\n");
fflush (m_fp);
*pstidThread = 0;
return hr;
}
HRESULT CNullScript::GetScriptThreadID(
/* [in] */ DWORD dwWin32ThreadId,
/* [out] */ SCRIPTTHREADID *pstidThread)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScript::GetScriptThreadID\n");
fflush (m_fp);
*pstidThread = 0;
return hr;
}
HRESULT CNullScript::GetScriptThreadState(
/* [in] */ SCRIPTTHREADID stidThread,
/* [out] */ SCRIPTTHREADSTATE *pstsState)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScript::GetScriptThreadState\n");
fflush (m_fp);
return hr;
}
HRESULT CNullScript::InterruptScriptThread(
/* [in] */ SCRIPTTHREADID stidThread,
/* [in] */ const EXCEPINFO *pexcepinfo,
/* [in] */ DWORD dwFlags)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScript::InterruptScriptThread\n");
fflush (m_fp);
return hr;
}
HRESULT CNullScript::Clone(
/* [out] */ IActiveScript **ppscript)
{
fprintf (m_fp, "IActiveScript::Clone\n");
fflush (m_fp);
HRESULT hr = this->QueryInterface (IID_IActiveScript,
reinterpret_cast<void **>(ppscript));
return hr;
}
The IActiveScriptParse methods report their method calls. Since they have important parameters passed to them, we record the parameters, too:
HRESULT CNullScript::InitNew(void)
{
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScriptParse::InitNew\n");
fflush (m_fp);
return hr;
}
HRESULT CNullScript::AddScriptlet(
/* [in] */ LPCOLESTR pstrDefaultName,
/* [in] */ LPCOLESTR pstrCode,
/* [in] */ LPCOLESTR pstrItemName,
/* [in] */ LPCOLESTR pstrSubItemName,
/* [in] */ LPCOLESTR pstrEventName,
/* [in] */ LPCOLESTR pstrDelimiter,
/* [in] */ DWORD dwSourceContextCookie,
/* [in] */ ULONG ulStartingLineNumber,
/* [in] */ DWORD dwFlags,
/* [out] */ BSTR *pbstrName,
/* [out] */ EXCEPINFO *pexcepinfo)
{
USES_CONVERSION;
TCHAR *cp = OLE2T(pstrCode);
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScriptParse::AddScriptlet(%s)\n", cp);
fflush (m_fp);
return hr;
}
HRESULT CNullScript::ParseScriptText(
/* [in] */ LPCOLESTR pstrCode,
/* [in] */ LPCOLESTR pstrItemName,
/* [in] */ IUnknown *punkContext,
/* [in] */ LPCOLESTR pstrDelimiter,
/* [in] */ DWORD dwSourceContextCookie,
/* [in] */ ULONG ulStartingLineNumber,
/* [in] */ DWORD dwFlags,
/* [out] */ VARIANT *pvarResult,
/* [out] */ EXCEPINFO *pexcepinfo)
{
USES_CONVERSION;
TCHAR *cp = OLE2T(pstrCode);
HRESULT hr = S_OK;
fprintf (m_fp, "IActiveScriptParse::ParseScriptText(%s)\n", cp);
fflush (m_fp);
return hr;
}
Now we're almost ready. We just have to set up some infrastructure and we're done. Next: RGS file© 2001-8 Hugh Brown. All rights reserved. |