|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995
//
// File: bscript.cxx
//
// Contents: Implementation of CBServerScript
//
//----------------------------------------------------------------------------
#include "headers.hxx"
CScriptHost::CScriptHost(CMTScript * pMT, BOOL fPrimary, BOOL fDispatchOnly) : _pMT(pMT), _fIsPrimaryScript(fPrimary) { _ulRefs = 1;
VariantInit(&_vPubCache); VariantInit(&_vPrivCache);
Assert(_dwPublicSN == 0); Assert(_dwPrivateSN == 0); }
CScriptHost::~CScriptHost() { int i;
// Any thread can call the dtor.
WHEN_DBG(_dwThreadId = GetCurrentThreadId()); AssertSz(PopScript() == S_FALSE, "Script object not closed properly!");
VariantClear(&_vPubCache); VariantClear(&_vPrivCache);
for (i = 0; i < _aryEvtSinks.Size(); i++) { _aryEvtSinks[i]->Disconnect(); }
_aryEvtSinks.ReleaseAll();
ReleaseInterface(_pTypeInfoIGlobalMTScript); ReleaseInterface(_pTypeInfoCMTScript); }
HRESULT CScriptHost::QueryInterface(REFIID iid, void **ppvObj) { if (iid == IID_IGlobalMTScript || iid == IID_IUnknown || iid == IID_IDispatch) { *ppvObj = (IGlobalMTScript *)this; } else { *ppvObj = NULL; return E_NOINTERFACE; }
((IUnknown *)*ppvObj)->AddRef(); return S_OK; }
DWORD CScriptHost::ThreadMain() { HRESULT hr; CStr cstrScript; VARIANT varParam; SCRIPT_PARAMS *pscrParams;
VariantInit(&varParam);
VERIFY_THREAD();
pscrParams = (SCRIPT_PARAMS*)_pvParams;
cstrScript.Set(pscrParams->pszPath);
#if DBG == 1
char achBuf[10]; cstrScript.GetMultiByte(achBuf, 10); SetName(achBuf); #endif
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY); if (!SUCCEEDED(hr)) { ThreadStarted(hr); // Free our creating thread
goto Cleanup; }
if (pscrParams->pvarParams) { if (V_VT(pscrParams->pvarParams) == VT_DISPATCH) { // Unmarshal the IDispatch pointer being handed to us from the
// other thread.
IDispatch *pDisp; DWORD dwCookie = V_I4(pscrParams->pvarParams);
hr = _pMT->_pGIT->GetInterfaceFromGlobal(dwCookie, IID_IDispatch, (LPVOID*)&pDisp); if (!hr) { V_VT(&varParam) = VT_DISPATCH; V_DISPATCH(&varParam) = pDisp; } } else { VariantCopy(&varParam, pscrParams->pvarParams); } }
// Hold a reference on ourself while the script is running
AddRef();
if (_fIsPrimaryScript) {
hr = THR(LoadTypeLibrary());
// Ensure that ScriptMain() completes before we fire any other events.
_fDontHandleEvents = TRUE; }
if (hr) { ThreadStarted(hr); goto Cleanup; } hr = ExecuteTopLevelScript(cstrScript, &varParam); if (hr) { ThreadStarted(hr); TraceTag((tagError, "Failed to execute script: %x", hr)); AssertSz(!_fIsPrimaryScript, "Failed to execute script");
PostQuitMessage(0); goto Cleanup; } ThreadStarted(hr); FireEvent(DISPID_MTScript_ScriptMain, 0, NULL); //
// Secondary scripts go away as soon as they're done.
//
if (_fIsPrimaryScript) { DWORD dwRet;
_fDontHandleEvents = FALSE;
dwRet = MessageEventPump(TRUE);
AssertSz(dwRet == MEP_EXIT, "NONFATAL: Invalid return value from MessageEventPump!"); } else { CScriptHost *pThis = this;
PostToThread(_pMT, MD_SECONDARYSCRIPTTERMINATE, (LPVOID)&pThis, sizeof(CScriptHost*)); }
Cleanup: CloseScripts();
VariantClear(&varParam);
if (_fIsPrimaryScript) { int i;
for (i = 0; i < s_arySyncEvents.Size(); i++) { CloseHandle(s_arySyncEvents[i]._hEvent); s_arySyncEvents[i]._cstrName.Free(); }
s_arySyncEvents.DeleteAll();
for (i = 0; i < (int)s_cThreadLocks; i++) { DeleteCriticalSection(&s_aThreadLocks[i]._csLock); s_aThreadLocks[i]._cstrName.Free(); }
memset(&s_aThreadLocks, 0, sizeof(s_aThreadLocks)); s_cThreadLocks = 0; }
Release(); CoUninitialize(); return 0; }
//+---------------------------------------------------------------------------
//
// Member: CScriptHost::MessageEventPump, public
//
// Synopsis: Empties our message queues (both windows' and our private
// threadcomm queue)
//
// Arguments: [fWait] -- If TRUE, will not return until an event occurs
// [cEvents] -- Count of events to monitor
// [pEvents] -- Pointer to list of event handles
// [fAll] -- If TRUE, don't return until all handles in
// pEvents are signaled.
// [dwTimeout] -- Timeout after this many ms if nothing signals
// [fNoEvents] -- If TRUE, don't fire events while waiting
//
// Returns: MEP_TIMEOUT: The given timeout period expired without any
// event objects becoming signaled. Returned only
// if dwTimeout != INFINITE
// MEP_EXIT: An event occurred which is causing this thread to
// terminate. The caller should clean up and finish
// what it's doing.
// MEP_FALLTHROUGH: Indicates that no objects signaled.
// Returned only if fWait==FALSE.
// MEP_EVENT_0: If one (or all if fAll==TRUE) of the passed-in
// event handles became signaled. The index of the
// signaled handle is added to MEP_EVENT_0. Returned
// only if one or more event handles were passed in.
//
//----------------------------------------------------------------------------
DWORD CScriptHost::MessageEventPump(BOOL fWait, UINT cEvents /* = 0 */, HANDLE *pEvents /* = NULL */, BOOL fAll /* = FALSE */, DWORD dwTimeout /* = INFINITE */, BOOL fNoEvents /* = FALSE */) { CStackPtrAry<HANDLE, 5> aryHandles;
MSG msg; DWORD dwRet; DWORD mepReturn = MEP_FALLTHROUGH;
_int64 i64Freq = 0; _int64 i64Time; _int64 i64Goal = 0; long lTimeout = dwTimeout; BOOL fTimeout = dwTimeout != INFINITE;
if (cEvents) { aryHandles.CopyIndirect(cEvents, pEvents, FALSE); }
if (_fMustExitThread) { return MEP_EXIT; }
// WARNING! aryHandles will get rebuilt under certain conditions below.
// If you add code which adds handles to the array, you must update the
// code below as well!
if (!fNoEvents && !_fDontHandleEvents) { aryHandles.Insert(0, _hCommEvent); } else if (fNoEvents) { _fDontHandleEvents = TRUE; }
if (fTimeout) { QueryPerformanceFrequency((LARGE_INTEGER*)&i64Freq); QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);
// Resolution must be at least milliseconds
Assert(i64Freq >= 1000);
// Compute the time when the timer will be complete, converted to ms
i64Goal = ((i64Time * 1000) / i64Freq) + lTimeout; }
do { //
// Purge out all window messages (primarily for OLE's benefit).
//
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { _fMustExitThread = TRUE; return MEP_EXIT; }
TranslateMessage(&msg); DispatchMessage(&msg); }
if (_fMustExitThread) { AbortScripts(); return MEP_EXIT; }
dwRet = MsgWaitForMultipleObjects(aryHandles.Size(), aryHandles, FALSE, (fWait) ? (DWORD)lTimeout : 0, QS_ALLINPUT);
if (dwRet == WAIT_OBJECT_0 && !_fDontHandleEvents) { //
// Another thread is sending us a message.
//
HandleThreadMessage(); } else if (dwRet < WAIT_OBJECT_0 + aryHandles.Size()) { Assert(cEvents);
int iEvent = dwRet - WAIT_OBJECT_0;
//
// One of the events the script is waiting for has been signaled.
//
if (fAll) { // They want to wait for all the events. Remove the signaled
// event from the array and if it's the last one then we're
// there!
aryHandles.Delete(iEvent);
if (aryHandles.Size() == ((_fDontHandleEvents) ? 0 : 1)) { // All the events have come back signaled. Check that none
// have become unsignaled.
if (WaitForMultipleObjects(cEvents, pEvents, TRUE, 0) == WAIT_TIMEOUT) { // Something became unsignaled. Start over! Rebuild
// the array of handles.
aryHandles.CopyIndirect(cEvents, pEvents, FALSE);
if (!_fDontHandleEvents) { aryHandles.Insert(0, _hCommEvent); } } else { mepReturn = MEP_EVENT_0;
break; } } } else { mepReturn = MEP_EVENT_0 + iEvent;
if (!_fDontHandleEvents) { mepReturn--; }
break; } } else if (dwRet == WAIT_OBJECT_0 + aryHandles.Size()) { //
// A windows message came through. It will be handled at the
// top of the loop.
//
} else if (dwRet == WAIT_FAILED) { TraceTag((tagError, "WaitForMultipleObjects failure (%d)", GetLastError()));
AssertSz(FALSE, "WaitForMultipleObjects failure");
_fMustExitThread = TRUE;
mepReturn = MEP_EXIT;
break; } else { Assert(dwRet == WAIT_TIMEOUT);
mepReturn = MEP_TIMEOUT;
break; }
// Since any number of things could have brought us out of MWFMO,
// we need to compute the remaining timeout for the next time around.
if (fTimeout) { QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);
// Convert current time to milliseconds.
i64Time = ((i64Time * 1000) / i64Freq);
// Compute the delta between the current time and our goal
lTimeout = (DWORD)(i64Goal - i64Time);
// Are we timed out?
if (lTimeout <= 0) { mepReturn = MEP_TIMEOUT;
break; } } } while (fWait); // Only do the loop once if fWait == FALSE
if (fNoEvents) { _fDontHandleEvents = FALSE; }
// MEP_FALLTHROUGH is not a valid return if fWait == TRUE
Assert(!fWait || mepReturn != MEP_FALLTHROUGH);
return mepReturn; }
void CScriptHost::HandleThreadMessage() { VERIFY_THREAD();
THREADMSG tm; BYTE bData[MSGDATABUFSIZE]; DWORD cbData;
if (_fDontHandleEvents) return;
//
//$ FUTURE: Add a way to filter messages so we can check for MD_PLEASEEXIT
// without pulling off the event messages
//
while (GetNextMsg(&tm, (void **)bData, &cbData)) { switch (tm) { case MD_PLEASEEXIT: //
// We're being asked to terminate.
//
AbortScripts(); PostQuitMessage(0); break;
case MD_MACHINECONNECT: AssertSz(_fIsPrimaryScript, "Non-primary script got machine event!");
_fDontHandleEvents = TRUE;
FireEvent(DISPID_MTScript_OnMachineConnect, 0, NULL);
_fDontHandleEvents = FALSE; break;
case MD_MACHEVENTCALL: AssertSz(_fIsPrimaryScript, "Non-primary script got machine event!"); Assert(cbData == sizeof(MACHPROC_EVENT_DATA*));
_fDontHandleEvents = TRUE;
// This call will set the event object in the
// MACHPROC_EVENT_DATA struct when everything completes.
FireMachineEvent(*(MACHPROC_EVENT_DATA**)bData, TRUE);
_fDontHandleEvents = FALSE; break;
case MD_PROCESSDATA: Assert(cbData == sizeof(MACHPROC_EVENT_DATA*));
_fDontHandleEvents = TRUE;
// This call will set the event object in the
// MACHPROC_EVENT_DATA struct when everything completes.
FireMachineEvent(*(MACHPROC_EVENT_DATA**)bData, FALSE);
_fDontHandleEvents = FALSE; break;
case MD_PROCESSEXITED: case MD_PROCESSTERMINATED: case MD_PROCESSCONNECTED: case MD_PROCESSCRASHED: Assert(cbData == sizeof(CProcessThread*));
_fDontHandleEvents = TRUE;
FireProcessEvent(tm, *(CProcessThread**)bData);
_fDontHandleEvents = FALSE;
break;
default: AssertSz(FALSE, "CScriptHost got a message it couldn't handle!"); break; } } }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::PushScript
//
// Create a new script site/engine and push it on the script stack
//
//---------------------------------------------------------------------------
HRESULT CScriptHost::PushScript(TCHAR *pchName) { VERIFY_THREAD();
HRESULT hr; CScriptSite * pScriptSite; TCHAR * pchFile;
hr = LoadTypeLibrary(); if (hr) goto Cleanup;
pScriptSite = new CScriptSite(this); if(!pScriptSite) { hr = E_OUTOFMEMORY; goto Cleanup; }
pchFile = _tcsrchr(pchName, _T('\\')); if (!pchFile) { pchFile = pchName; } else pchFile++;
hr = pScriptSite->Init(pchFile); if (hr) { delete pScriptSite; pScriptSite = NULL; goto Cleanup; }
pScriptSite->_pScriptSitePrev = _pScriptSite; _pScriptSite = pScriptSite;
Cleanup: RRETURN(hr); }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::PopScript
//
// Pop last script site/engine off the script stack
//
//---------------------------------------------------------------------------
HRESULT CScriptHost::PopScript() { VERIFY_THREAD();
CScriptSite * pScriptSite = _pScriptSite;
if(!_pScriptSite) return S_FALSE;
_pScriptSite = _pScriptSite->_pScriptSitePrev;
pScriptSite->Close(); pScriptSite->Release();
return S_OK; }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::CloseScripts
//
// Clear the stack of script engines
//
//---------------------------------------------------------------------------
HRESULT CScriptHost::CloseScripts() { VERIFY_THREAD();
while(PopScript() == S_OK) ;
AssertSz(_pScriptSite == NULL, "Should have released script site");
return S_OK; }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::AbortScripts
//
// Clear the stack of script engines
//
//---------------------------------------------------------------------------
HRESULT CScriptHost::AbortScripts() { VERIFY_THREAD();
// Make sure we're not stuck on MsgWaitForMultipleObjects and that we
// never will be again.
_fMustExitThread = TRUE; SetEvent(_hCommEvent);
CScriptSite * pScriptSite;
pScriptSite = _pScriptSite;
while (pScriptSite) { pScriptSite->Abort();
pScriptSite = pScriptSite->_pScriptSitePrev; }
return S_OK; }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::ExecuteTopLevelScript
//
// Close previous top level script engine then load and execute script
// in a new top level script engine
//
//---------------------------------------------------------------------------
HRESULT CScriptHost::ExecuteTopLevelScript(TCHAR * pchPath, VARIANT *pvarParams) { VERIFY_THREAD();
HRESULT hr;
// Stablize reference count during script execution.
// Script can hide window which decrements reference count.
AddRef();
// Getting read to close the scripts fire unload event.
CloseScripts();
hr = THR(PushScript(pchPath)); if(hr) goto Cleanup;
hr = THR(VariantCopy(&_pScriptSite->_varParam, pvarParams)); if (hr) goto Cleanup;
hr = THR(_pScriptSite->ExecuteScriptFile(pchPath)); if(hr) goto Cleanup;
hr = THR(_pScriptSite->SetScriptState(SCRIPTSTATE_CONNECTED)); if (hr) goto Cleanup;
Cleanup: Release(); RRETURN(hr); }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::ExecuteScriptlet
//
// Add a scriptlet to the current top level script engine and execute it
//
//---------------------------------------------------------------------------
HRESULT CScriptHost::ExecuteTopLevelScriptlet(TCHAR * pchScript) { VERIFY_THREAD();
HRESULT hr;
// Stablize reference count during script execution.
// Script can hide window which decrements reference count.
AddRef();
if(!_pScriptSite) { hr = THR(PushScript(_T("Scriptlet"))); if(hr) goto Cleanup; } else { Assert(_pScriptSite->_pScriptSitePrev == NULL); }
hr = THR(_pScriptSite->ExecuteScriptStr(pchScript)); if (hr) goto Cleanup;
hr = THR(_pScriptSite->SetScriptState(SCRIPTSTATE_CONNECTED));
Cleanup: Release(); RRETURN(hr); }
//+---------------------------------------------------------------------------
//
// Member: CScriptHost::FireProcessEvent, public
//
// Synopsis: Fires an OnProcessEvent event into the script
//
//----------------------------------------------------------------------------
void CScriptHost::FireProcessEvent(THREADMSG tm, CProcessThread *pProc) { VARIANTARG varg[3]; TCHAR *pszMsg; DISPID dispid = DISPID_MTScript_OnProcessEvent;
VERIFY_THREAD();
VariantInit(&varg[0]); VariantInit(&varg[1]); VariantInit(&varg[2]);
// Parameters are in order from last to first
V_VT(&varg[2]) = VT_I4; V_I4(&varg[2]) = pProc->ProcId();
switch (tm) { case MD_PROCESSEXITED: pszMsg = _T("exited");
V_VT(&varg[0]) = VT_I4; V_I4(&varg[0]) = pProc->GetExitCode(); break;
case MD_PROCESSCRASHED: pszMsg = _T("crashed");
// 3rd parameter is empty
break;
case MD_PROCESSTERMINATED: pszMsg = _T("terminated");
// 3rd parameter is empty
break;
case MD_PROCESSCONNECTED: pszMsg = _T("connected");
// 3rd parameter is empty
break;
default: AssertSz(FALSE, "NONFATAL: Invalid THREADMSG value"); return; break; }
V_VT(&varg[1]) = VT_BSTR; V_BSTR(&varg[1]) = SysAllocString(pszMsg); // NULL is a valid value for BSTR
FireEvent(dispid, 3, varg);
VariantClear(&varg[0]); VariantClear(&varg[1]); VariantClear(&varg[2]);
return; }
long CScriptHost::FireScriptErrorEvent( TCHAR *bstrFile, long nLine, long nChar, TCHAR *bstrText, long sCode, TCHAR *bstrSource, TCHAR *bstrDescription) { long cSucceeded = 0;
VERIFY_THREAD();
// Parameters are in order from last to first
AutoVariant varg[7]; cSucceeded += varg[6].Set(bstrFile); cSucceeded += varg[5].Set(nLine); cSucceeded += varg[4].Set(nChar); cSucceeded += varg[3].Set(bstrText); cSucceeded += varg[2].Set(sCode); cSucceeded += varg[1].Set(bstrSource); cSucceeded += varg[0].Set(bstrDescription);
if (cSucceeded != ARRAY_SIZE(varg)) return 0; // Default return value
AutoVariant varResult; FireEvent(DISPID_MTScript_OnScriptError, ARRAY_SIZE(varg), varg, &varResult); AutoVariant varResultInt; if (VariantChangeType(&varResultInt, &varResult, 0, VT_I4) == S_OK) return V_I4(&varResultInt);
return 0; } //---------------------------------------------------------------------------
//
// Member: CScriptHost::FireMachineEvent
//
// Notes: Fires the OnRemoteExec event when a machine connected to us
// remotely calls the Exec() method.
//
//---------------------------------------------------------------------------
void CScriptHost::FireMachineEvent(MACHPROC_EVENT_DATA *pmed, BOOL fExec) {
VERIFY_THREAD();
DISPID dispid = (fExec) ? DISPID_MTScript_OnRemoteExec : DISPID_MTScript_OnProcessEvent; DISPPARAMS dp; EXCEPINFO ei; UINT uArgErr = 0; VARIANTARG vararg[3]; VARIANTARG varResult; HRESULT hr = S_OK;
pmed->hrReturn = S_OK;
if (GetSite() && GetSite()->_pDispSink) { VariantInit(&vararg[0]); VariantInit(&vararg[1]); VariantInit(&vararg[2]); VariantInit(&varResult);
// Params are in order from last to first in the array
V_VT(&vararg[0]) = VT_BSTR; V_BSTR(&vararg[0]) = pmed->bstrParams;
V_VT(&vararg[1]) = VT_BSTR; V_BSTR(&vararg[1]) = pmed->bstrCmd;
if (!fExec) { V_VT(&vararg[2]) = VT_I4; V_I4(&vararg[2]) = pmed->dwProcId; }
dp.rgvarg = vararg; dp.rgdispidNamedArgs = NULL; dp.cArgs = (fExec) ? 2 : 3; dp.cNamedArgs = 0;
hr = GetSite()->_pDispSink->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, &dp, &varResult, &ei, &uArgErr); pmed->hrReturn = hr;
if (hr) { // If an error occurred, do nothing except return the error code.
} // Check for data types which we don't support.
else if ( V_ISBYREF(&varResult) || V_ISARRAY(&varResult) || V_ISVECTOR(&varResult) || V_VT(&varResult) == VT_UNKNOWN) { // Do nothing. Return an empty result
AssertSz(FALSE, "NONFATAL: Unsupported data type returned from OnRemoteExec event"); } else if (V_VT(&varResult) == VT_DISPATCH) { if (fExec) { // Note that the return value is an IDispatch, but don't set the
// pointer because it will need to be retrieved out of the GIT
V_VT(pmed->pvReturn) = VT_DISPATCH; V_DISPATCH(pmed->pvReturn) = NULL;
hr =_pMT->_pGIT->RegisterInterfaceInGlobal(V_DISPATCH(&varResult), IID_IDispatch, &pmed->dwGITCookie); if (hr) { pmed->hrReturn = hr; } }
// Leave the result empty if they returned an IDispatch from an
// OnProcessEvent call.
} else { VariantCopy(pmed->pvReturn, &varResult); }
VariantClear(&varResult); }
// Tell the calling thread we're done with the call and it can continue.
SetEvent(pmed->hEvent); }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::FireEvent
//
//---------------------------------------------------------------------------
void CScriptHost::FireEvent(DISPID dispid, UINT cArg, VARIANTARG *pvararg, VARIANTARG *pvarResult) { VERIFY_THREAD();
DISPPARAMS dp; EXCEPINFO ei; UINT uArgErr = 0;
if (GetSite() && GetSite()->_pDispSink) { dp.rgvarg = pvararg; dp.rgdispidNamedArgs = NULL; dp.cArgs = cArg; dp.cNamedArgs = 0;
GetSite()->_pDispSink->Invoke( dispid, IID_NULL, 0, DISPATCH_METHOD, &dp, pvarResult, &ei, &uArgErr); } }
void CScriptHost::FireEvent(DISPID dispid, UINT carg, VARIANTARG *pvararg) { FireEvent(dispid, carg, pvararg, NULL); }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::FireEvent
//
//---------------------------------------------------------------------------
void CScriptHost::FireEvent(DISPID dispid, LPCTSTR pch) { VERIFY_THREAD();
VARIANT var;
V_BSTR(&var) = SysAllocString(pch); V_VT(&var) = VT_BSTR; FireEvent(dispid, 1, &var); SysFreeString(V_BSTR(&var)); }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::FireEvent
//
//---------------------------------------------------------------------------
void CScriptHost::FireEvent(DISPID dispid, BOOL fArg) { VERIFY_THREAD();
VARIANT var;
V_BOOL(&var) = fArg ? VARIANT_TRUE : VARIANT_FALSE; V_VT(&var) = VT_BOOL; FireEvent(dispid, 1, &var); }
//---------------------------------------------------------------------------
//
// Member: CScriptHost::FireEvent
//
//---------------------------------------------------------------------------
void CScriptHost::FireEvent(DISPID dispid, IDispatch *pDisp) { VERIFY_THREAD();
VARIANT var;
V_DISPATCH(&var) = pDisp; V_VT(&var) = VT_DISPATCH; FireEvent(dispid, 1, &var); }
HRESULT CScriptHost::LoadTypeLibrary() { VERIFY_THREAD();
HRESULT hr = S_OK;
if (!_pTypeLibEXE) { // BUGBUG -- Is this valid, or does this need to be marshalled?
_pTypeLibEXE = _pMT->_pTypeLibEXE; }
if (!_pTypeInfoCMTScript) { hr = THR(_pTypeLibEXE->GetTypeInfoOfGuid(CLSID_LocalMTScript, &_pTypeInfoCMTScript)); if (hr) goto Cleanup; }
if (!_pTypeInfoIGlobalMTScript) { hr = THR(_pTypeLibEXE->GetTypeInfoOfGuid(IID_IGlobalMTScript, &_pTypeInfoIGlobalMTScript)); if (hr) goto Cleanup; }
Cleanup: return hr; }
void CScriptHost::GetScriptPath(CStr *pcstrPath) { _pMT->_options.GetScriptPath(pcstrPath); }
|