windows-nt/Source/XPSP1/NT/multimedia/directx/dmusic/dmscript/scriptthread.cpp
2020-09-26 16:20:57 +08:00

401 lines
11 KiB
C++

// 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<S_Create*>(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<S_Start*>(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<S_CallRoutine*>(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<S_ScriptTrackCallRoutine*>(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<S_ScriptTrackCallRoutine *>(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<char *>(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<S_SetVariable*>(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<S_GetVariable*>(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<S_EnumItem*>(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<S_DispGetIDsOfNames*>(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<S_DispInvoke*>(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<S_Close*>(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<S_Release*>(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<S_XXX*>(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;
}
*/