IActiveScript : IUnknown
{
HRESULT SetScriptSite(IActiveScriptSite* pass) = 0;
HRESULT GetScriptSite(REFIID riid, void** ppvObject) = 0;
HRESULT SetScriptState(SCRIPTSTATE ss) = 0;
HRESULT GetScriptState(SCRIPTSTATE* pssState) = 0;
HRESULT Close( void) = 0;
HRESULT AddNamedItem(LPCOLESTR pstrName,
DWORD dwFlags) = 0;
HRESULT AddTypeLib(REFGUID rguidTypeLib,
DWORD dwMajor,
DWORD dwMinor,
DWORD dwFlags) = 0;
HRESULT GetScriptDispatch(LPCOLESTR pstrItemName,
IDispatch** ppdisp) = 0;
HRESULT GetCurrentScriptThreadID(SCRIPTTHREADID* pstidThread)=0;
HRESULT GetScriptThreadID(DWORD dwWin32ThreadId,
SCRIPTTHREADID* pstidThread) = 0;
HRESULT GetScriptThreadState(SCRIPTTHREADID stidThread,
SCRIPTTHREADSTATE* pstsState) = 0;
HRESULT InterruptScriptThread(SCRIPTTHREADID stidThread,
EXCEPINFO* pexcepinfo,
DWORD dwFlags) = 0;
HRESULT Clone(IActiveScript** ppscript) = 0;
};
Figure 2 IActiveScriptParse
IActiveScriptParse : IUnknown
{
HRESULT InitNew( void) = 0;
HRESULT AddScriptlet(
LPCOLESTR pstrDefaultName,
LPCOLESTR pstrCode,
LPCOLESTR pstrItemName,
LPCOLESTR pstrSubItemName,
LPCOLESTR pstrEventName,
LPCOLESTR pstrDelimiter,
DWORD dwSourceContextCookie,
ULONG ulStartingLineNumber,
DWORD dwFlags,
BSTR* pbstrName,
EXCEPINFO* pexcepinfo) = 0;
HRESULT ParseScriptText(
LPCOLESTR pstrCode,
LPCOLESTR pstrItemName,
IUnknown* punkContext,
LPCOLESTR pstrDelimiter,
DWORD dwSourceContextCookie,
ULONG ulStartingLineNumber,
DWORD dwFlags,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo) = 0;
};
Figure 3 IActiveScriptSite
IActiveScriptSite : IUnknown
{
HRESULT GetLCID(LCID* plcid) = 0;
HRESULT GetItemInfo(LPCOLESTR pstrName,
DWORD dwReturnMask,
IUnknown** ppiunkItem,
ITypeInfo** ppti) = 0;
HRESULT GetDocVersionString(BSTR* pbstrVersion) = 0;
HRESULT OnScriptTerminate(VARIANT* pvarResult,
EXCEPINFO* pexcepinfo) = 0;
HRESULT OnStateChange(SCRIPTSTATE ssScriptState) = 0;
HRESULT OnScriptError(IActiveScriptError* pscripterror) = 0;
HRESULT OnEnterScript(void) = 0;
HRESULT OnLeaveScript(void) = 0;
};
Figure 5 CActiveScriptSite Highlights
class CActiveScriptSite :
public IActiveScriptSite,
{
protected:
/////////////////////////////////////////////////////////////
// These interfaces come from Microsoft. We'll cache them.
IActiveScript* m_pActiveScript;
IActiveScriptParse* m_pActiveScriptParse;
/////////////////////////////////////////////////////////////
// Lists of named items and macro information.
CNamedItems* m_pitems;
CMacroInfos* m_pmacros;
/////////////////////////////////////////////////////////////
// Prototypes for the functions found in the interfaces
// QueryInterface, AddRef, Release, GetItemInfo, etc.
};
Figure 6 InitScriptEngine
////////////////////////////////////////////////////////////////////
// Called by the client to start up the script engine...
//
STDMETHODIMP InitScriptEngine(REFCLSID clsid)
{
ULONG ul = 0;
HRESULT hResult = E_FAIL;
IActiveScriptSite* pActiveScriptSite = NULL;
hResult = CoCreateInstance(clsid, NULL,
CLSCTX_INPROC_SERVER,
IID_IActiveScript,
(void**)&m_pActiveScript);
if(SUCCEEDED(hResult))
{
hResult = m_pActiveScript->QueryInterface(
IID_IActiveScriptParse, (void**)&m_pActiveScriptParse);
if(FAILED(hResult))
{
goto err;
}
}
if( FAILED( hResult ) )
{
goto err;
}
hResult = QueryInterface(IID_IActiveScriptSite,
(void**)&pActiveScriptSite);
if(SUCCEEDED(hResult))
{
hResult = m_pActiveScript->SetScriptSite(
pActiveScriptSite);
pActiveScriptSite->Release();
} else
{
goto err;
}
if(FAILED( hResult ))
{
goto err;
}
hResult = m_pActiveScriptParse->InitNew();
if( FAILED( hResult ) )
{
goto err;
}
m_bIsInitialized = true;
return S_OK;
err:
if(m_pActiveScriptParse)
{
m_pActiveScriptParse->Release();
m_pActiveScriptParse = NULL;
}
if(m_pActiveScript)
{
m_pActiveScript->Release();
m_pActiveScript = NULL;
}
return hResult;
}
Figure 7 Adding a Named Item
STDMETHODIMP AddNamedItem(BSTR bstrName, IUnknown* pUnkItem)
{
if(!m_pitems)
{
m_pitems = new CNamedItems;
/////////////////////////////////////////////////////////
// First add the named item to our own internal collection
NamedItem* pNamedItem = NULL;
pNamedItem = new NamedItem(bstrName, pUnkItem);
m_pitems->push_back(pNamedItem);
///////////////////////////////////////////////////////
// Then add the item to the active script engine...
HRESULT hr = m_pActiveScript->AddNamedItem(bstrName,
SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE);
}
return S_OK;
}
Figure 8 IActiveScriptSite::OnStateChange
////////////////////////////////////////////////////////////////////////////
//
// Called by active script engine when the state changes...
//
STDMETHODIMP OnStateChange(tagSCRIPTSTATE ssScriptState)
{
OutputDebugString("OnStateChange\n");
switch(ssScriptState)
{
case SCRIPTSTATE_UNINITIALIZED:
OutputDebugString( "\tSCRIPTSTATE_UNINITIALIZED\n" );
break;
case SCRIPTSTATE_INITIALIZED:
OutputDebugString( "\tSCRIPTSTATE_INITIALIZED\n" );
break;
case SCRIPTSTATE_STARTED:
OutputDebugString( "\tSCRIPTSTATE_STARTED\n" );
break;
case SCRIPTSTATE_CONNECTED:
OutputDebugString( "\tSCRIPTSTATE_CONNECTED\n" );
break;
case SCRIPTSTATE_DISCONNECTED:
OutputDebugString( "\tSCRIPTSTATE_DISCONNECTED\n" );
break;
case SCRIPTSTATE_CLOSED:
OutputDebugString( "\tSCRIPTSTATE_CLOSED\n" );
break;
default:
OutputDebugString( "\tUnknown SCRIPTSTATE value\n" );
break;
}
return S_OK;
}
Figure 9 Script Engine States
State
|
Description
|
SCRIPTSTATE_UNINITIALIZED
|
Script has just been created, but has not yet been initialized using an IPersist interface and IActiveScript::SetScriptSite.
|
SCRIPTSTATE_INITIALIZED
|
Script has been initialized, but is not running (connecting to other objects or sinking events) or executing any code. Code can be queried for execution by calling the IActiveScriptParse::ParseScriptText method.
|
SCRIPTSTATE_STARTED
|
Script can execute code, but is not yet sinking the events of objects added by the IActiveScript::AddNamedItem method.
|
SCRIPTSTATE_CONNECTED
|
Script is loaded and connected for sinking events.
|
SCRIPTSTATE_DISCONNECTED
|
Script is loaded and has a runtime execution state, but is temporarily disconnected from sinking events.
|
SCRIPTSTATE_CLOSED
|
Script has been closed. The scripting engine no longer works and returns errors for most methods.
|
Figure 10 IActiveScriptSite::GetItemInfo
/////////////////////////////////////////////////////////////////
//
// This function is called by the COM scripting engine.
//
STDMETHODIMP GetItemInfo(LPCOLESTR pstrName,
ULONG dwReturnMask,
IUnknown** ppiunkItem,
ITypeInfo** ppti)
{
OutputDebugString( "GetItemInfo\n" );
if( ppiunkItem != NULL )
{
*ppiunkItem = NULL;
}
if( ppti != NULL )
{
*ppti = NULL;
}
HRESULT hr = S_OK;
bool bFound = false;
std::vector<NamedItem*>::iterator iter;
//Find the named item...
if(m_pitems)
{
for (iter = m_pitems->begin();
iter < m_pitems->end();
iter++)
{
NamedItem* pNamedItem = *iter;
bFound = (wcscmp(pNamedItem->m_bstrName,
pstrName) == 0);
if (bFound)
{
break;
}
}
}
if(!bFound)
{
return TYPE_E_ELEMENTNOTFOUND;
}
if( dwReturnMask&SCRIPTINFO_IUNKNOWN )
{
OutputDebugString( "Looking for item's unknown\n" );
NamedItem* pNamedItem = *iter;
pNamedItem->m_pUnk->AddRef();
*ppiunkItem = pNamedItem->m_pUnk;
}
if( dwReturnMask&SCRIPTINFO_ITYPEINFO )
{
OutputDebugString( "Looking for item's type info\n" );
NamedItem* pNamedItem = *iter;
if(pNamedItem->m_pTypeInfo)
{
pNamedItem->m_pTypeInfo->AddRef();
}
*ppti = pNamedItem->m_pTypeInfo;
}
return S_OK;
}
Figure 11 Invoking a Scripting Function
STDMETHODIMP RunMacro(BSTR bstrMacroName)
{
CMacroInfos::iterator iter;
bool bFound = false;
CMacroInfo* pMacroInfo = 0;
if(m_pmacros)
{
for (iter = m_pmacros->begin();
iter < m_pmacros->end();
iter++)
{
pMacroInfo = *iter;
bFound = (wcscmp(pMacroInfo->m_bstrMacroName,
bstrMacroName)
== 0);
if (bFound)
{
break;
}
}
if(bFound)
{
IDispatch* pDispatch = 0;
HRESULT hResult;
hresult = m_pActiveScript->GetScriptDispatch(NULL, &pDispatch);
if(SUCCEEDED(hResult))
{
DISPPARAMS dp = {0, 0};
VARIANT v;
VariantInit(&v);
EXCEPINFO ei;
unsigned int nArgError = 0;
memset(&ei, sizeof(EXCEPINFO), 0);
HRESULT hr;
hr = pDispatch->Invoke(pMacroInfo->m_dispID,
IID_NULL,
0, DISPATCH_METHOD,
&dp,
&v,
&ei,
&nArgError);
pDispatch->Release();
}
}
}
return S_OK;
}