openDecal/Native/DecalNet/MessageImpl.h
erik d1442e3747 Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild:

Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil)
Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs
  - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters
  - Decal.Core, DecalControls, DecalRender, D3DService
Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL
Phase 4: DenAgent WinForms tray application
Phase 5: WiX installer and build script

25 C# projects building with 0 errors.
Native C++ projects require VS 2022 + Windows SDK (x86).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:27:56 +01:00

363 lines
8.1 KiB
C++

// MessageImpl.h
// Declaration of helper classes for implementing the IMessageMembers interface
#ifndef __MESSAGEIMPL_H
#define __MESSAGEIMPL_H
#include "Message.h"
template< class ImplT >
class ATL_NO_VTABLE IMessageIteratorImpl
: public IDispatchImpl< IMessageIterator, &__uuidof( IMessageIterator ), &LIBID_DecalNet >
{
public:
enum { eEndIndex = 0xFFFFFFFF };
cMessage *getSource();
DWORD getStartIndex();
DWORD getEndIndex();
DWORD m_dwIterator;
long m_nIndex;
void init()
{
m_nIndex = -1;
}
DWORD getNextIndex( DWORD dwIndex )
{
DWORD dwNextIndex = dwIndex + ( static_cast< ImplT * >( this )->getSource()->m_fields.begin() + dwIndex )->m_nOwns;
if( dwNextIndex == static_cast< ImplT * >( this )->getEndIndex() )
return eEndIndex;
return dwNextIndex;
}
DWORD getNextIndex()
{
if( m_nIndex == -1 )
{
DWORD dwIndex = static_cast< ImplT * >( this )->getStartIndex();
if ( dwIndex == static_cast< ImplT * >( this )->getEndIndex () )
// This was 0 size
return eEndIndex;
return dwIndex;
}
return static_cast< ImplT * >( this )->getNextIndex( m_dwIterator );
}
HRESULT advanceToIndex( long nIndex )
{
if( nIndex <= m_nIndex )
{
_ASSERT( FALSE );
return E_INVALIDARG;
}
int nCurIndex = m_nIndex;
for( DWORD dwIterator = static_cast< ImplT * >( this )->getNextIndex(); dwIterator != eEndIndex; dwIterator = static_cast< ImplT * >( this )->getNextIndex( dwIterator ) )
{
// Reset the counter
++ nCurIndex;
if( nCurIndex == nIndex )
{
m_dwIterator = dwIterator;
m_nIndex = nCurIndex;
return S_OK;
}
}
// The advance went off the edge
m_dwIterator = eEndIndex;
return S_FALSE;
}
HRESULT advanceToName( BSTR strName )
{
int nIndex = m_nIndex;
for( DWORD dwIterator = static_cast< ImplT * >( this )->getNextIndex(); dwIterator != eEndIndex; dwIterator = static_cast< ImplT * >( this )->getNextIndex( dwIterator ) )
{
++ nIndex;
if( ::VarBstrCmp( strName, ( static_cast< ImplT * >( this )->getSource()->m_fields.begin() + dwIterator )->m_pSchema->m_strName, LOCALE_USER_DEFAULT, 0 ) == VARCMP_EQ )
{
// We've found the field
m_nIndex = nIndex;
m_dwIterator = dwIterator;
return S_OK;
}
}
return S_FALSE;
}
HRESULT advanceNext()
{
m_dwIterator = static_cast< ImplT * >( this )->getNextIndex();
if( m_dwIterator == eEndIndex )
return S_FALSE;
++ m_nIndex;
return S_OK;
}
STDMETHOD(get_Current)(VARIANT *pData)
{
if( pData == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
if( m_dwIterator == eEndIndex )
{
pData->vt = VT_NULL;
return E_FAIL;
}
cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator;
i->m_pSchema->getValue( static_cast< ImplT * >( this )->getSource(), i, pData );
return S_OK;
}
STDMETHOD(get_MemberName)( BSTR *pstrName )
{
if( pstrName == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
if( m_dwIterator == eEndIndex )
return E_FAIL;
cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator;
*pstrName = SysAllocString( i->m_pSchema->m_strName );
return S_OK;
}
STDMETHOD(get_Index)( long *pnIndex )
{
if( pnIndex == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
if( m_dwIterator == eEndIndex )
return E_FAIL;
*pnIndex = m_nIndex;
return S_OK;
}
STDMETHOD(get_Next)( VARIANT vIndex, LPVARIANT pvValue )
{
if( pvValue == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
HRESULT hRes;
if( vIndex.vt == VT_ERROR )
// Error value indicates the optional value was not filled
hRes = advanceNext();
else if( vIndex.vt == VT_BSTR )
hRes = advanceToName( vIndex.bstrVal );
else
{
// Try and convert it to a long
HRESULT hResConv = ::VariantChangeType( &vIndex, &vIndex, 0, VT_I4 );
if( FAILED( hResConv ) )
{
_ASSERT( FALSE );
return E_INVALIDARG;
}
hRes = advanceToIndex( vIndex.lVal );
}
if( hRes == S_FALSE )
{
pvValue->vt = VT_NULL;
return hRes;
}
cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator;
i->m_pSchema->getValue( static_cast< ImplT * >( this )->getSource(), i, pvValue );
return S_OK;
}
STDMETHOD(get_NextString)(BSTR Name, BSTR *pValue)
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = Name;
VARIANT vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt != VT_BSTR )
{
_ASSERT( FALSE );
return E_FAIL;
}
*pValue = vOut.bstrVal;
return S_OK;
}
STDMETHOD(get_NextInt)(BSTR Name, long *pValue)
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = Name;
VARIANT vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt == VT_I4 )
*pValue = vOut.lVal;
else if( vOut.vt == VT_I2 )
*pValue = vOut.iVal;
else if ( vOut.vt == VT_UI1 )
*pValue = vOut.bVal;
else
{
_ASSERT( FALSE );
return E_FAIL;
}
return S_OK;
}
STDMETHOD(get_NextFloat)(BSTR Name, float *pValue)
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = Name;
VARIANT vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt == VT_R4 )
*pValue = vOut.fltVal;
else if( vOut.vt == VT_R8 )
*pValue = static_cast< float >( vOut.dblVal );
else
{
_ASSERT( FALSE );
return E_FAIL;
}
return S_OK;
}
STDMETHOD(get_NextObject)(BSTR Name, IMessageIterator **pValue)
{
VARIANT v;
v.vt = VT_BSTR;
v.bstrVal = Name;
VARIANT vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt != VT_DISPATCH )
{
_ASSERT( FALSE );
return E_FAIL;
}
return vOut.pdispVal->QueryInterface ( pValue );
}
STDMETHOD(get_NextObjectIndex)(IMessageIterator **pValue)
{
VARIANT v;
v.vt = VT_ERROR;
CComVariant vOut;
HRESULT hRes = get_Next( v, &vOut );
if( hRes == S_FALSE )
return E_FAIL;
if( vOut.vt != VT_DISPATCH )
{
_ASSERT( FALSE );
return E_FAIL;
}
return vOut.pdispVal->QueryInterface ( pValue );
}
STDMETHOD(Reset)()
{
m_nIndex = -1;
return S_OK;
}
STDMETHOD(get_Message)(IMessage **ppMessage)
{
if( ppMessage == NULL )
{
_ASSERT( FALSE );
return E_POINTER;
}
static_cast< ImplT * >( this )->getSource()->QueryInterface( IID_IMessage, reinterpret_cast< void ** >( ppMessage ) );
return S_OK;
}
};
class IMessageIteratorSublistImpl
: public IMessageIteratorImpl< IMessageIteratorSublistImpl >
{
public:
cMessage *m_pSource;
DWORD m_dwStartIndex,
m_dwEndIndex;
cMessage *getSource()
{
return m_pSource;
}
DWORD getStartIndex()
{
return m_dwStartIndex;
}
DWORD getEndIndex()
{
return m_dwEndIndex;
}
void init( cMessage *pMessage, DWORD dwStructIndex )
{
m_pSource = pMessage;
m_dwStartIndex = dwStructIndex + 1;
m_dwEndIndex = dwStructIndex + ( m_pSource->m_fields.begin() + dwStructIndex )->m_nOwns;
IMessageIteratorImpl< IMessageIteratorSublistImpl >::init();
}
};
#endif