openDecal/Native/DecalDat/DatService.cpp
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

152 lines
4 KiB
C++

// DatService.cpp : Implementation of cDatService
#include "stdafx.h"
#include "DecalDat.h"
#include "DatService.h"
#include "DatLibrary.h"
#include <ApiHook.h>
/////////////////////////////////////////////////////////////////////////////
// cDatService
HANDLE WINAPI CreateFileF( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile )
{
dwShareMode |= FILE_SHARE_READ | FILE_SHARE_WRITE;
return cDatService::g_fn_CreateFile( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile );
}
static cHookDescriptor _hooks[] = {
{ eByName, _T( "kernel32.dll" ), _T( "CreateFileA" ), 0, reinterpret_cast< DWORD >( CreateFileF ), 0 },
};
cDatService::cFileFilter *cDatService::getFilter( LPTSTR szFilter, int nLength )
{
std::string strFilter( szFilter, nLength );
for( cFileFilterList::iterator i = m_filters.begin(); i != m_filters.end(); ++ i )
{
if( strFilter == i->m_strName )
return &(*(i));
}
return NULL;
}
HRESULT cDatService::createFilter( cDatService::cFileFilter *pFilter, REFIID iid, LPVOID *ppvItf )
{
static _bstr_t _strFilter( _T( "FileFilters" ) );
CComPtr< IDecalEnum > pEnumFilter;
if( m_pDecal->get_Configuration( _strFilter, pFilter->m_clsid, &pEnumFilter ) != S_OK )
return E_FAIL;
return pEnumFilter->CreateInstance( iid, ppvItf );
}
HRESULT cDatService::onInitialize()
{
USES_CONVERSION;
static _bstr_t _strPortal( _T( "%ac%\\portal.dat" ) ),
_strCell( _T( "%ac%\\cell.dat" ) );
if( g_p == NULL )
{
hookFunctions( _hooks, 1, true );
g_fn_CreateFile = reinterpret_cast< fn_CreateFile >( _hooks[ 0 ].m_pOldFunction );
g_p = this;
}
CComObject< cDatLibrary > *pComCell, *pComPortal;
CComObject< cDatLibrary >::CreateInstance( &pComCell );
CComObject< cDatLibrary >::CreateInstance( &pComPortal );
pComCell->AddRef();
pComPortal->AddRef();
m_pCell = pComCell;
m_pPortal = pComPortal;
m_pCell->load( this, _strCell, eCell, 256 );
m_pPortal->load( this, _strPortal, ePortal, 1024 );
// Load the list of filters
static _bstr_t _strFilter( _T( "FileFilters" ) ),
_strPrefix( _T( "Prefix" ) ),
_strCache( _T( "Cache" ) );
CComPtr< IDecalEnum > pEnum;
m_pDecal->get_Configuration( _strFilter, GUID_NULL, &pEnum );
while( pEnum->Next() == S_OK )
{
CComVariant vPrefix, vCache;
cFileFilter;
cFileFilter ff;
pEnum->get_ComClass( &ff.m_clsid );
HRESULT hRes = pEnum->get_Property( _strPrefix, &vPrefix );
if( !SUCCEEDED( hRes ) || vPrefix.vt != VT_BSTR )
{
_ASSERT( FALSE );
continue;
}
hRes = pEnum->get_Property( _strCache, &vCache );
if( !SUCCEEDED( hRes ) || vCache.vt != VT_I4 )
{
_ASSERT( FALSE );
continue;
}
ff.m_bCache = !!vCache.lVal;
LPTSTR szPrefix = OLE2T( vPrefix.bstrVal );
::_tcslwr( szPrefix );
ff.m_strName = szPrefix;
m_filters.push_back( ff );
}
return S_OK;
}
void cDatService::onTerminate()
{
m_cache.clear();
m_filters.clear();
if( g_p == this )
{
hookFunctions( _hooks, 1, false );
g_p = NULL;
}
m_pCell->Release();
m_pPortal->Release();
m_pCell = NULL;
m_pPortal = NULL;
}
cDatService *cDatService::g_p = NULL;
cDatService::fn_CreateFile cDatService::g_fn_CreateFile = NULL;
STDMETHODIMP cDatService::Lookup( BSTR strName, IUnknown **ppItf )
{
static _bstr_t _strPortal( _T( "portal" ) ),
_strCell( _T( "cell" ) );
if( ::VarBstrCmp( strName, _strPortal, 0, NORM_IGNORECASE ) == VARCMP_EQ )
return m_pPortal->QueryInterface( IID_IUnknown, reinterpret_cast< void ** >( ppItf ) );
if( ::VarBstrCmp( strName, _strCell, 0, NORM_IGNORECASE ) == VARCMP_EQ )
return m_pCell->QueryInterface( IID_IUnknown, reinterpret_cast< void ** >( ppItf ) );
// None of the above
return E_INVALIDARG;
}