// Copyright (c) 1999 Microsoft Corporation. All rights reserved. // // Declaration of CSingleThreadedActiveScriptManager. // #include "stdinc.h" #include "scriptthread.h" #include "activescript.h" #include "workthread.h" #define S_STD_PARAMS ScriptManager *pmgr; HRESULT *phr; CWorkerThread CSingleThreadedScriptManager::ms_Thread(true, true); ////////////////////////////////////////////////////////////////////// // Construction struct S_Create { CSingleThreadedScriptManager *_this; bool fUseOleAut; const WCHAR *pwszLanguage; const WCHAR *pwszSource; CDirectMusicScript *pParentScript; HRESULT *phr; DMUS_SCRIPT_ERRORINFO *pErrorInfo; }; void F_Create(void *pvParams) { S_Create *pS = reinterpret_cast(pvParams); pS->_this->m_pScriptManager = new CActiveScriptManager(pS->fUseOleAut, pS->pwszLanguage, pS->pwszSource, pS->pParentScript, pS->phr, pS->pErrorInfo); } CSingleThreadedScriptManager::CSingleThreadedScriptManager( bool fUseOleAut, const WCHAR *pwszLanguage, const WCHAR *pwszSource, CDirectMusicScript *pParentScript, HRESULT *phr, DMUS_SCRIPT_ERRORINFO *pErrorInfo) : m_pScriptManager(NULL) { S_Create S = { this, fUseOleAut, pwszLanguage, pwszSource, pParentScript, phr, pErrorInfo }; HRESULT hr = ms_Thread.Create(); if (SUCCEEDED(hr)) { hr = ms_Thread.Call(F_Create, &S, sizeof(S), true); } if (FAILED(hr)) // Only overwrite phr if the call itself failed. Otherwise the call itself sets phr via struct S. *phr = hr; } ////////////////////////////////////////////////////////////////////// // Start struct S_Start { S_STD_PARAMS DMUS_SCRIPT_ERRORINFO *pErrorInfo; }; void F_Start(void *pvParams) { S_Start *pS = reinterpret_cast(pvParams); *pS->phr = pS->pmgr->Start(pS->pErrorInfo); } HRESULT CSingleThreadedScriptManager ::Start(DMUS_SCRIPT_ERRORINFO *pErrorInfo) { HRESULT hr = E_FAIL; S_Start S = { m_pScriptManager, &hr, pErrorInfo }; HRESULT hrThreadCall = ms_Thread.Call(F_Start, &S, sizeof(S), true); if (FAILED(hrThreadCall)) return hrThreadCall; return hr; } ////////////////////////////////////////////////////////////////////// // CallRoutine struct S_CallRoutine { S_STD_PARAMS const WCHAR *pwszRoutineName; DMUS_SCRIPT_ERRORINFO *pErrorInfo; }; void F_CallRoutine(void *pvParams) { S_CallRoutine *pS = reinterpret_cast(pvParams); *pS->phr = pS->pmgr->CallRoutine(pS->pwszRoutineName, pS->pErrorInfo); } HRESULT CSingleThreadedScriptManager::CallRoutine(const WCHAR *pwszRoutineName, DMUS_SCRIPT_ERRORINFO *pErrorInfo) { HRESULT hr = E_FAIL; S_CallRoutine S = { m_pScriptManager, &hr, pwszRoutineName, pErrorInfo }; HRESULT hrThreadCall = ms_Thread.Call(F_CallRoutine, &S, sizeof(S), true); if (FAILED(hrThreadCall)) return hrThreadCall; return hr; } ////////////////////////////////////////////////////////////////////// // ScriptTrackCallRoutine struct S_ScriptTrackCallRoutine { S_STD_PARAMS IDirectMusicSegmentState *pSegSt; DWORD dwVirtualTrackID; bool fErrorPMsgsEnabled; __int64 i64IntendedStartTime; DWORD dwIntendedStartTimeFlags; WCHAR wszRoutineName[1]; // dynamically allocate extra space to hold the actual string within this structure }; void F_ScriptTrackCallRoutine(void *pvParams) { S_ScriptTrackCallRoutine *pS = reinterpret_cast(pvParams); pS->pmgr->ScriptTrackCallRoutine( pS->wszRoutineName, pS->pSegSt, pS->dwVirtualTrackID, pS->fErrorPMsgsEnabled, pS->i64IntendedStartTime, pS->dwIntendedStartTimeFlags); pS->pSegSt->Release(); // release the interface held in CSingleThreadedScriptManager::ScriptTrackCallRoutine } HRESULT CSingleThreadedScriptManager::ScriptTrackCallRoutine( const WCHAR *pwszRoutineName, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualTrackID, bool fErrorPMsgsEnabled, __int64 i64IntendedStartTime, DWORD dwIntendedStartTimeFlags) { // We need to allocate the structure with extra space to hold the routine name. This is because // the call is asynchonous so a copy of the text will be needed because copying the pwszRoutineName // would fail because we can't be sure the string it points to will remain be allocated. int cbS = sizeof(S_ScriptTrackCallRoutine) + (sizeof(WCHAR) * wcslen(pwszRoutineName)); S_ScriptTrackCallRoutine *pS = reinterpret_cast(new char[cbS]); if (!pS) return E_OUTOFMEMORY; pS->pmgr = m_pScriptManager; pS->phr = NULL; pS->pSegSt = pSegSt; pS->pSegSt->AddRef(); // hold a ref because the call is asynchronous and the interface we were passed may be released pS->dwVirtualTrackID = dwVirtualTrackID; pS->fErrorPMsgsEnabled = fErrorPMsgsEnabled; pS->i64IntendedStartTime = i64IntendedStartTime; pS->dwIntendedStartTimeFlags = dwIntendedStartTimeFlags; wcscpy(pS->wszRoutineName, pwszRoutineName); // Call asynchronously. Needed to avoid deadlocks between the VBScript thread and // performance or to avoid blocking the performance if the VBScript routine goes into // a long loop. VVVVV HRESULT hrThreadCall = ms_Thread.Call(F_ScriptTrackCallRoutine, pS, cbS, false); delete [] reinterpret_cast(pS); return hrThreadCall; } ////////////////////////////////////////////////////////////////////// // SetVariable struct S_SetVariable { S_STD_PARAMS const WCHAR *pwszVariableName; VARIANT *pvarValue; // pass struct by reference bool fSetRef; DMUS_SCRIPT_ERRORINFO *pErrorInfo; }; void F_SetVariable(void *pvParams) { S_SetVariable *pS = reinterpret_cast(pvParams); *pS->phr = pS->pmgr->SetVariable(pS->pwszVariableName, *pS->pvarValue, pS->fSetRef, pS->pErrorInfo); } HRESULT CSingleThreadedScriptManager::SetVariable(const WCHAR *pwszVariableName, VARIANT varValue, bool fSetRef, DMUS_SCRIPT_ERRORINFO *pErrorInfo) { HRESULT hr = E_FAIL; S_SetVariable S = { m_pScriptManager, &hr, pwszVariableName, &varValue, fSetRef, pErrorInfo }; HRESULT hrThreadCall = ms_Thread.Call(F_SetVariable, &S, sizeof(S), true); if (FAILED(hrThreadCall)) return hrThreadCall; return hr; } ////////////////////////////////////////////////////////////////////// // GetVariable struct S_GetVariable { S_STD_PARAMS const WCHAR *pwszVariableName; VARIANT *pvarValue; DMUS_SCRIPT_ERRORINFO *pErrorInfo; }; void F_GetVariable(void *pvParams) { S_GetVariable *pS = reinterpret_cast(pvParams); *pS->phr = pS->pmgr->GetVariable(pS->pwszVariableName, pS->pvarValue, pS->pErrorInfo); } HRESULT CSingleThreadedScriptManager::GetVariable(const WCHAR *pwszVariableName, VARIANT *pvarValue, DMUS_SCRIPT_ERRORINFO *pErrorInfo) { HRESULT hr = E_FAIL; S_GetVariable S = { m_pScriptManager, &hr, pwszVariableName, pvarValue, pErrorInfo }; HRESULT hrThreadCall = ms_Thread.Call(F_GetVariable, &S, sizeof(S), true); if (FAILED(hrThreadCall)) return hrThreadCall; return hr; } ////////////////////////////////////////////////////////////////////// // EnumRoutine struct S_EnumItem { S_STD_PARAMS bool fRoutine; DWORD dwIndex; WCHAR *pwszName; int *pcItems; }; void F_EnumItem(void *pvParams) { S_EnumItem *pS = reinterpret_cast(pvParams); *pS->phr = pS->pmgr->EnumItem(pS->fRoutine, pS->dwIndex, pS->pwszName, pS->pcItems); } HRESULT CSingleThreadedScriptManager::EnumItem(bool fRoutine, DWORD dwIndex, WCHAR *pwszName, int *pcItems) { HRESULT hr = E_FAIL; S_EnumItem S = { m_pScriptManager, &hr, fRoutine, dwIndex, pwszName, pcItems }; HRESULT hrThreadCall = ms_Thread.Call(F_EnumItem, &S, sizeof(S), true); if (FAILED(hrThreadCall)) return hrThreadCall; return hr; } ////////////////////////////////////////////////////////////////////// // DispGetIDsOfNames struct S_DispGetIDsOfNames { S_STD_PARAMS const IID *piid; // use pointer instead of reference to leave struct as simple aggregate type LPOLESTR __RPC_FAR *rgszNames; UINT cNames; LCID lcid; DISPID *rgDispId; }; void F_DispGetIDsOfNames(void *pvParams) { S_DispGetIDsOfNames *pS = reinterpret_cast(pvParams); *pS->phr = pS->pmgr->DispGetIDsOfNames(*pS->piid, pS->rgszNames, pS->cNames, pS->lcid, pS->rgDispId); } HRESULT CSingleThreadedScriptManager::DispGetIDsOfNames(REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames, LCID lcid, DISPID __RPC_FAR *rgDispId) { HRESULT hr = E_FAIL; S_DispGetIDsOfNames S = { m_pScriptManager, &hr, &riid, rgszNames, cNames, lcid, rgDispId }; HRESULT hrThreadCall = ms_Thread.Call(F_DispGetIDsOfNames, &S, sizeof(S), true); if (FAILED(hrThreadCall)) return hrThreadCall; return hr; } ////////////////////////////////////////////////////////////////////// // DispInvoke struct S_DispInvoke { S_STD_PARAMS DISPID dispIdMember; const IID *piid; // use pointer instead of reference to leave struct as simple aggregate type LCID lcid; WORD wFlags; DISPPARAMS __RPC_FAR *pDispParams; VARIANT __RPC_FAR *pVarResult; EXCEPINFO __RPC_FAR *pExcepInfo; UINT __RPC_FAR *puArgErr; }; void F_DispInvoke(void *pvParams) { S_DispInvoke *pS = reinterpret_cast(pvParams); *pS->phr = pS->pmgr->DispInvoke(pS->dispIdMember, *pS->piid, pS->lcid, pS->wFlags, pS->pDispParams, pS->pVarResult, pS->pExcepInfo, pS->puArgErr); } HRESULT CSingleThreadedScriptManager::DispInvoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS __RPC_FAR *pDispParams, VARIANT __RPC_FAR *pVarResult, EXCEPINFO __RPC_FAR *pExcepInfo, UINT __RPC_FAR *puArgErr) { HRESULT hr = E_FAIL; S_DispInvoke S = { m_pScriptManager, &hr, dispIdMember, &riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr }; HRESULT hrThreadCall = ms_Thread.Call(F_DispInvoke, &S, sizeof(S), true); if (FAILED(hrThreadCall)) return hrThreadCall; return hr; } ////////////////////////////////////////////////////////////////////// // Close struct S_Close { ScriptManager *pmgr; }; void F_Close(void *pvParams) { S_Close *pS = reinterpret_cast(pvParams); pS->pmgr->Close(); } void CSingleThreadedScriptManager::Close() { S_Close S = { m_pScriptManager }; ms_Thread.Call(F_Close, &S, sizeof(S), true); } ////////////////////////////////////////////////////////////////////// // Release struct S_Release { ScriptManager *pmgr; DWORD *pdw; }; void F_Release(void *pvParams) { S_Release *pS = reinterpret_cast(pvParams); *pS->pdw = pS->pmgr->Release(); } STDMETHODIMP_(ULONG) CSingleThreadedScriptManager::Release() { DWORD dw = 1; S_Release S = { m_pScriptManager, &dw }; if (m_pScriptManager) // if creation failed, release will be called when m_pScriptManager hasn't been set { ms_Thread.Call(F_Release, &S, sizeof(S), true); } if (!dw) delete this; return dw; } /* Template I used to stamp these things out... ////////////////////////////////////////////////////////////////////// // XXX struct S_XXX { S_STD_PARAMS YYY }; void F_XXX(void *pvParams) { S_XXX *pS = reinterpret_cast(pvParams); *pS->phr = pS->pmgr->XXX(YYY); } HRESULT CSingleThreadedScriptManager::XXX(YYY) { HRESULT hr = E_FAIL; S_XXX S = { m_pScriptManager, &hr, YYY }; HRESULT hrThreadCall = ms_Thread.Call(F_XXX, &S, sizeof(S), true); if (FAILED(hrThreadCall)) return hrThreadCall; return hr; } */