Fabulous Adventures In Coding
Eric Lippert is a principal developer on the C# compiler team. Learn more about Eric.
#include "headers.h"
ScriptEngine::ScriptEngine(){ DLLAddRef();
this->m_cref = 1; this->m_thread = threadNone; this->m_state = SCRIPTSTATE_UNINITIALIZED; this->m_psite = NULL; this->m_pNamedItemList = NULL;}
ScriptEngine::~ScriptEngine(){ Assert(this->m_cref == 0);
if (this->m_state != SCRIPTSTATE_CLOSED && this->m_state != SCRIPTSTATE_UNINITIALIZED) { Bug("It's a very bad idea to deallocate an initialized engine."); }
this->Close(); if (NULL != this->m_pNamedItemList) delete this->m_pNamedItemList;
DLLRelease();}
HRESULT ScriptEngine::Create(ScriptEngine * * ppEngine){ AssertOutPtr(ppEngine);
HRESULT hr;
*ppEngine = NULL; ScriptEngine * pEngine = NULL;
pEngine = new ScriptEngine(); if (NULL == pEngine) { hr = E_OUTOFMEMORY; goto LError; }
hr = NamedItemList::Create(23, &pEngine->m_pNamedItemList); if (FAILED(hr)) goto LError;
*ppEngine = pEngine; pEngine = NULL;
hr = S_OK;
LError:
if (NULL != pEngine) pEngine->Release(); return hr;}
void ScriptEngine::ChangeScriptState(SCRIPTSTATE state){ if (this->m_state != state) { this->m_state = state; if (this->m_psite != NULL) this->m_psite->OnStateChange(state); }}
BOOL ScriptEngine::IsInitialized(void){ switch(this->m_state) { case SCRIPTSTATE_CLOSED: case SCRIPTSTATE_UNINITIALIZED: Assert(NULL == this->m_psite); Assert(threadNone == this->m_thread); return FALSE; case SCRIPTSTATE_INITIALIZED: case SCRIPTSTATE_STARTED: case SCRIPTSTATE_CONNECTED: case SCRIPTSTATE_DISCONNECTED: Assert(threadNone != this->m_thread); Assert(NULL != this->m_psite); return TRUE; default: Bug("The script state is a bad value."); return FALSE; }}
HRESULT ScriptEngine::VerifyThread(void){ if (this->IsInitialized() && this->m_thread != GetCurrentThreadId()) {
Bug("The host is in violation of the script engine threading contract. " "Hosts are required to treat the engine as apartment threaded when " "the engine is initialized (with some exceptions) and as rental " "threaded when it is not initialized.");
return E_UNEXPECTED; } return S_OK;}
HRESULT ScriptEngine::Uninitialize(void){ HRESULT hr; if (this->m_state == SCRIPTSTATE_CLOSED) { Bug("It is illegal to move a script engine from CLOSED to UNINITIALIZED"); // Pointless, too. return E_UNEXPECTED; }
if (this->m_state == SCRIPTSTATE_UNINITIALIZED) return S_OK;
hr = this->Initialize(); if (FAILED(hr)) goto LError;
this->m_pNamedItemList->Reset();
this->m_psite->Release(); this->m_psite = NULL; this->m_thread = threadNone;
return hr;}
HRESULT ScriptEngine::Initialize(void){ HRESULT hr; if (!this->IsInitialized()) { Bug("To initialize an uninitialized engine, call SetScriptSite."); return E_UNEXPECTED; }
if (this->m_state == SCRIPTSTATE_INITIALIZED) return S_OK;
if (this->m_state == SCRIPTSTATE_CONNECTED || this->m_state == SCRIPTSTATE_DISCONNECTED) { hr = this->FullyDisconnectEventSinks(); if (FAILED(hr)) goto LError; }
hr = this->StopEngine(); if (FAILED(hr)) goto LError;
HRESULT ScriptEngine::Start(void){ HRESULT hr;
if (!this->IsInitialized()) { Bug("You cannot start an uninitialized engine."); return E_UNEXPECTED; }
if (this->m_state == SCRIPTSTATE_STARTED) return S_OK;
hr = this->Execute();
if (SCRIPT_E_REPORTED == hr) hr = S_OK; if (FAILED(hr)) goto LError;
HRESULT ScriptEngine::Execute(void){ // UNDONE return S_OK;}
HRESULT ScriptEngine::StopEngine(void){ // UNDONE return S_OK;}
HRESULT ScriptEngine::Connect(void){ HRESULT hr;
if (!this->IsInitialized()) { Bug("You cannot connect an uninitialized engine."); return E_UNEXPECTED; }
if (this->m_state == SCRIPTSTATE_CONNECTED) return S_OK;
if (this->m_state == SCRIPTSTATE_DISCONNECTED) { hr = this->ReconnectEventSinks(); if (FAILED(hr)) goto LError; } else { hr = this->Start(); if (FAILED(hr)) goto LError;
hr = this->ConnectEventSinks(); if (FAILED(hr)) goto LError; }
HRESULT ScriptEngine::TemporarilyDisconnectEventSinks(void){ if (this->m_state == SCRIPTSTATE_DISCONNECTED) return S_OK;
if (this->m_state != SCRIPTSTATE_CONNECTED) { Bug("You cannot disconnect an engine that is not connected!"); return E_UNEXPECTED; } // UNDONE return S_OK;}
HRESULT ScriptEngine::FullyDisconnectEventSinks(void){ Assert(this->m_state == SCRIPTSTATE_CONNECTED || this->m_state == SCRIPTSTATE_DISCONNECTED);
// UNDONE return S_OK;}
HRESULT ScriptEngine::ConnectEventSinks(void){ // UNDONE return S_OK;}
HRESULT ScriptEngine::ReconnectEventSinks(void){ // UNDONE return S_OK;}
// IUnknown
STDMETHODIMP ScriptEngine::QueryInterface(REFIID riid, void * * ppv){ // This method can be called on any thread at any time. if (NULL == ppv) { Bug("Null out pointer"); return E_POINTER; } AssertOutPtr(ppv);
*ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown)) *ppv = (IUnknown *)(IActiveScript *) this; else if (IsEqualIID(riid, IID_IActiveScript)) *ppv = (IActiveScript *) this; else if (IsEqualIID(riid, IID_IActiveScriptParse)) *ppv = (IActiveScriptParse *) this; else if (IsEqualIID(riid, IID_IActiveScriptParseProcedure2)) *ppv = (IActiveScriptParseProcedure2 *) this; else if (IsEqualIID(riid, IID_IObjectSafety)) *ppv = (IObjectSafety *) this; else return E_NOINTERFACE;
this->AddRef(); return S_OK;}
STDMETHODIMP_(ULONG) ScriptEngine::AddRef(void){ // This method can be called on any thread at any time. return InterlockedIncrement(&this->m_cref);}
STDMETHODIMP_(ULONG) ScriptEngine::Release(void){ // This method can be called on any thread at any time, // but if this is the final release, the engine should be // uninitialized. long cref = InterlockedDecrement(&this->m_cref); if (0 == cref) delete this; return cref;}
// IActiveScript
STDMETHODIMP ScriptEngine::SetScriptSite(IActiveScriptSite * psite){ if (NULL == psite) { Bug("Null site pointer"); return E_POINTER; }
AssertReadPtr(psite); if (this->IsInitialized()) { Bug("It is a violation of the script engine contract to set " "the site of an engine which is already initialized"); return E_UNEXPECTED; } psite->AddRef(); this->m_psite = psite; this->m_thread = GetCurrentThreadId();
this->ChangeScriptState(SCRIPTSTATE_INITIALIZED);
return S_OK;} STDMETHODIMP ScriptEngine::GetScriptSite(REFIID riid, void * * ppv){ HRESULT hr;
if (NULL == ppv) { Bug("Null out pointer"); return E_POINTER; }
AssertOutPtr(ppv);
*ppv = NULL; hr = this->VerifyThread(); if (FAILED(hr)) return hr;
if (this->m_psite == NULL) return S_FALSE;
return this->m_psite->QueryInterface(riid, ppv);}
STDMETHODIMP ScriptEngine::SetScriptState(SCRIPTSTATE state){ HRESULT hr; hr = this->VerifyThread(); if (FAILED(hr)) goto LError; switch(state) { default: Bug("The script state is a bad value."); hr = E_INVALIDARG; break; case SCRIPTSTATE_CLOSED: hr = this->Close(); break; case SCRIPTSTATE_UNINITIALIZED: hr = this->Uninitialize(); break; case SCRIPTSTATE_INITIALIZED: hr = this->Initialize(); break; case SCRIPTSTATE_STARTED: hr = this->Start(); break; case SCRIPTSTATE_CONNECTED: hr = this->Connect(); break; case SCRIPTSTATE_DISCONNECTED: hr = this->TemporarilyDisconnectEventSinks(); break; }
if (FAILED(hr)) goto LError;
this->ChangeScriptState(state);
STDMETHODIMP ScriptEngine::Close(void){ HRESULT hr;
if (this->m_state == SCRIPTSTATE_CLOSED) return S_OK;
hr = this->VerifyThread(); if (FAILED(hr)) goto LError;
hr = this->Uninitialize(); if (FAILED(hr)) goto LError;
this->m_pNamedItemList->Clear();
this->ChangeScriptState(SCRIPTSTATE_CLOSED);
STDMETHODIMP ScriptEngine::AddNamedItem(const WCHAR * pszName, DWORD flags){
// There are six possible flags. Suppose the named item is "foo"://// SCRIPTITEM_ISVISIBLE : foo is added to the namespace, so you can call// "foo.bar(123)" from the script// SCRIPTITEM_ISSOURCE : foo is an object which sources events// SCRIPTITEM_GLOBALMEMBERS : calling "bar(123)" calls "foo.bar(123)". Think// "window.alert()". These guys go into the global module.// SCRIPTITEM_ISPERSISTENT : foo survives when we go back to Uninitialized state.// SCRIPTITEM_CODEONLY : foo is just the name of a module, not an object// SCRIPTITEM_NOCODE : foo is just the name of a named item, not a code module
if (NULL == pszName) return E_POINTER;
AssertReadString(pszName); if (!this->IsInitialized()) { Bug("It is a violation of the script engine contract to add " "a named item to an uninitialized engine."); return E_UNEXPECTED; }
if ((flags & ~SCRIPTITEM_ALL_FLAGS) != 0) { Bug("Bad flag passed to AddNamedItem"); return E_INVALIDARG; }
hr = this->VerifyThread(); if (FAILED(hr)) return hr;
hr = this->m_pNamedItemList->Add(pszName, flags); if (FAILED(hr)) return hr;
return S_OK;}
STDMETHODIMP ScriptEngine::AddTypeLib(REFGUID rguid, DWORD major, DWORD minor, DWORD flags){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::GetScriptDispatch(const WCHAR * pszName, IDispatch * * ppdisp){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::GetScriptState(SCRIPTSTATE * pstate){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::GetCurrentScriptThreadID(SCRIPTTHREADID * pthread){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::GetScriptThreadID(DWORD thread, SCRIPTTHREADID * pthread){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::GetScriptThreadState(SCRIPTTHREADID thread, SCRIPTTHREADSTATE * pstate){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::InterruptScriptThread(SCRIPTTHREADID thread, const EXCEPINFO * pexcepinfo, DWORD flags){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::Clone(IActiveScript * * ppScriptEngine){ return E_NOTIMPL;}
// IActiveScriptParse
STDMETHODIMP ScriptEngine::InitNew(void){ return S_OK;}
STDMETHODIMP ScriptEngine::AddScriptlet(const WCHAR * pszDefaultName, const WCHAR * pszCode, const WCHAR * pszItemName, const WCHAR * pszSubItemName, const WCHAR * pszEventName, const WCHAR * pszDelimiter, DWORD sourceContext, ULONG startingLineNumber, DWORD flags, BSTR * pbstrName, EXCEPINFO * pexcepinfo){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::ParseScriptText(const WCHAR * pszCode, const WCHAR * pszItemName, IUnknown *punkContext, const WCHAR * pszDelimiter, DWORD sourceContext, ULONG startingLineNumber, DWORD flags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo){ return E_NOTIMPL;}
// IActiveScriptParseProcedure2
STDMETHODIMP ScriptEngine::ParseProcedureText(const WCHAR * pstrCode, const WCHAR * pstrFormalParams, const WCHAR * pstrProcedureName, const WCHAR * pstrItemName, IUnknown * punkContext, const WCHAR * pstrDelimiter, DWORD sourceContext, ULONG startingLineNumber, DWORD flags, IDispatch * * ppdisp){ return E_NOTIMPL;}
// IObjectSafety
STDMETHODIMP ScriptEngine::GetInterfaceSafetyOptions(REFIID riid, DWORD * pSupported, DWORD * pEnabled){ return E_NOTIMPL;}
STDMETHODIMP ScriptEngine::SetInterfaceSafetyOptions(REFIID riid, DWORD mask, DWORD options){ return E_NOTIMPL;}
I am using the Script Host to impliment the business logic
now i am using vb script for this purpuse
1. How we can use LINQ comands in parsing in Script Host so i can extends
my appliction