#include "pch.h"
#include <AGC.h>
#include "AGCEventDef.h"
#include "resource.h"
#include <..\TCLib\ObjectLock.h>
class TCSimpleLock
{
public:
TCSimpleLock(LONG& nSync) :
m_nSync(nSync) {}
public:
void Lock()
{
while (InterlockedExchange(&m_nSync, 1))
Sleep(10);
}
void Unlock()
{
InterlockedExchange(&m_nSync, 0);
}
protected:
LONG& m_nSync;
};
#include <AGCEventsRCH.h>
#include <AGCEventsCPP.h>
LONG CAGCEventDef::s_nInitSync = 0;
bool CAGCEventDef::s_bInitialized = false;
CAGCEventDef::XNameMap* CAGCEventDef::s_pNameMap = NULL;
CAGCEventDef CAGCEventDef::s_Instance;
CAGCEventDef::CAGCEventDef()
{
#ifdef _DEBUG
{
const XEventDef* a = begin();
const XEventDef* b = a + 1;
while (end() != b)
assert(XLess()(*a++, *b++));
int nIndent = 0;
for (const XEventDef* it = begin(); end() != it; ++it)
{
assert(-1 <= it->m_nIndent && it->m_nIndent <= 1);
nIndent += it->m_nIndent;
assert(0 <= nIndent);
}
assert(0 == nIndent);
}
#endif }
void CAGCEventDef::Initialize()
{
TCSimpleLock spinLock(s_nInitSync);
TCObjectLock<TCSimpleLock> lock(&spinLock);
if (s_bInitialized)
return;
s_pNameMap = new XNameMap;
for (const XEventDef* it = begin(); end() != it; ++it)
{
if (HIWORD(reinterpret_cast<DWORD>(it->m_pszName)))
(*s_pNameMap)[it->m_pszName] = it->m_id;
else
{
BSTR bstrName;
ZSucceeded(GetString(it->m_pszName, &bstrName));
(*s_pNameMap)[bstrName] = it->m_id;
}
}
s_bInitialized = true;
}
void CAGCEventDef::Terminate()
{
TCSimpleLock spinLock(s_nInitSync);
TCObjectLock<TCSimpleLock> lock(&spinLock);
if (!s_bInitialized)
return;
for (XNameMapIt it = s_pNameMap->begin(); it != s_pNameMap->end(); ++it)
{
const XEventDef* itFind = find(it->second);
assert(itFind != end());
if (!HIWORD(reinterpret_cast<DWORD>(itFind->m_pszName)))
SysFreeString(const_cast<BSTR>(it->first));
}
delete s_pNameMap;
s_pNameMap = NULL;
s_bInitialized = false;
}
HRESULT CAGCEventDef::GetEventName(AGCEventID idEvent, BSTR* pbstrOut)
{
*pbstrOut = NULL;
const XEventDef* it = find(idEvent);
if (end() == it)
return E_INVALIDARG;
HRESULT hr = GetString(it->m_pszName, pbstrOut);
return S_OK;
}
HRESULT CAGCEventDef::GetEventDescription(AGCEventID idEvent, BSTR* pbstrOut)
{
*pbstrOut = NULL;
const XEventDef* it = find(idEvent);
if (end() == it)
return E_INVALIDARG;
HRESULT hr = GetString(it->m_pszEventDescription, pbstrOut);
return (S_FALSE != hr) ? hr : GetEventName(it->m_id, pbstrOut);
}
HRESULT CAGCEventDef::GetEventDescription(IAGCEvent* pEvent, BSTR* pbstrOut,
const XEventDef* pDefHint)
{
*pbstrOut = NULL;
assert(pEvent);
if (!pDefHint)
{
AGCEventID idEvent;
RETURN_FAILED(pEvent->get_ID(&idEvent));
const XEventDef* it = find(idEvent);
if (end() == it)
return E_INVALIDARG;
pDefHint = it;
}
else
{
#ifdef _DEBUG
AGCEventID idEvent;
RETURN_FAILED(pEvent->get_ID(&idEvent));
assert(pDefHint->m_id == idEvent);
#endif }
CComBSTR bstrFmt;
HRESULT hr = GetString(pDefHint->m_pszFormatDescription, &bstrFmt);
RETURN_FAILED(hr);
if (S_FALSE == hr)
{
return GetEventDescription(pDefHint->m_id, pbstrOut);
}
assert(pEvent);
return ExpandFmtString(bstrFmt, pEvent, pbstrOut);
}
HRESULT CAGCEventDef::GetEventParameters (IAGCEvent* pEvent,
CAGCEventDef::XParamStrings& rParamStrings, const XEventDef* pDefHint)
{
assert(pEvent);
if (!pDefHint)
{
AGCEventID idEvent;
RETURN_FAILED(pEvent->get_ID(&idEvent));
const XEventDef* it = find(idEvent);
if (end() == it)
return E_INVALIDARG;
pDefHint = it;
}
else
{
#ifdef _DEBUG
AGCEventID idEvent;
RETURN_FAILED(pEvent->get_ID(&idEvent));
assert(pDefHint->m_id == idEvent);
#endif }
CComBSTR bstrFmt;
HRESULT hr = GetString(pDefHint->m_pszFormatDescription, &bstrFmt);
if (S_OK != hr)
return hr;
return ExpandParams(bstrFmt, pEvent, rParamStrings);
}
HRESULT CAGCEventDef::GetString(LPCOLESTR psz, BSTR* pbstrOut)
{
DWORD dw = reinterpret_cast<DWORD>(psz);
if (HIWORD(dw))
{
USES_CONVERSION;
*pbstrOut = SysAllocString(psz);
return *pbstrOut ? (SysStringLen(*pbstrOut) ? S_OK : S_FALSE)
: E_OUTOFMEMORY;
}
return TCLoadBSTR(_Module.GetResourceInstance(), dw, pbstrOut);
}
HRESULT CAGCEventDef::ExpandFmtString(BSTR bstrFmt, IAGCEvent* pEvent,
BSTR* pbstrOut)
{
assert(BSTRLen(bstrFmt));
assert(pbstrOut);
IStreamPtr spStm;
RETURN_FAILED(CreateStreamOnHGlobal(NULL, true, &spStm));
XParseData data =
{pEvent, spStm, NULL, NULL, NULL, bstrFmt, NULL, false};
XStateProc pfnState = ParseState_Base;
for (UINT cch = SysStringLen(bstrFmt); cch && pfnState; --cch)
{
RETURN_FAILED(pfnState(data));
pfnState = data.m_pfnNextState;
++data.m_pszInput;
}
data.m_bEndOfString = true;
while (pfnState)
{
RETURN_FAILED(pfnState(data));
pfnState = data.m_pfnNextState;
}
LARGE_INTEGER li = {0};
ULARGE_INTEGER uli;
RETURN_FAILED(spStm->Seek(li, STREAM_SEEK_CUR, &uli));
UINT cchStream = uli.QuadPart / sizeof(OLECHAR);
HGLOBAL hGlobal = NULL;
RETURN_FAILED(GetHGlobalFromStream(spStm, &hGlobal));
assert(hGlobal);
LPCOLESTR pszOut = reinterpret_cast<LPCOLESTR>(GlobalLock(hGlobal));
assert(pszOut);
*pbstrOut = SysAllocStringLen(pszOut, cchStream);
GlobalUnlock(hGlobal);
return *pbstrOut ? S_OK : E_OUTOFMEMORY;
}
HRESULT CAGCEventDef::ExpandParams(BSTR bstrFmt, IAGCEvent* pEvent,
CAGCEventDef::XParamStrings& rParams)
{
assert(BSTRLen(bstrFmt));
XParseData data =
{pEvent, NULL, &rParams, NULL, NULL, bstrFmt, NULL, false};
XStateProc pfnState = ParseState_Base;
for (UINT cch = SysStringLen(bstrFmt); cch && pfnState; --cch)
{
RETURN_FAILED(pfnState(data));
pfnState = data.m_pfnNextState;
++data.m_pszInput;
}
data.m_bEndOfString = true;
while (pfnState)
{
RETURN_FAILED(pfnState(data));
pfnState = data.m_pfnNextState;
}
return S_OK;
}
HRESULT __fastcall
CAGCEventDef::ParseState_WriteInput(CAGCEventDef::XParseData& data)
{
HRESULT hr = S_OK;
if (data.m_pStm)
hr = data.m_pStm->Write(data.m_pszInput, sizeof(*data.m_pszInput), NULL);
data.m_pfnNextState = SUCCEEDED(hr) ? ParseState_Base : NULL;
return hr;
}
HRESULT __fastcall
CAGCEventDef::ParseState_WriteVar(CAGCEventDef::XParseData& data)
{
UINT cch = data.m_pszVarEnd - data.m_pszVarBegin;
UINT cb = cch * sizeof(*data.m_pszVarEnd);
HRESULT hr = S_OK;
if (data.m_pStm)
hr = data.m_pStm->Write(data.m_pszVarBegin, cb, NULL);
data.m_pfnNextState = SUCCEEDED(hr) ? ParseState_Base : NULL;
return hr;
}
HRESULT __fastcall
CAGCEventDef::ParseState_End(CAGCEventDef::XParseData& data)
{
assert(data.m_bEndOfString);
data.m_pfnNextState = NULL;
return S_OK;
}
HRESULT __fastcall
CAGCEventDef::ParseState_Base(CAGCEventDef::XParseData& data)
{
if (data.m_bEndOfString)
return ParseState_End(data);
if (OLESTR('%') != *data.m_pszInput)
return ParseState_WriteInput(data);
data.m_pszVarBegin = data.m_pszInput + 1;
data.m_pfnNextState = ParseState_InVar;
return S_OK;
}
HRESULT __fastcall
CAGCEventDef::ParseState_InVar(CAGCEventDef::XParseData& data)
{
if (data.m_bEndOfString)
{
--data.m_pszVarBegin;
data.m_pszVarEnd = data.m_pszInput;
RETURN_FAILED(ParseState_WriteVar(data));
return ParseState_End(data);
}
if (OLESTR('%') == *data.m_pszInput)
{
if (data.m_pszInput == data.m_pszVarBegin)
return ParseState_WriteInput(data);
data.m_pszVarEnd = data.m_pszInput;
return ParseState_ProcessVar(data);
}
return S_OK;
}
HRESULT __fastcall
CAGCEventDef::ParseState_ProcessVar(CAGCEventDef::XParseData& data)
{
UINT cch = data.m_pszVarEnd - data.m_pszVarBegin;
CComVariant varKey;
V_VT(&varKey) = VT_BSTR;
V_BSTR(&varKey) = ::SysAllocStringLen(data.m_pszVarBegin, cch);
if (!V_BSTR(&varKey))
{
data.m_pfnNextState = NULL;
return E_OUTOFMEMORY;
}
CComVariant varValue;
HRESULT hr = data.m_pEvent->get_Property(&varKey, &varValue);
if (FAILED(hr))
{
data.m_pfnNextState = NULL;
return hr;
}
if (VT_EMPTY == V_VT(&varValue))
{
--data.m_pszVarBegin;
++data.m_pszVarEnd;
if (data.m_pParams)
{
cch = data.m_pszVarEnd - data.m_pszVarBegin;
BSTR bstrValue = SysAllocStringLen(data.m_pszVarBegin, cch);
if (!bstrValue)
{
data.m_pfnNextState = NULL;
return E_OUTOFMEMORY;
}
data.m_pParams->push_back(bstrValue);
}
return ParseState_WriteVar(data);
}
if (VT_BSTR != V_VT(&varValue))
{
VariantChangeTypeEx(&varValue, &varValue, GetThreadLocale(),
VARIANT_LOCALBOOL | VARIANT_ALPHABOOL, VT_BSTR);
if (VT_BSTR != V_VT(&varValue))
{
data.m_pfnNextState = ParseState_Base;
return S_OK;
}
}
UINT cchValue = BSTRLen(V_BSTR(&varValue));
if (!cchValue)
{
if (data.m_pParams)
{
BSTR bstrValue = SysAllocString(L"");
if (!bstrValue)
{
data.m_pfnNextState = NULL;
return E_OUTOFMEMORY;
}
data.m_pParams->push_back(bstrValue);
}
data.m_pfnNextState = ParseState_Base;
return S_OK;
}
data.m_pszVarBegin = V_BSTR(&varValue);
data.m_pszVarEnd = data.m_pszVarBegin + cchValue;
RETURN_FAILED(ParseState_WriteVar(data));
if (data.m_pParams)
{
data.m_pParams->push_back(V_BSTR(&varValue));
V_VT(&varValue) = VT_EMPTY; }
return S_OK;
}