最近由于工作需要,开发的程式需要有二次开发的能力,我想到了脚本解析(PerlScript,JavaScript,VBScript...);经过N多次Google,终于弄了个非常简单的代码;
实现了接口IActiveScriptSitet和IDispatch
以下是在类头文件中定义的子类
- BEGIN_INTERFACE_PART(ActiveScriptSite, IActiveScriptSite)
- STDMETHOD(GetLCID)(LCID*) { return E_NOTIMPL; }
- STDMETHOD(GetItemInfo)(LPCOLESTR, DWORD, LPUNKNOWN*, LPTYPEINFO*);
- STDMETHOD(GetDocVersionString)(BSTR*) { return E_NOTIMPL; }
- STDMETHOD(OnScriptTerminate)(const VARIANT*, const EXCEPINFO*) { return S_OK; }
- STDMETHOD(OnStateChange)(SCRIPTSTATE) { return S_OK; }
- STDMETHOD(OnScriptError)(IActiveScriptError*);
- STDMETHOD(OnEnterScript)() { return S_OK; }
- STDMETHOD(OnLeaveScript)() { return S_OK; }
- END_INTERFACE_PART(ActiveScriptSite)
- BEGIN_INTERFACE_PART(MY, IDispatch)
- STDMETHOD(GetTypeInfoCount)(UINT*);
- STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**);
- STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*);
- STDMETHOD(Invoke)(DISPID, REFIID, LCID, WORD, DISPPARAMS *, VARIANT *, EXCEPINFO *, UINT *);
- STDMETHOD(GetLCID)(LCID*) { return E_NOTIMPL; }
- END_INTERFACE_PART(MY)
接口类的实现部分,本例中只简单实现了一个函数msg和变量int33。
- STDMETHODIMP CApplication1Dlg::XActiveScriptSite::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
- {
- if( iid == IID_IUnknown || iid == IID_IActiveScriptSite ){
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
- *ppvObj = NULL;
- return E_NOINTERFACE;
- }
- STDMETHODIMP CApplication1Dlg::XActiveScriptSite::GetItemInfo(
- /* [in] */ LPCOLESTR pstrName,
- /* [in] */ DWORD dwReturnMask,
- /* [out] */LPUNKNOWN* ppiunkItem,
- /* [out] */LPTYPEINFO* ppti)
- {
- if (dwReturnMask & SCRIPTINFO_ITYPEINFO){
- if (!ppti)
- return E_INVALIDARG;
- *ppti = NULL;
- }
- if (dwReturnMask & SCRIPTINFO_IUNKNOWN){
- if (!ppiunkItem)
- return E_INVALIDARG;
- *ppiunkItem = NULL;
- }
- if ( !_wcsicmp( TEXT("MY"), pstrName ) ){
- *ppiunkItem = &pThis->m_xMY;
- (*ppiunkItem)->AddRef();
- return S_OK;
- }
- return E_FAIL;
- }
- STDMETHODIMP CApplication1Dlg::XActiveScriptSite::OnScriptError(
- /* [in] */ IActiveScriptError* pse)
- {
- EXCEPINFO ei;
- ULONG ulLine;
- LONG ichError;
- CString strError;
- pse->GetExceptionInfo(&ei);
- pse->GetSourcePosition(NULL, &ulLine, &ichError);
- strError.Format(TEXT("行:/t%d/n字符:/t%d/n错误:/t%s/n代码:/t%x/n来源:/t%s"), ulLine + 1, ichError + 1, (LPCWSTR)ei.bstrDescription, ei.scode, (LPCWSTR)ei.bstrSource );
- AfxMessageBox(strError, MB_ICONSTOP);
- return S_OK;
- }
- STDMETHODIMP CApplication1Dlg::XMY::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
- {
- if ( iid == IID_IUnknown || iid == IID_IDispatch ){
- *ppvObj = this;
- AddRef();
- return S_OK;
- }
- *ppvObj = NULL;
- return E_NOINTERFACE;
- }
- STDMETHODIMP CApplication1Dlg::XMY::GetTypeInfoCount(
- /* [out] */ UINT *pctinfo)
- {
- return S_OK;
- }
- STDMETHODIMP CApplication1Dlg::XMY::GetTypeInfo(
- /* [in] */ UINT iTInfo,
- /* [in] */ LCID lcid,
- /* [out] */ ITypeInfo **ppTInfo)
- {
- return S_OK;
- }
- STDMETHODIMP CApplication1Dlg::XMY::GetIDsOfNames(
- /* [in] */ REFIID riid,
- /* [size_is][in] */ LPOLESTR *rgszNames,
- /* [in] */ UINT cNames,
- /* [in] */ LCID lcid,
- /* [size_is][out] */ DISPID *rgDispId)
- {
- if ( !lstrcmp ( TEXT("msg"), *rgszNames ) ){
- *rgDispId = 1;
- } else if ( !lstrcmp ( TEXT("int33"), *rgszNames ) ){
- *rgDispId = 2;
- } else {
- return E_NOTIMPL;
- }
- return S_OK;
- }
- STDMETHODIMP CApplication1Dlg::XMY::Invoke(
- /* [in] */ DISPID dispIdMember,
- /* [in] */ REFIID riid,
- /* [in] */ LCID lcid,
- /* [in] */ WORD wFlags,
- /* [out][in] */ DISPPARAMS *pDispParams,
- /* [out] */ VARIANT *pVarResult,
- /* [out] */ EXCEPINFO *pExcepInfo,
- /* [out] */ UINT *puArgErr)
- {
- switch(dispIdMember){
- case 1:
- if ( pDispParams->cArgs != 1 ) return DISP_E_BADPARAMCOUNT;
- if ( pDispParams->rgvarg[0].vt != VT_BSTR ){ *puArgErr = 0; return DISP_E_TYPEMISMATCH; }
- AfxMessageBox ( pDispParams->rgvarg[0].bstrVal );
- break;
- case 2:
- pVarResult->vt = VT_I4;
- pVarResult->intVal = 5000;
- break;
- default:
- return DISP_E_MEMBERNOTFOUND;
- }
- return S_OK;
- }
我用了一行简单的JScript脚本代码:
- var c=0;var p=2+int33;msg(p.toString());
m_pActiveScript->AddNamedItem 加入自定义的对象,在脚本中可以直接访问这些对象。SCRIPTITEM_GLOBALMEMBERS 标志表示对象在脚本中是个全局对象。
函数m_pActiveScriptParse->ParseScriptText 将脚本代码解析后,调用m_pActiveScript->SetScriptState ( SCRIPTSTATE_STARTED ) 开始执行脚本代码;整个过程非常简单。
- CLSID cid;
- IActiveScript* m_pActiveScript = NULL;
- IActiveScriptParse* m_pActiveScriptParse = NULL;
- try {
- HCHECK ( CLSIDFromProgID ( TEXT("JScript"), &cid ) );
- HCHECK ( CoCreateInstance ( cid, NULL, CLSCTX_ALL, IID_IActiveScript, (void **)&m_pActiveScript ) );
- HCHECK ( m_pActiveScript->QueryInterface ( IID_IActiveScriptParse, (void **)&m_pActiveScriptParse ) );
- HCHECK ( m_pActiveScriptParse->InitNew () );
- HCHECK ( m_pActiveScript->SetScriptSite ( &m_xActiveScriptSite ) );
- HCHECK ( m_pActiveScript->AddNamedItem ( TEXT("MY"), SCRIPTITEM_ISVISIBLE | SCRIPTITEM_GLOBALMEMBERS ) );
- HCHECK ( m_pActiveScriptParse->ParseScriptText ( TEXT("var c=0;var p=2+int33;msg(p.toString());"), NULL, NULL, NULL, 0, 0, 0, NULL, NULL ) );
- HCHECK ( m_pActiveScript->SetScriptState ( SCRIPTSTATE_STARTED ) );
- HCHECK ( m_pActiveScript->Close () );
- }
- catch (HRESULT hr){
- TRACE("---Script Error: %x ---", hr);
- }
- if ( m_pActiveScript != NULL ){
- m_pActiveScript->Release ();
- m_pActiveScript = NULL;
- }