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>
This commit is contained in:
commit
d1442e3747
1382 changed files with 170725 additions and 0 deletions
519
Native/Decal/DecalEnum.cpp
Normal file
519
Native/Decal/DecalEnum.cpp
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
// DecalEnum.cpp : Implementation of cDecalEnum
|
||||
#include "stdafx.h"
|
||||
#include "Decal.h"
|
||||
#include "DecalEnum.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// cDecalEnum
|
||||
|
||||
cDecalEnum::~cDecalEnum()
|
||||
{
|
||||
// Write out the order if there were changes
|
||||
if ( !m_bOrderChanged )
|
||||
return;
|
||||
|
||||
USES_CONVERSION;
|
||||
|
||||
std::string strOrder;
|
||||
strOrder.reserve ( m_keys.size () );
|
||||
|
||||
for ( cKeyList::iterator i = m_keys.begin (); i != m_keys.end(); ++ i )
|
||||
strOrder += i->m_letter;
|
||||
|
||||
// Compile the new order from the
|
||||
RegKey hkGroup;
|
||||
if( hkGroup.Create( HKEY_LOCAL_MACHINE, m_strGroupKey.c_str() ) != ERROR_SUCCESS )
|
||||
{
|
||||
_ASSERTE ( FALSE );
|
||||
return;
|
||||
}
|
||||
|
||||
hkGroup.SetStringValue (_T("Order"), strOrder.c_str ());
|
||||
}
|
||||
|
||||
bool cDecalEnum::Initialize( IDecal *pDecal, BSTR strKey )
|
||||
{
|
||||
_ASSERTE( pDecal != NULL );
|
||||
|
||||
USES_CONVERSION;
|
||||
m_strGroupKey = "SOFTWARE\\Decal\\";
|
||||
m_strGroupKey += OLE2A( strKey );
|
||||
m_strGroup = strKey;
|
||||
m_pDecal = pDecal;
|
||||
m_nIndex = -1;
|
||||
m_bOrderChanged = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT cDecalEnum::Advance( REFCLSID clsid )
|
||||
{
|
||||
// Assign a dummy letter
|
||||
cKeyEntry ke;
|
||||
ke.m_clsid = clsid;
|
||||
ke.m_letter = _T( 'A' );
|
||||
m_keys.reserve ( 1 );
|
||||
m_keys.push_back ( ke );
|
||||
|
||||
return openKeyAt ( 0 );
|
||||
}
|
||||
|
||||
HRESULT cDecalEnum::Begin()
|
||||
{
|
||||
USES_CONVERSION;
|
||||
|
||||
// Load and sort the list
|
||||
RegKey hkGroup;
|
||||
if( hkGroup.Create( HKEY_LOCAL_MACHINE, m_strGroupKey.c_str() ) != ERROR_SUCCESS )
|
||||
return Error ( IDE_GROUPKEYNOTOPEN );
|
||||
|
||||
// Load the order string and prepare a new item string
|
||||
std::string strIdentifiers( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,./;'[]-=`<>?:{}|_+`!@#$%^&*()" );
|
||||
DWORD nMaxOrder = strIdentifiers.length ();
|
||||
LPTSTR szOrder = reinterpret_cast< LPTSTR > ( _alloca ( sizeof ( TCHAR ) * nMaxOrder ) );
|
||||
|
||||
// Count the number of subkeys
|
||||
DWORD dwSubkeys;
|
||||
if ( ::RegQueryInfoKey ( hkGroup, NULL, NULL, NULL, &dwSubkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) != ERROR_SUCCESS )
|
||||
return Error ( IDE_INVALIDSUBKEYS );
|
||||
m_keys.reserve ( dwSubkeys );
|
||||
|
||||
LPTSTR szEndOrder;
|
||||
|
||||
// Load an existing order
|
||||
if ( hkGroup.QueryStringValue (_T("Order"), szOrder, &nMaxOrder) == ERROR_SUCCESS )
|
||||
{
|
||||
szEndOrder = szOrder + ( nMaxOrder - 1 );
|
||||
|
||||
// Sort and merge the differences
|
||||
std::string strOrder ( szOrder, szEndOrder );
|
||||
std::sort ( strOrder.begin (), strOrder.end () );
|
||||
std::string strMerged;
|
||||
strMerged.reserve ( strIdentifiers.length () - ( nMaxOrder - 1 ) );
|
||||
std::set_difference ( strIdentifiers.begin (), strIdentifiers.end (), strOrder.begin (), strOrder.end (), std::inserter ( strMerged, strMerged.end() ) );
|
||||
|
||||
// Reset the identifiers to exclude the currently used ones
|
||||
strIdentifiers.swap ( strMerged );
|
||||
}
|
||||
else
|
||||
{
|
||||
szOrder[ 0 ] = _T( '\0' );
|
||||
szEndOrder = szOrder;
|
||||
}
|
||||
|
||||
std::string::iterator iNextID = strIdentifiers.begin ();
|
||||
|
||||
// Now we walk through the subkeys and insert in order
|
||||
TCHAR szCLSID[ 64 ];
|
||||
|
||||
for ( int i = 0; ::RegEnumKey ( hkGroup, i, szCLSID, sizeof ( szCLSID ) ) == ERROR_SUCCESS; ++ i )
|
||||
{
|
||||
CLSID clsid;
|
||||
HRESULT hRes = ::CLSIDFromString ( T2OLE ( szCLSID ), &clsid );
|
||||
if ( FAILED ( hRes ) )
|
||||
// Skip non-CLSID keys
|
||||
continue;
|
||||
|
||||
RegKey hkItem;
|
||||
if ( hkItem.Open ( hkGroup, szCLSID ) != ERROR_SUCCESS )
|
||||
continue;
|
||||
|
||||
// Attempt to read the sequence indicator
|
||||
TCHAR szSequence[ 4 ];
|
||||
DWORD dwSequence = sizeof ( szSequence );
|
||||
cKeyEntry ke;
|
||||
ke.m_clsid = clsid;
|
||||
|
||||
if ( hkItem.QueryStringValue ( _T( "Order" ), szSequence, &dwSequence ) == ERROR_SUCCESS )
|
||||
{
|
||||
_ASSERTE ( szSequence[ 1 ] == _T( '\0' ) );
|
||||
|
||||
ke.m_letter = *szSequence;
|
||||
insertKey ( ke, szOrder, szEndOrder );
|
||||
continue;
|
||||
}
|
||||
|
||||
// There's no sequence current, add on to the end
|
||||
_ASSERTE ( iNextID != strIdentifiers.end () );
|
||||
ke.m_letter = *( iNextID ++ );
|
||||
m_keys.push_back ( ke );
|
||||
TCHAR szVal[ 2 ] = { ke.m_letter, _T( '\0' ) };
|
||||
hkItem.SetStringValue ( _T( "Order" ), szVal );
|
||||
|
||||
// The sequence is changed by adding items
|
||||
m_bOrderChanged = true;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void cDecalEnum::insertKey ( cKeyEntry &ke, TCHAR *szOrder, TCHAR *szEndOrder )
|
||||
{
|
||||
// Insert the item in the correct order into the list - first
|
||||
// find the sequence number in the list
|
||||
for ( TCHAR *szOrderIndex = szOrder; szOrderIndex != szEndOrder; ++ szOrderIndex )
|
||||
if ( *szOrderIndex == ke.m_letter )
|
||||
break;
|
||||
|
||||
if ( szOrderIndex == szEndOrder )
|
||||
{
|
||||
// This item is last, don't search for anything after
|
||||
m_keys.push_back ( ke );
|
||||
return;
|
||||
}
|
||||
|
||||
// We have an insert, search for the member to insert before
|
||||
for ( szOrderIndex = szOrderIndex + 1; szOrderIndex != szEndOrder; ++ szOrderIndex )
|
||||
{
|
||||
// Search for a matchinf item in the array
|
||||
for ( cKeyList::iterator j = m_keys.begin(); j != m_keys.end(); ++ j )
|
||||
{
|
||||
if ( j->m_letter == *szOrderIndex )
|
||||
{
|
||||
m_keys.insert ( j, ke );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The next entry most likely hasn't been loaded yet - just append
|
||||
m_keys.push_back ( ke );
|
||||
}
|
||||
|
||||
HRESULT cDecalEnum::openKeyAt ( int nIndex )
|
||||
{
|
||||
USES_CONVERSION;
|
||||
|
||||
if ( m_key.m_hKey != NULL )
|
||||
m_key.Close ();
|
||||
|
||||
LPOLESTR strClsid;
|
||||
::StringFromCLSID( m_keys[ nIndex ].m_clsid, &strClsid );
|
||||
LPCTSTR szClsid = OLE2T( strClsid );
|
||||
::CoTaskMemFree( strClsid );
|
||||
|
||||
std::string strItemKey = m_strGroupKey + _T( "\\" );
|
||||
strItemKey += szClsid;
|
||||
if ( m_key.Open ( HKEY_LOCAL_MACHINE, strItemKey.c_str () ) != ERROR_SUCCESS )
|
||||
return Error ( IDE_CLASSKEYNOTFOUND );
|
||||
|
||||
m_nIndex = nIndex;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::get_FriendlyName(BSTR *pVal)
|
||||
{
|
||||
if( pVal == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if( m_key.m_hKey == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return Error ( IDE_BADITERATOR );
|
||||
}
|
||||
|
||||
USES_CONVERSION;
|
||||
|
||||
TCHAR szName[ MAX_PATH ];
|
||||
DWORD dwSize = MAX_PATH;
|
||||
if( m_key.QueryStringValue( NULL, szName, &dwSize ) != ERROR_SUCCESS )
|
||||
return E_FAIL;
|
||||
|
||||
*pVal = T2BSTR( szName );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::get_ComClass(CLSID *pVal)
|
||||
{
|
||||
if( pVal == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if( m_key.m_hKey == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return Error ( IDE_BADITERATOR );
|
||||
}
|
||||
|
||||
USES_CONVERSION;
|
||||
|
||||
*pVal = m_keys[ m_nIndex ].m_clsid;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::get_Enabled(VARIANT_BOOL *pVal)
|
||||
{
|
||||
if( pVal == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if( m_key.m_hKey == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return Error ( IDE_BADITERATOR );
|
||||
}
|
||||
|
||||
DWORD dwEnabled;
|
||||
if( m_key.QueryDWORDValue( _T("Enabled"), dwEnabled ) != ERROR_SUCCESS )
|
||||
// Plugins are enabled when this value is ommitted
|
||||
dwEnabled = TRUE;
|
||||
|
||||
*pVal = ( dwEnabled ) ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::put_Enabled(VARIANT_BOOL newVal)
|
||||
{
|
||||
if( m_key.m_hKey == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return Error ( IDE_BADITERATOR );
|
||||
}
|
||||
|
||||
if( m_key.SetDWORDValue( _T( "Enabled" ), ( ( newVal ) ? 1 : 0 ) ) != ERROR_SUCCESS )
|
||||
return E_FAIL;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::CreateInstance(REFIID iid, LPVOID *ppvItf)
|
||||
{
|
||||
CLSID clsidSurrogate;
|
||||
if( FAILED( get_SurrogateClass( &clsidSurrogate ) ) )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if( clsidSurrogate == GUID_NULL )
|
||||
{
|
||||
// Create the object without a surrogate
|
||||
CLSID clsidObject;
|
||||
HRESULT hRes = get_ComClass( &clsidObject );
|
||||
if( FAILED( hRes ) )
|
||||
return hRes;
|
||||
|
||||
return ::CoCreateInstance( clsidObject, NULL, CLSCTX_INPROC_SERVER, iid, ppvItf );
|
||||
}
|
||||
|
||||
// Create the surrogate object
|
||||
CComPtr< IDecalEnum > pEnum;
|
||||
static _bstr_t _strSurrogates ( _T( "Surrogates" ) );
|
||||
|
||||
HRESULT hRes = m_pDecal->get_Configuration ( _strSurrogates, clsidSurrogate, &pEnum );
|
||||
if ( !SUCCEEDED ( hRes ) )
|
||||
return hRes;
|
||||
|
||||
VARIANT_BOOL bEnabled;
|
||||
hRes = pEnum->get_Enabled ( &bEnabled );
|
||||
_ASSERTE ( SUCCEEDED ( hRes ) );
|
||||
|
||||
if ( !bEnabled )
|
||||
return Error ( IDE_SURROGATEDISABLED );
|
||||
|
||||
CComPtr< IDecalSurrogate > pSurrogate;
|
||||
hRes = pEnum->CreateInstance ( IID_IDecalSurrogate, reinterpret_cast< LPVOID * > ( &pSurrogate ) );
|
||||
|
||||
if( FAILED( hRes ) )
|
||||
return hRes;
|
||||
|
||||
return pSurrogate->CreateInstance( this, iid, ppvItf );
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::Next()
|
||||
{
|
||||
if ( m_nIndex == m_keys.size () - 1 )
|
||||
{
|
||||
// End of iteration
|
||||
if ( m_key.m_hKey != NULL )
|
||||
m_key.Close ();
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
return openKeyAt ( m_nIndex + 1 );
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::get_SurrogateClass(CLSID *pVal)
|
||||
{
|
||||
if( pVal == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if( m_key.m_hKey == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return Error ( IDE_BADITERATOR );
|
||||
}
|
||||
|
||||
USES_CONVERSION;
|
||||
|
||||
TCHAR szName[ MAX_PATH + 1 ];
|
||||
DWORD dwSize = MAX_PATH + 1;
|
||||
|
||||
if( m_key.QueryStringValue( _T("Surrogate"), szName, &dwSize ) != ERROR_SUCCESS )
|
||||
{
|
||||
// If the surrogate is not found, return the NULL guid
|
||||
*pVal = GUID_NULL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return ::CLSIDFromString( T2OLE( szName ), pVal );
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::get_ResourcePath(BSTR *pVal)
|
||||
{
|
||||
if( pVal == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if( m_key.m_hKey == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return Error ( IDE_BADITERATOR );
|
||||
}
|
||||
|
||||
USES_CONVERSION;
|
||||
|
||||
TCHAR szName[ MAX_PATH ];
|
||||
DWORD dwSize = MAX_PATH;
|
||||
if( m_key.QueryStringValue( NULL, szName, &dwSize ) != ERROR_SUCCESS )
|
||||
return E_FAIL;
|
||||
|
||||
*pVal = T2BSTR( szName );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::get_Property(BSTR Name, VARIANT *pVal)
|
||||
{
|
||||
if( pVal == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if( m_key.m_hKey == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return Error ( IDE_BADITERATOR );
|
||||
}
|
||||
|
||||
USES_CONVERSION;
|
||||
|
||||
LPCTSTR szValueName = OLE2T( Name );
|
||||
|
||||
// Get some info about the property
|
||||
DWORD dwDataType;
|
||||
if( ::RegQueryValueEx( m_key.m_hKey, szValueName, NULL, &dwDataType, NULL, NULL ) != ERROR_SUCCESS )
|
||||
// We'll assume there's no value
|
||||
return E_INVALIDARG;
|
||||
|
||||
switch( dwDataType )
|
||||
{
|
||||
case REG_DWORD:
|
||||
{
|
||||
DWORD dwValue;
|
||||
if( m_key.QueryDWORDValue( szValueName, dwValue ) != ERROR_SUCCESS )
|
||||
return E_FAIL;
|
||||
|
||||
pVal->vt = VT_I4;
|
||||
pVal->lVal = dwValue;
|
||||
return S_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_EXPAND_SZ:
|
||||
case REG_SZ:
|
||||
{
|
||||
TCHAR szValue[ MAX_PATH ];
|
||||
DWORD dwSize = MAX_PATH;
|
||||
if( m_key.QueryStringValue( szValueName, szValue, &dwSize ) != ERROR_SUCCESS )
|
||||
return E_FAIL;
|
||||
|
||||
pVal->vt = VT_BSTR;
|
||||
pVal->bstrVal = T2BSTR( szValue );
|
||||
return S_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::get_Group(BSTR *pVal)
|
||||
{
|
||||
if( pVal == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
*pVal = OLE2BSTR( m_strGroup );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::Skip (REFCLSID clsid)
|
||||
{
|
||||
// Search our loaded list for the clsid
|
||||
for ( cKeyList::iterator i = m_keys.begin (); i != m_keys.end(); ++ i )
|
||||
{
|
||||
if ( clsid == i->m_clsid )
|
||||
return openKeyAt ( i - m_keys.begin() );
|
||||
}
|
||||
|
||||
return Error ( IDE_CLASSNOTFOUND );
|
||||
}
|
||||
|
||||
STDMETHODIMP cDecalEnum::MoveBefore(REFCLSID clsidBefore)
|
||||
{
|
||||
if( m_key.m_hKey == NULL )
|
||||
{
|
||||
_ASSERT( FALSE );
|
||||
return Error ( IDE_BADITERATOR );
|
||||
}
|
||||
|
||||
// Find the entry we're inserting before
|
||||
for ( cKeyList::iterator i = m_keys.begin (); i != m_keys.end(); ++ i )
|
||||
{
|
||||
if ( i->m_clsid == clsidBefore )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( i == m_keys.end () )
|
||||
return Error ( IDE_CLASSNOTFOUND );
|
||||
|
||||
int nFoundIndex = i - m_keys.begin ();
|
||||
if ( nFoundIndex == m_nIndex )
|
||||
// No op
|
||||
return S_FALSE;
|
||||
|
||||
if ( nFoundIndex > m_nIndex )
|
||||
-- nFoundIndex;
|
||||
|
||||
cKeyEntry eRemoved = m_keys[ m_nIndex ];
|
||||
m_keys.erase ( m_keys.begin () + m_nIndex );
|
||||
|
||||
m_keys.insert ( m_keys.begin () + nFoundIndex, eRemoved );
|
||||
|
||||
// Reset so we're still on the same item
|
||||
m_nIndex = nFoundIndex;
|
||||
m_bOrderChanged = true;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue