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>
194 lines
6.1 KiB
C++
194 lines
6.1 KiB
C++
// ActiveXSurrogate.cpp : Implementation of cActiveXSurrogate
|
|
#include "stdafx.h"
|
|
#include "Decal.h"
|
|
#include "ActiveXSurrogate.h"
|
|
|
|
// Duplicated from Inject.h to prevent circular dependency
|
|
class IPluginSite;
|
|
|
|
class __declspec(uuid("{BA3E677F-8E44-4829-982E-58BBBC5C5F9B}")) IPlugin
|
|
: public IUnknown
|
|
{
|
|
public:
|
|
STDMETHOD(Initialize)(IPluginSite *pSite, long) = 0;
|
|
STDMETHOD(Terminate)() = 0;
|
|
STDMETHOD(get_FriendlyName)(BSTR *pstrName) = 0;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// cActiveXSurrogate
|
|
|
|
typedef HRESULT (__stdcall *pfnDllRegisterServer)();
|
|
typedef HRESULT (__stdcall *pfnDllUnregisterServer)();
|
|
|
|
STDMETHODIMP cActiveXSurrogate::Register(BSTR strFilename)
|
|
{
|
|
USES_CONVERSION;
|
|
LPCTSTR szFilename = OLE2T( strFilename );
|
|
|
|
// First, register the library
|
|
HMODULE hLib = ::LoadLibrary( szFilename );
|
|
if( hLib == NULL )
|
|
return E_FAIL;
|
|
|
|
pfnDllRegisterServer pfnReg = reinterpret_cast< pfnDllRegisterServer >( ::GetProcAddress( hLib, _T( "DllRegisterServer" ) ) );
|
|
HRESULT hRes = E_FAIL;
|
|
if( pfnReg != NULL )
|
|
hRes = pfnReg();
|
|
|
|
::FreeLibrary( hLib );
|
|
|
|
if( FAILED( hRes ) )
|
|
return hRes;
|
|
|
|
// Next open up the type library and look for suitable classes, they have
|
|
// to be creatable - then we make one and see if it implements IPlugin2
|
|
CComPtr< ITypeLib > pTypeLib;
|
|
hRes = ::LoadTypeLib( strFilename, &pTypeLib );
|
|
|
|
if( FAILED( hRes ) )
|
|
return hRes;
|
|
|
|
UINT nTypeInfoCount = pTypeLib->GetTypeInfoCount();
|
|
int nFound = 0;
|
|
|
|
for( UINT i = 0; i < nTypeInfoCount; ++ i )
|
|
{
|
|
TYPEKIND tk;
|
|
pTypeLib->GetTypeInfoType( i, &tk );
|
|
|
|
if( tk != TKIND_COCLASS )
|
|
// Only coclasses
|
|
continue;
|
|
|
|
CComPtr< ITypeInfo > pClass1;
|
|
pTypeLib->GetTypeInfo( i, &pClass1 );
|
|
|
|
TYPEATTR *pta;
|
|
pClass1->GetTypeAttr( &pta );
|
|
|
|
if( pta->wTypeFlags & TYPEFLAG_FCANCREATE )
|
|
{
|
|
// Create an instance of the plugin and see if it implements IPlugin
|
|
CComPtr< IUnknown > pUnkPlugin;
|
|
HRESULT hRes = pClass1->CreateInstance ( NULL, IID_IUnknown, reinterpret_cast< LPVOID * > ( &pUnkPlugin ) );
|
|
if ( SUCCEEDED ( hRes ) )
|
|
{
|
|
// Check for the IPlugin2 interface
|
|
CComPtr< IPlugin2 > pPlugin2;
|
|
if ( SUCCEEDED ( pUnkPlugin->QueryInterface ( &pPlugin2 ) ) )
|
|
{
|
|
// This is a plugin (anything that implements IPlugin2 is a plugin afterall, make the registry key
|
|
LPCSTR szCLSID;
|
|
LPOLESTR strCLSID;
|
|
::StringFromCLSID( pta->guid, &strCLSID );
|
|
szCLSID = OLE2T( strCLSID );
|
|
::CoTaskMemFree( strCLSID );
|
|
|
|
TCHAR szRegKey[ 255 ];
|
|
::_tcscat ( ::_tcscpy ( szRegKey, _T( "Software\\Decal\\Plugins\\" ) ), szCLSID );
|
|
|
|
RegKey key;
|
|
key.Create( HKEY_LOCAL_MACHINE, szRegKey );
|
|
|
|
CComBSTR strDescription;
|
|
pClass1->GetDocumentation( MEMBERID_NIL, NULL, &strDescription, NULL, NULL );
|
|
|
|
key.SetStringValue( NULL, OLE2T( strDescription ) );
|
|
key.SetStringValue( _T("File"), szFilename );
|
|
key.SetDWORDValue( _T( "Enabled" ), 1 );
|
|
key.SetStringValue( _T("Uninstall"), _T( "{7559F22F-C56F-4621-AE08-9C354D799D4B}" ) );
|
|
|
|
++ nFound;
|
|
}
|
|
else
|
|
{
|
|
CComPtr< IPlugin > pPlugin;
|
|
if ( SUCCEEDED( pUnkPlugin->QueryInterface ( &pPlugin ) ) )
|
|
{
|
|
// This is a V1 plugin - same registration, but use a surrogate
|
|
LPCSTR szCLSID;
|
|
LPOLESTR strCLSID;
|
|
::StringFromCLSID( pta->guid, &strCLSID );
|
|
szCLSID = OLE2T( strCLSID );
|
|
::CoTaskMemFree( strCLSID );
|
|
|
|
TCHAR szRegKey[ 255 ];
|
|
::_tcscat ( ::_tcscpy ( szRegKey, _T( "Software\\Decal\\Plugins\\" ) ), szCLSID );
|
|
|
|
RegKey key;
|
|
key.Create( HKEY_LOCAL_MACHINE, szRegKey );
|
|
|
|
CComBSTR strDescription;
|
|
pPlugin->get_FriendlyName( &strDescription );
|
|
|
|
// Friendly name
|
|
key.SetStringValue( NULL, OLE2T( strDescription ) );
|
|
// File for uninstalling
|
|
key.SetStringValue( _T( "File" ), szFilename );
|
|
// Enabled by default
|
|
key.SetDWORDValue( _T( "Enabled" ), 1 );
|
|
// This object uninstalls
|
|
key.SetStringValue( _T("Uninstall"), _T( "{7559F22F-C56F-4621-AE08-9C354D799D4B}" ));
|
|
// The V1 surrogate
|
|
key.SetStringValue( _T( "Surrogate" ), _T( "{3D837F6E-B5CA-4604-885F-7AB45FCFA62A}" ) );
|
|
|
|
++ nFound;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pClass1->ReleaseTypeAttr( pta );
|
|
}
|
|
|
|
return ( nFound > 0 ) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP cActiveXSurrogate::Uninstall()
|
|
{
|
|
USES_CONVERSION;
|
|
TCHAR szParent[ 255 ];
|
|
::_tcscat ( ::_tcscpy ( szParent, _T( "Software\\Decal\\Plugins\\" ) ), OLE2T( m_strGroup ) );
|
|
|
|
RegKey rk;
|
|
if( rk.Open( HKEY_LOCAL_MACHINE, szParent ) != ERROR_SUCCESS )
|
|
{
|
|
_ASSERT( FALSE );
|
|
return E_FAIL;
|
|
}
|
|
|
|
LPOLESTR strCLSID;
|
|
::StringFromCLSID( m_clsid, &strCLSID );
|
|
|
|
LPTSTR szCLSID = OLE2T( strCLSID );
|
|
|
|
::CoTaskMemFree( strCLSID );
|
|
|
|
if( rk.RecurseDeleteKey( szCLSID ) != ERROR_SUCCESS )
|
|
{
|
|
_ASSERT( FALSE );
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Load the library and call DLL unreg server
|
|
LPCTSTR szFilename = OLE2T( m_strFile );
|
|
|
|
// First, register the library
|
|
HMODULE hLib = ::LoadLibrary( szFilename );
|
|
if( hLib == NULL )
|
|
return E_FAIL;
|
|
|
|
pfnDllUnregisterServer pfnReg = reinterpret_cast< pfnDllUnregisterServer >( ::GetProcAddress( hLib, _T( "DllUnregisterServer" ) ) );
|
|
HRESULT hRes = E_FAIL;
|
|
if( pfnReg != NULL )
|
|
hRes = pfnReg();
|
|
|
|
::FreeLibrary( hLib );
|
|
|
|
// Just call this to make sure the library isn't locked so the user
|
|
// can delete it after this point.
|
|
::CoFreeUnusedLibraries();
|
|
|
|
return hRes;
|
|
}
|