www.pudn.com > mod_rssim6.zip > ActiveScriptHost.cpp
/////////////////////////////////////////////////////////////////////////////// // File: ActiveScriptHost.cpp // Version: 1.1 // // Author: Ernest Laurentin // E-mail: elaurentin@sympatico.ca // // This class implements an Active Script Hosting // // This code may be used in compiled form in any way you desire. This // file may be redistributed unmodified by any means PROVIDING it is // not sold for profit without the authors written consent, and // providing that this notice and the authors name and all copyright // notices remains intact. // // An email letting me know how you are using it would be nice as well. // // This file is provided "as is" with no expressed or implied warranty. // The author accepts no liability for any damage/loss of business that // this c++ class may cause. // // Version history // v1.01 : Bug fix with accessing object info (ITypeInfo) // v1.1 : Add 'InvokeFuncHelper' allows to call script function directly from c++ /////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include// or #include "ActiveScriptHost.h" #pragma warning(disable: 4290) // C++ Exception Specification ignored struct HRESULT_EXCEPTION { HRESULT_EXCEPTION(HRESULT hr) { if (FAILED(hr)) throw hr; } HRESULT operator = (HRESULT hr) { if (FAILED(hr)) throw hr; return hr; } static inline void CheckError(HRESULT hr) throw(HRESULT) { if (FAILED(hr)) throw hr; } }; HRESULT LoadTypeInfoFromModule(REFIID riid, ITypeInfo **ppti); //BEGIN_DISPATCH_MAP(CActiveScriptHost, CCmdTarget) //END_DISPATCH_MAP() BEGIN_INTERFACE_MAP(CActiveScriptHost, CCmdTarget) INTERFACE_PART(CActiveScriptHost, IID_IActiveScriptSite, ActiveScriptSite) INTERFACE_PART(CActiveScriptHost, IID_IActiveScriptSiteWindow, ActiveScriptSiteWindow) END_INTERFACE_MAP() IMPLEMENT_DYNAMIC(CActiveScriptHost, CCmdTarget) /////////////////////////////////////////////////////////////////////////////// // Construction CActiveScriptHost::CActiveScriptHost() : m_pAxsParse(NULL), m_pAxsScript(NULL), m_hHostWnd(NULL) { m_xActiveScriptSite.m_running = FALSE; } CActiveScriptHost::~CActiveScriptHost() { ReleaseObjects(); } /////////////////////////////////////////////////////////////////////////////// // CommonConstruct void CActiveScriptHost::CommonConstruct() { m_hHostWnd = ::GetDesktopWindow(); } /////////////////////////////////////////////////////////////////////////////// // ReleaseObjects void CActiveScriptHost::ReleaseObjects() { if (m_pAxsParse) { m_pAxsParse->Release(); m_pAxsParse = NULL; } if (m_pAxsScript) { m_pAxsScript->Close(); m_pAxsScript->Release(); m_pAxsScript = NULL; } } /////////////////////////////////////////////////////////////////////////////// // Members /////////////////////////////////////////////////////////////////////////////// // SetHostWindow BOOL CActiveScriptHost::SetHostWindow(HWND hWnd) { m_hHostWnd = hWnd; if (!::IsWindow(hWnd)) m_hHostWnd = GetDesktopWindow(); return TRUE; } /////////////////////////////////////////////////////////////////////////////// // CreateEngine BOOL CActiveScriptHost::CreateEngine(LPCOLESTR pstrProgID) { CLSID clsid; HRESULT hr; try { // Auto deletion of script engine ReleaseObjects(); // Search for LanguageID and create instance of script engine if (SUCCEEDED(CLSIDFromProgID(pstrProgID, &clsid))) { // If this happens, the scripting engine is probably not properly registered hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IActiveScript, (void **)&m_pAxsScript); HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed // Script Engine must support IActiveScriptParse for us to use it hr = m_pAxsScript->QueryInterface(IID_IActiveScriptParse, (void **)&m_pAxsParse); HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed hr = m_pAxsScript->SetScriptSite(&m_xActiveScriptSite); // Our MFC-OLE interface implementation HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed // InitNew the object: hr = m_pAxsParse->InitNew(); HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed USES_CONVERSION; LPCTSTR activsHost = OLE2CT(ACTIVS_HOST); mapNamedItems[activsHost] = GetIDispatch(FALSE); // Add Top-level Global Named Item hr = m_pAxsScript->AddNamedItem(ACTIVS_HOST, SCRIPTITEM_NAMEDITEM); HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed hr = m_pAxsScript->SetScriptState(SCRIPTSTATE_STARTED); HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed return TRUE; } } catch(HRESULT hr){ TRACE("### Script Error: %x ###", hr); ReleaseObjects(); } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // AddScriptItem BOOL CActiveScriptHost::AddScriptItem(LPCOLESTR pstrNamedItem, LPUNKNOWN lpUnknown, DWORD dwFlags /* = SCRIPTITEM_NAMEDITEM*/) { try { // Add Top-level Global Named Item if (m_pAxsScript != NULL && lpUnknown != NULL) { HRESULT hr; USES_CONVERSION; LPCTSTR szNamedItem = OLE2CT(pstrNamedItem); mapNamedItems[szNamedItem] = lpUnknown; hr = m_pAxsScript->AddNamedItem(pstrNamedItem, dwFlags); HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed // Connected to object sink-interface hr = m_pAxsScript->SetScriptState(SCRIPTSTATE_CONNECTED); HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed return TRUE; } } catch(HRESULT hr){ TRACE("### Script Error: %x ###", hr); } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // AddScriptCode BOOL CActiveScriptHost::AddScriptCode(LPCOLESTR pstrScriptCode) { m_xActiveScriptSite.m_running = TRUE; //script will run try { if (m_pAxsParse != NULL) { HRESULT hr; EXCEPINFO ei = { 0 }; hr = m_pAxsParse->ParseScriptText(pstrScriptCode, 0, 0, 0, 0, 0, SCRIPTTEXT_ISPERSISTENT|SCRIPTTEXT_ISVISIBLE, 0, &ei); HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed // Force script to Connected //hr = m_pAxsScript->SetScriptState(SCRIPTSTATE_CONNECTED); //HRESULT_EXCEPTION::CheckError( hr ); // will throw an exception if failed return TRUE; } } catch(HRESULT hr){ m_xActiveScriptSite.m_running = FALSE; //script will not be running TRACE("### Script Error: %x ###", hr); } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // AddScriptlet BOOL CActiveScriptHost::AddScriptlet(LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName, LPCOLESTR pstrEventName) { try { // Add Top-level Global Named Item if (m_pAxsParse != NULL) { HRESULT hr; EXCEPINFO ei = { 0 }; BSTR bstrName = NULL; hr = m_pAxsParse->AddScriptlet(pstrDefaultName, pstrCode, pstrItemName, // name object pstrItemName, // no subobject - same as object pstrEventName, // event name - attach to 'pstrItemName' L"", 0, 0, 0, &bstrName, &ei); SysFreeString(bstrName); } } catch(HRESULT hr){ TRACE("### Script Error: %x ###", hr); } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // Helper functions /////////////////////////////////////////////////////////////////////////////// // CreateObjectHelper LPDISPATCH CActiveScriptHost::CreateObjectHelper(LPCOLESTR bstrProgID) { USES_CONVERSION; HRESULT hr = S_OK; LPDISPATCH lpObject = NULL; TRACE( "Calling CreateObjectHelper()\n" ); CLSID clsidObject; hr = CLSIDFromProgID(bstrProgID, &clsidObject ); if( SUCCEEDED( hr ) ) { // Only Local-Server is safe (run as separated process) hr = CoCreateInstance(clsidObject, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&lpObject ); if (FAILED(hr)) { CString strProgID; strProgID = bstrProgID; TRACE("Failed to create object '%s'.\nReturn = 0x%x\n", strProgID, hr); } } else { CString strProgID; strProgID = bstrProgID; TRACE("Invalid ProgID '%s'\n",strProgID); } return lpObject; } /////////////////////////////////////////////////////////////////////////////// // ReadTextFileHelper WCHAR* CActiveScriptHost::ReadTextFileHelper(LPCOLESTR strFileName) { WCHAR *pwszResult = NULL; char szFileNameA[MAX_PATH]; if (wcstombs(szFileNameA, strFileName, MAX_PATH) == -1) return pwszResult; HANDLE hfile = CreateFileA(szFileNameA, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hfile != INVALID_HANDLE_VALUE) { DWORD cch = GetFileSize(hfile, 0); char *psz = (char*)CoTaskMemAlloc(cch + 1); if (psz) { DWORD cb; ReadFile(hfile, psz, cch, &cb, 0); pwszResult = (WCHAR*)CoTaskMemAlloc((cch + 1)*sizeof(WCHAR)); if (pwszResult) mbstowcs(pwszResult, psz, cch + 1); pwszResult[cch] = 0; CoTaskMemFree(psz); } CloseHandle(hfile); } return pwszResult; } /////////////////////////////////////////////////////////////////////////////// // DestroyDataHelper void CActiveScriptHost::DestroyDataHelper(LPVOID lpvData) { CoTaskMemFree(lpvData); } /////////////////////////////////////////////////////////////////////////// // InvokeFuncHelper HRESULT CActiveScriptHost::InvokeFuncHelper(LPCOLESTR lpszName, VARIANT* pvarParams, int nParams, VARIANT* pvarRet /*= NULL*/) { HRESULT hr = E_FAIL; if (m_pAxsScript != NULL && lpszName != NULL) { DISPID dispid; LPDISPATCH pDisp = NULL; DISPPARAMS dispparams = { pvarParams, NULL, nParams, 0}; hr = m_pAxsScript->GetScriptDispatch(0, &pDisp); if (SUCCEEDED(hr)) hr = pDisp->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpszName, 1, LOCALE_SCRIPT_DEFAULT, &dispid); if (SUCCEEDED(hr)) hr = pDisp->Invoke(dispid, IID_NULL, LOCALE_SCRIPT_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); } return hr; } /////////////////////////////////////////////////////////////////////////////// // Methods ///////////////////////////////////////////////////////////////////////////// // IActiveScriptSite Implementation /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::AddRef STDMETHODIMP_(ULONG)CActiveScriptHost::XActiveScriptSite::AddRef() { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) return pThis->ExternalAddRef(); } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::Release STDMETHODIMP_(ULONG)CActiveScriptHost::XActiveScriptSite::Release() { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) return pThis->ExternalRelease(); } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::QueryInterface STDMETHODIMP CActiveScriptHost::XActiveScriptSite::QueryInterface( REFIID iid, void FAR* FAR* ppvObj) { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj); } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::GetLCID STDMETHODIMP CActiveScriptHost::XActiveScriptSite::GetLCID(LCID* plcid) { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) *plcid = LOCALE_SCRIPT_DEFAULT; // Default LCID: english-neutral return S_OK; } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::GetItemInfo STDMETHODIMP CActiveScriptHost::XActiveScriptSite::GetItemInfo( /* [in] */ LPCOLESTR pstrName, /* [in] */ DWORD dwReturnMask, /* [out] */LPUNKNOWN* ppiunkItem, /* [out] */LPTYPEINFO* ppti) { HRESULT hr = S_OK; METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) USES_CONVERSION; TRACE("GetItemInfo: Name = %s Mask = %x\n", OLE2CT(pstrName), dwReturnMask); if (dwReturnMask & SCRIPTINFO_ITYPEINFO) { if (!ppti) return E_INVALIDARG; *ppti = NULL; } if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { if (!ppiunkItem) return E_INVALIDARG; *ppiunkItem = NULL; } // Global object if (!_wcsicmp(ACTIVS_HOST, pstrName)) { if (dwReturnMask & SCRIPTINFO_ITYPEINFO) { CLSID clsid = CLSID_NULL; pThis->GetDispatchIID( &clsid ); pThis->GetTypeInfoOfGuid(0 /* lcid unknown! */, clsid, ppti); if (*ppti) (*ppti)->AddRef(); // because returning } if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { *ppiunkItem = pThis->GetIDispatch(TRUE); (*ppiunkItem)->AddRef(); // because returning } return S_OK; } // Check map for named item LPUNKNOWN lpUnknown = NULL; if (!(pThis->mapNamedItems.Lookup(OLE2CT(pstrName), (LPVOID&) lpUnknown))) { return TYPE_E_ELEMENTNOTFOUND; } ASSERT(NULL != lpUnknown); if (NULL == lpUnknown) { TRACE("No IUnknown for item!\n"); // This shouldn't ever happen, since we're providing the items return E_FAIL; } if (dwReturnMask & SCRIPTINFO_ITYPEINFO) { // Use IProvideClassInfo to get ITypeInfo of coclass! IProvideClassInfo *pci = NULL; hr = lpUnknown->QueryInterface(IID_IProvideClassInfo, (void**)&pci); if (SUCCEEDED(hr) && pci) hr = pci->GetClassInfo(ppti); else { CLSID clsid = CLSID_NULL; pThis->GetDispatchIID( &clsid ); hr = LoadTypeInfoFromModule(clsid, ppti); } // Release interface if (pci) pci->Release(); if (FAILED(hr)) return E_FAIL; } if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { *ppiunkItem = lpUnknown; (*ppiunkItem)->AddRef(); // because returning } return S_OK; } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::GetDocVersionString STDMETHODIMP CActiveScriptHost::XActiveScriptSite::GetDocVersionString(LPBSTR pbstrVersion) { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) return E_NOTIMPL; } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::OnScriptTerminate STDMETHODIMP CActiveScriptHost::XActiveScriptSite::OnScriptTerminate( /* [in] */ const VARIANT* pvarResult, /* [in] */ const EXCEPINFO* pexcepinfo) { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) m_running = FALSE; return S_OK; } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::OnStateChange STDMETHODIMP CActiveScriptHost::XActiveScriptSite::OnStateChange( /* [in] */ SCRIPTSTATE ssScriptState) { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) return S_OK; } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::OnScriptError STDMETHODIMP CActiveScriptHost::XActiveScriptSite::OnScriptError( /* [in] */ IActiveScriptError* pse) { METHOD_PROLOGUE_EX(CActiveScriptHost, ActiveScriptSite) EXCEPINFO ei; DWORD dwSrcContext; ULONG ulLine; LONG ichError; BSTR bstrLine = NULL; CString strError; pse->GetExceptionInfo(&ei); pse->GetSourcePosition(&dwSrcContext, &ulLine, &ichError); pse->GetSourceLineText(&bstrLine); CString desc; CString src; desc = (LPCWSTR)ei.bstrDescription; src = (LPCWSTR)ei.bstrSource; strError.Format("%s\nSrc: %s\nLine:%d Error:%d Scode:%x", desc, src, ulLine, (int)ei.wCode, ei.scode); pGlobalDialog->AddCommsDebugString("SCRIPT ERROR!!!!!!"); pGlobalDialog->AddCommsDebugString(strError); pGlobalDialog->SetLastScriptErrorString(strError); m_running = FALSE; TRACE(strError); TRACE("\n"); //AfxMessageBox(strError, MB_SETFOREGROUND); return S_OK; } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::OnEnterScript STDMETHODIMP CActiveScriptHost::XActiveScriptSite::OnEnterScript() { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) TRACE("OnEnterScript\n"); //CActiveScriptHost::_OnEnterScript() return S_OK; } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSite::OnLeaveScript STDMETHODIMP CActiveScriptHost::XActiveScriptSite::OnLeaveScript() { METHOD_PROLOGUE(CActiveScriptHost, ActiveScriptSite) TRACE("OnLeaveScript\n"); m_running = FALSE; //_OnLeaveScript() return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IActiveScriptSiteWindow Implementation /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSiteWindow::AddRef STDMETHODIMP_(ULONG) CActiveScriptHost::XActiveScriptSiteWindow::AddRef() { METHOD_PROLOGUE_EX_(CActiveScriptHost, ActiveScriptSiteWindow) return pThis->ExternalAddRef(); } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSiteWindow::Release STDMETHODIMP_(ULONG) CActiveScriptHost::XActiveScriptSiteWindow::Release() { METHOD_PROLOGUE_EX_(CActiveScriptHost, ActiveScriptSiteWindow) return pThis->ExternalRelease(); } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSiteWindow::QueryInterface STDMETHODIMP CActiveScriptHost::XActiveScriptSiteWindow::QueryInterface(REFIID iid, LPVOID* ppvObj) { METHOD_PROLOGUE_EX_(CActiveScriptHost, ActiveScriptSiteWindow) return pThis->ExternalQueryInterface(&iid, ppvObj); } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSiteWindow::EnableModeless STDMETHODIMP CActiveScriptHost::XActiveScriptSiteWindow::EnableModeless(BOOL fEnable) { METHOD_PROLOGUE_EX_(CActiveScriptHost, ActiveScriptSiteWindow) return S_OK; } /////////////////////////////////////////////////////////////////////////////// // XActiveScriptSiteWindow::GetWindow STDMETHODIMP CActiveScriptHost::XActiveScriptSiteWindow::GetWindow(HWND* phWnd) { METHOD_PROLOGUE_EX_(CActiveScriptHost, ActiveScriptSiteWindow) *phWnd = pThis->m_hHostWnd; if (*phWnd) return S_OK; return E_FAIL; } /////////////////////////////////////////////////////////////////////////////// // LoadTypeInfoFromModule HRESULT LoadTypeInfoFromModule(REFIID riid, ITypeInfo **ppti) { *ppti = 0; char szFileName[MAX_PATH]; GetModuleFileNameA(0, szFileName, MAX_PATH); OLECHAR wszFileName[MAX_PATH]; mbstowcs(wszFileName, szFileName, MAX_PATH); ITypeLib *ptl = 0; HRESULT hr = LoadTypeLib(wszFileName, &ptl); if (SUCCEEDED(hr)) { hr = ptl->GetTypeInfoOfGuid(riid, ppti); ptl->Release(); } return hr; }