|
|
//____________________________________________________________________________
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: ScriptHost.cpp
//
// Contents: CScriptHostMgr & CScriptHost implementation.
//
// History: 11/05/1999 AnandhaG Created
//____________________________________________________________________________
//
#include "stdafx.h"
#include "scripthost.h"
//+-------------------------------------------------------------------
// MMCObjectName is the name scripts will use to refer to mmc object.
//
// Example:
//
// Dim doc
// Dim snapins
// Set doc = MMCApplication.Document
// Set snapins = doc.snapins
// snapins.Add "{58221c66-ea27-11cf-adcf-00aa00a80033}" ' the services snap-in
//
//+-------------------------------------------------------------------
const LPOLESTR MMCObjectName = OLESTR("MMCApplication");
//+-------------------------------------------------------------------
//
// Member: CScriptHostMgr::ScInitScriptHostMgr
//
// Synopsis: Get the ITypeInfo of this instance of mmc.
//
// Arguments: [pDispatch]
//
// Returns: SC
//
//--------------------------------------------------------------------
CScriptHostMgr::CScriptHostMgr(LPDISPATCH pDispatch) { m_spMMCObjectDispatch = pDispatch;
// It is ok if below fails. These interfaces (dispatch & typeinfo) are required
// in CScriptHost::GetItemInfo method, so that this object can be given to engine.
pDispatch->GetTypeInfo(1, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &m_spMMCObjectTypeInfo); }
CScriptHostMgr::~CScriptHostMgr() { DECLARE_SC(sc, _T("CScriptHostMgr::~CScriptHostMgr"));
// The script manager is going away so ask all the script
// hosts to finish their scripts & then destroy them.
sc = ScDestroyScriptHosts(); }
SC CScriptHostMgr::ScGetMMCObject(LPUNKNOWN *ppunkItem) { DECLARE_SC(sc, TEXT("CScriptHostMgr::ScGetMMCObject")); sc = ScCheckPointers(ppunkItem); if (sc) return sc;
if (m_spMMCObjectDispatch) { *ppunkItem = m_spMMCObjectDispatch; return sc; }
return (sc = E_FAIL); }
SC CScriptHostMgr::ScGetMMCTypeInfo(LPTYPEINFO *ppTypeInfo) { DECLARE_SC(sc, TEXT("CScriptHostMgr::ScGetMMCObject")); sc = ScCheckPointers(ppTypeInfo); if (sc) return sc;
if (m_spMMCObjectDispatch) { *ppTypeInfo = m_spMMCObjectTypeInfo; return sc; }
return (sc = E_FAIL); }
//+-------------------------------------------------------------------
//
// Member: ScGetScriptEngineFromExtn
//
// Synopsis: Using the file extension get the script engine & Clsid.
//
// Arguments: [strFileExtn] - Script extension.
// [strScriptEngine] - Type script.
// [rClsid] - CLSID of engine.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHostMgr::ScGetScriptEngineFromExtn(const tstring& strFileExtn, tstring& strScriptEngine, CLSID& rClsid) { DECLARE_SC(sc, _T("CScriptHostMgr::ScGetScriptEngine"));
CRegKey regKey;
// Open the extension.
LONG lRet = regKey.Open(HKEY_CLASSES_ROOT, strFileExtn.data(), KEY_READ); if (ERROR_SUCCESS != lRet) { sc.FromWin32(lRet); return sc; }
TCHAR szTemp[MAX_PATH]; DWORD dwLen = MAX_PATH; tstring strTemp; // Read the default value, the location of file association data.
lRet = regKey.QueryValue(szTemp, NULL, &dwLen); if (ERROR_SUCCESS != lRet) { sc.FromWin32(lRet); return sc; } ASSERT(dwLen > 0);
// Open the HKCR/FileAssocLoc/ScriptEngine.
strTemp = szTemp; strTemp += _T("\\"); strTemp += SCRIPT_ENGINE_KEY;
lRet = regKey.Open(HKEY_CLASSES_ROOT, strTemp.data(), KEY_READ); if (ERROR_SUCCESS != lRet) { sc.FromWin32(lRet); return sc; }
// Now read the ScriptEngine default value.
dwLen = MAX_PATH; lRet = regKey.QueryValue(szTemp, NULL, &dwLen); if (ERROR_SUCCESS != lRet) { sc.FromWin32(lRet); return sc; } ASSERT(dwLen > 0);
strScriptEngine = szTemp;
// Read HKCR/ScriptEngine/CLSID for ScriptEngine clsid.
strTemp = strScriptEngine + _T("\\"); strTemp += CLSIDSTR;
lRet = regKey.Open(HKEY_CLASSES_ROOT, strTemp.data(), KEY_READ); if (ERROR_SUCCESS != lRet) { sc.FromWin32(lRet); return sc; }
// Read the CLSID value.
dwLen = MAX_PATH; lRet = regKey.QueryValue(szTemp, NULL, &dwLen); if (ERROR_SUCCESS != lRet) { sc.FromWin32(lRet); return sc; } ASSERT(dwLen > 0);
USES_CONVERSION; LPOLESTR lpClsid = T2OLE(szTemp); sc = CLSIDFromString(lpClsid, &rClsid); if (sc) return sc;
return (sc); }
//+-------------------------------------------------------------------
//
// Member: ScGetScriptEngine
//
// Synopsis: [strFileName] - Script file name.
// [eScriptType] - Type script.
// [rClsid] - CLSID of engine.
//
// Arguments:
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHostMgr::ScGetScriptEngine(const tstring& strFileName, tstring& strScriptEngine, CLSID& rClsid) { DECLARE_SC(sc, _T("CScriptHostMgr::ScGetScriptEngine"));
// Is this required, the file is already read.
// It is a file & it exists.
DWORD dwAttr = GetFileAttributes(strFileName.data()); if (-1 == dwAttr) { // What if lasterror is overwritten?
sc.FromWin32(::GetLastError()); return sc; }
// Get the extension (look for . from end).
int iPos = strFileName.rfind(_T('.')); tstring strExtn; if (-1 != iPos) { strExtn = strFileName.substr(iPos, strFileName.length()); } else { sc = E_UNEXPECTED; return sc; }
sc = ScGetScriptEngineFromExtn(strExtn, strScriptEngine, rClsid); if (sc) return sc;
return (sc); }
//+-------------------------------------------------------------------
//
// Member: ScLoadScriptFromFile
//
// Synopsis: Allocate memory & Load the script from the given file.
//
// Arguments: [strFileName] - File to be loaded.
// [pszScriptContents] - Memory buffer containing the script
// contents (See note).
//
// Note: The caller should call HeapFree() to free the pszScriptContents.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHostMgr::ScLoadScriptFromFile (const tstring& strFileName, LPOLESTR* pszScriptText) { DECLARE_SC(sc, _T("CScriptHostMgr::ScLoadScriptFromFile")); sc = ScCheckPointers(pszScriptText); if (sc) return sc; *pszScriptText = NULL;
// Open the file.
HANDLE hFile = ::CreateFile(strFileName.data(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if (hFile == INVALID_HANDLE_VALUE) { sc.FromWin32(::GetLastError()); return sc; }
HANDLE hFileMap = NULL; LPSTR pszMBCS = NULL;
DWORD dwFileSize = ::GetFileSize(hFile, NULL); if (dwFileSize == 0xFFFFFFFF) { sc.FromWin32(::GetLastError()); goto FileError; }
if (dwFileSize == 0) { sc = E_UNEXPECTED; goto FileError; }
// Create a file mapping object.
hFileMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL ); if (hFileMap == NULL) { sc.FromWin32(::GetLastError()); goto FileError; }
// Dummy block.
{ // Map the file into memory.
pszMBCS = (LPSTR) ::MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0 );
if (pszMBCS == NULL) { sc.FromWin32(::GetLastError()); goto FileMapError; }
// Get the size of buffer needed.
int n = ::MultiByteToWideChar(CP_ACP, 0, pszMBCS, dwFileSize, NULL, 0 );
//
// Allocate script text buffer. +1 for EOS.
//
LPOLESTR pszText; pszText = (LPOLESTR) ::HeapAlloc(::GetProcessHeap(), 0, (n + 2) * sizeof(wchar_t) ); if (pszText == NULL) { sc.FromWin32(::GetLastError()); goto FileAllocError; }
// Store file as WCHAR inthe buffer.
::MultiByteToWideChar(CP_ACP, 0, pszMBCS, dwFileSize, pszText, n ); //
// Remove legacy EOF character.
//
if (pszText[n - 1] == 0x1A) { pszText[n - 1] = '\n'; }
pszText[n] = '\n'; pszText[n + 1] = '\0';
*pszScriptText = pszText; }
FileAllocError: ::UnmapViewOfFile(pszMBCS);
FileMapError: ::CloseHandle(hFileMap);
FileError: ::CloseHandle(hFile);
//NoError:
return sc; }
//+-------------------------------------------------------------------
//
// Member: ScExecuteScript
//
// Synopsis: Execute given script file.
//
// Arguments: [strFileName] - The script file.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHostMgr::ScExecuteScript(const tstring& strFileName) { DECLARE_SC(sc, _T("CScriptHostMgr::ScExecuteScript"));
CHeapAllocMemPtr<OLECHAR> spszFileContents; sc = ScLoadScriptFromFile(strFileName, &spszFileContents); if (sc) return sc;
tstring strScriptEngine; CLSID EngineClsid; // Validate the file, get the script engine and script type.
sc = ScGetScriptEngine(strFileName, strScriptEngine, EngineClsid); if (sc) return sc;
sc = ScExecuteScriptHelper(spszFileContents, strScriptEngine, EngineClsid);
return sc; }
//+-------------------------------------------------------------------
//
// Member: ScExecuteScript
//
// Synopsis: Execute given script.
//
// Arguments: [pszScriptText] - The script itself.
// [strExtn] - The script file extension.
//
// Note: The extension is used to determine the script
// engine (as shell does).
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHostMgr::ScExecuteScript(LPOLESTR pszScriptText, const tstring& strExtn) { DECLARE_SC(sc, _T("CScriptHostMgr::ScExecuteScript"));
tstring strScriptEngine; CLSID EngineClsid; // Validate the file, get the script engine and script type.
sc = ScGetScriptEngineFromExtn(strExtn, strScriptEngine, EngineClsid); if (sc) return sc;
sc = ScExecuteScriptHelper(pszScriptText, strScriptEngine, EngineClsid);
return sc; }
//+-------------------------------------------------------------------
//
// Member: ScExecuteScriptHelper
//
// Synopsis: Helper for ScExecuteScript, Create the Script Host &
// asks it to run the script.
//
// Arguments: [pszScriptText] - The script contents.
// [strScriptEngine] - The script engine name.
// [EngineClsid]
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHostMgr::ScExecuteScriptHelper (LPCOLESTR pszScriptText, const tstring strScriptEngine, const CLSID& EngineClsid) { DECLARE_SC(sc, _T("ScExecuteScriptHelper"));
// Create CScriptHost and ask it to run the script.
CComObject<CScriptHost>* pScriptHost = NULL; sc = CComObject<CScriptHost>::CreateInstance(&pScriptHost); if (sc) return sc;
if (NULL == pScriptHost) return (sc = E_FAIL);
IUnknownPtr spUnknown = pScriptHost; if (NULL == spUnknown) return (sc = E_UNEXPECTED);
m_ArrayOfHosts.push_back(spUnknown);
sc = pScriptHost->ScRunScript(this, pszScriptText, strScriptEngine, EngineClsid); if (sc) return sc;
return (sc); }
//+-------------------------------------------------------------------
//
// Member: ScDestroyScriptHosts
//
// Synopsis: Stop all the running scripts and destroy all
// script hosts.
//
// Arguments:
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHostMgr::ScDestroyScriptHosts() { DECLARE_SC(sc, _T("CScriptHostMgr::ScStopAllScripts"));
// Ask each script host created to stop its script.
ArrayOfScriptHosts::iterator it = m_ArrayOfHosts.begin(); for (;it != m_ArrayOfHosts.end(); ++it) { CScriptHost* pScriptHost = dynamic_cast<CScriptHost*>(it->GetInterfacePtr()); sc = ScCheckPointers(pScriptHost, E_UNEXPECTED); if (sc) return sc;
sc = pScriptHost->ScStopScript(); }
// This clear will call release on the IUnknown smart-pointers (that are in this array).
m_ArrayOfHosts.clear();
return sc; }
CScriptHost::CScriptHost() : m_pScriptHostMgr(NULL) { }
CScriptHost::~CScriptHost() { }
//+-------------------------------------------------------------------
//
// Member: ScRunScript
//
// Synopsis: Run the given script
//
// Arguments: [pMgr] - Object that manages all CScriptHosts.
// [strScript] - The script itself.
// [strEngineName] - Script engine name.
// [rEngineClsid] - The script engine that runs this script.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHost::ScRunScript(CScriptHostMgr* pMgr, LPCOLESTR pszScriptText, const tstring& strEngineName, const CLSID& rEngineClsid) { DECLARE_SC(sc, _T("CScriptHost::ScRunScript"));
m_pScriptHostMgr = pMgr; sc = ScCheckPointers(m_pScriptHostMgr, E_UNEXPECTED); if (sc) return sc;
m_strScriptEngine = strEngineName; m_EngineClsid = rEngineClsid;
// Now create the script engine.
LPUNKNOWN* pUnknown = NULL; sc = CoCreateInstance(m_EngineClsid, NULL, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void **)&m_spActiveScriptEngine); if (sc) return sc;
m_spActiveScriptParser = m_spActiveScriptEngine; if (NULL == m_spActiveScriptParser) { m_spActiveScriptEngine = NULL; // Release the engine.
return (sc = E_FAIL); }
sc = m_spActiveScriptEngine->SetScriptSite(this); if (sc) return sc;
sc = m_spActiveScriptParser->InitNew(); if (sc) return sc;
// Add MMC objects to the top-level.
sc = m_spActiveScriptEngine->AddNamedItem(MMCObjectName, SCRIPTITEM_ISSOURCE | SCRIPTITEM_GLOBALMEMBERS | SCRIPTITEM_ISVISIBLE); if (sc) { m_spActiveScriptEngine = NULL; m_spActiveScriptParser = NULL; return sc; }
sc = m_spActiveScriptParser->ParseScriptText(pszScriptText, NULL, NULL, NULL, 0, 0, 0L, NULL, NULL); if (sc) { m_spActiveScriptEngine = NULL; m_spActiveScriptParser = NULL; return sc; }
sc = m_spActiveScriptEngine->SetScriptState(SCRIPTSTATE_CONNECTED); if (sc) { m_spActiveScriptEngine = NULL; m_spActiveScriptParser = NULL; return sc; }
return sc; }
//+-------------------------------------------------------------------
//
// Member: ScStopScript
//
// Synopsis: Stop the script engine.
//
// Arguments:
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScriptHost::ScStopScript () { DECLARE_SC(sc, _T("CScriptHost::ScStopScript"));
sc = ScCheckPointers(m_spActiveScriptEngine, E_UNEXPECTED); if (sc) return sc;
sc = m_spActiveScriptEngine->SetScriptState(SCRIPTSTATE_DISCONNECTED); sc = m_spActiveScriptEngine->Close();
return (sc); }
//+-------------------------------------------------------------------
//
// Member: GetLCID
//
// Synopsis: Return the Lang Id to Script engine.
//
// Arguments: [plcid] - Language Identifier.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::GetLCID( LCID *plcid) { DECLARE_SC(sc, _T("CScriptHost::GetLCID")); sc = ScCheckPointers(plcid); if (sc) return sc.ToHr();
*plcid = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
return sc.ToHr(); }
//+-------------------------------------------------------------------
//
// Member: GetItemInfo
//
// Synopsis: Return IUnknown or ITypeInfo of the item added using
// IActiveScript::AddNamedItem. Called by script engine.
//
// Arguments: [pstrName] - The item that was added.
// [dwReturnMask] - Request (IUnknown or ITypeInfo).
// [ppunkItem] - IUnknown returned if requested.
// [ppTypeInfo] - ITypeInfo returned if requested.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::GetItemInfo( LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppTypeInfo) { DECLARE_SC(sc, _T("CScriptHost::GetItemInfo"));
// The IUnknown** & ITypeInfo** can be NULL.
if (ppunkItem) *ppunkItem = NULL;
if (ppTypeInfo) *ppTypeInfo = NULL;
// Make sure it is our object being requested.
if (_wcsicmp(MMCObjectName, pstrName)) return (sc = TYPE_E_ELEMENTNOTFOUND).ToHr();
sc = ScCheckPointers(m_pScriptHostMgr, E_UNEXPECTED); if (sc) return sc.ToHr();
if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { if (ppunkItem) { sc = m_pScriptHostMgr->ScGetMMCObject(ppunkItem); if (sc) return sc.ToHr();
(*ppunkItem)->AddRef(); } else return (sc = E_POINTER).ToHr(); }
if (dwReturnMask & SCRIPTINFO_ITYPEINFO) { if (ppTypeInfo) { sc = m_pScriptHostMgr->ScGetMMCTypeInfo(ppTypeInfo); if (sc) return sc.ToHr();
(*ppTypeInfo)->AddRef(); } else return (sc = E_POINTER).ToHr();
}
return sc.ToHr(); }
//+-------------------------------------------------------------------
//
// Member: GetDocVersionString
//
// Synopsis: This retrieves a host-defined string that uniquely
// identifies the current script (document) version from
// the host's point of view. Called by script engine.
//
// Arguments: [pbstrVersionString] - The doc version string.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::GetDocVersionString( BSTR *pbstrVersionString) { DECLARE_SC(sc, _T("CScriptHost::GetDocVersionString"));
return E_NOTIMPL; }
//+-------------------------------------------------------------------
//
// Member: OnScriptTerminate
//
// Synopsis: Called by engine when the script has completed execution.
//
// Arguments: [pvarResult] - Script results.
// [pexcepinfo] - Any exceptions generated.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::OnScriptTerminate( const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) { DECLARE_SC(sc, _T("CScriptHost::OnScriptTerminate"));
return sc.ToHr(); }
//+-------------------------------------------------------------------
//
// Member: OnStateChange
//
// Synopsis: Called by engine when its state changes.
//
// Arguments: [ssScriptState] - New state.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::OnStateChange(SCRIPTSTATE ssScriptState) { DECLARE_SC(sc, _T("CScriptHost::OnStateChange"));
return sc.ToHr(); }
//+-------------------------------------------------------------------
//
// Member: OnScriptError
//
// Synopsis: Engine informs that an execution error occurred
// while it was running the script.
//
// Arguments: [pase ] - Host can obtain info about execution
// error using this interface.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::OnScriptError(IActiveScriptError *pase) { DECLARE_SC(sc, _T("CScriptHost::OnScriptError")); sc = ScCheckPointers(pase); if (sc) return sc.ToHr();
// For test purposes. We need to provide much better debug info,
// We will hookup the ScriptDebugger for this.
BSTR bstrSourceLine; sc = pase->GetSourceLineText(&bstrSourceLine);
EXCEPINFO exinfo; ZeroMemory(&exinfo, sizeof(exinfo)); sc = pase->GetExceptionInfo(&exinfo);
DWORD dwSourceContext = 0; ULONG ulLineNumber = -1; LONG lCharPos = -1; sc = pase->GetSourcePosition(&dwSourceContext, &ulLineNumber, &lCharPos);
return sc.ToHr(); }
//+-------------------------------------------------------------------
//
// Member: OnEnterScript
//
// Synopsis: Engine informs that it has begun executing script.
//
// Arguments:
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::OnEnterScript(void) { DECLARE_SC(sc, _T("CScriptHost::OnEnterScript"));
return sc.ToHr(); }
//+-------------------------------------------------------------------
//
// Member: OnEnterScript
//
// Synopsis: Engine informs that it has returned from executing script.
//
// Arguments:
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::OnLeaveScript(void) { DECLARE_SC(sc, _T("CScriptHost::OnLeaveScript"));
return sc.ToHr(); }
//+-------------------------------------------------------------------
//
// Member: GetWindow
//
// Synopsis: Engine asks for window that can be parent of a popup
// it can display.
//
// Arguments: [phwnd ] - Parent window.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::GetWindow(HWND *phwnd) { DECLARE_SC(sc, _T("CScriptHost::GetWindow"));
return sc.ToHr(); }
//+-------------------------------------------------------------------
//
// Member: EnableModeless
//
// Synopsis: Enables/Disables modelessness of parent window.
//
// Arguments: [fEnable ] - Enable/Disable.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
STDMETHODIMP CScriptHost::EnableModeless(BOOL fEnable) { DECLARE_SC(sc, _T("CScriptHost::EnableModeless"));
return sc.ToHr(); }
|