//____________________________________________________________________________
//
//  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();
}