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>
691 lines
18 KiB
C++
691 lines
18 KiB
C++
// DenAgent.cpp : Defines the class behaviors for the application.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "DenAgent.h"
|
|
#include "DenAgentDlg.h"
|
|
|
|
#include "TrayWnd.h"
|
|
#include <initguid.h>
|
|
#include "DenAgent_i.c"
|
|
#include "..\Inject\Inject.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
//FILELIST g_FileList[] = { { "messages.xml", "messages.dlc" }, { "memlocs.xml", "messages.dlc" }, { "decalplugins.xml", "messages.dlc" } };
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDenAgentApp
|
|
|
|
BEGIN_MESSAGE_MAP(CDenAgentApp, CWinApp)
|
|
//{{AFX_MSG_MAP(CDenAgentApp)
|
|
// NOTE - the ClassWizard will add and remove mapping macros here.
|
|
// DO NOT EDIT what you see in these blocks of generated code!
|
|
//}}AFX_MSG
|
|
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDenAgentApp construction
|
|
|
|
CDenAgentApp::CDenAgentApp()
|
|
{
|
|
// TODO: add construction code here,
|
|
// Place all significant initialization in InitInstance
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// The one and only CDenAgentApp object
|
|
|
|
CDenAgentApp theApp;
|
|
LONG g_fAbortDownload;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDenAgentApp initialization
|
|
|
|
bool CheckForHardwareMode ()
|
|
{
|
|
RegKey key;
|
|
|
|
if (key.Open (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00", KEY_READ) != ERROR_SUCCESS)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DWORD dwValue = 0;
|
|
|
|
if (key.QueryDWORDValue ("UseHardware", dwValue) != ERROR_SUCCESS)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return dwValue ? true : false;
|
|
}
|
|
|
|
bool CheckForIE5OrLater ()
|
|
{
|
|
RegKey key;
|
|
|
|
if (key.Open (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Internet Explorer", KEY_READ) != ERROR_SUCCESS)
|
|
return false;
|
|
|
|
DWORD dwValue = 0;
|
|
|
|
TCHAR szVersionBuffer[256];
|
|
DWORD dwSize = sizeof (szVersionBuffer);
|
|
|
|
if (key.QueryStringValue("Version", szVersionBuffer, &dwSize) != ERROR_SUCCESS)
|
|
return false;
|
|
|
|
DWORD dwMajor = 0, dwMinor = 0, dwBuild1 = 0, dwBuild2 = 0;
|
|
|
|
if (::_stscanf (szVersionBuffer, _T("%ld.%ld.%ld.%ld"), &dwMajor, &dwMinor, &dwBuild1, &dwBuild2) != 4)
|
|
return false;
|
|
|
|
// IE 5.01 is build: 5.00.2919.6307
|
|
return !( dwMajor < 5 || ( dwMajor == 5 && dwMinor == 0 ) && ( ( dwBuild1 < 2919 ) || ( dwBuild1 == 2919 && dwBuild2 < 6307 ) ) );
|
|
}
|
|
|
|
bool CDenAgentApp::getVersionString ( LPCTSTR szFilename, CString &strVersion )
|
|
{
|
|
DWORD dwDummy,
|
|
dwVerSize = ::GetFileVersionInfoSize( const_cast< LPTSTR > ( szFilename ), &dwDummy );
|
|
if( dwVerSize == 0 )
|
|
return false;
|
|
|
|
BYTE *pbVersionInfo = reinterpret_cast< BYTE * >( ::_alloca( dwVerSize ) );
|
|
|
|
::GetFileVersionInfo( const_cast< LPTSTR > ( szFilename ), 0, dwVerSize, pbVersionInfo );
|
|
|
|
VS_FIXEDFILEINFO *vffi;
|
|
UINT nLength = sizeof( VS_FIXEDFILEINFO );
|
|
if( !::VerQueryValue( pbVersionInfo, _T( "\\" ), reinterpret_cast< LPVOID * >( &vffi ), &nLength ) )
|
|
return false;
|
|
|
|
// Got it, so format it
|
|
strVersion.FormatMessage ( IDS_VERSIONTEMPLATE, static_cast< int > ( HIWORD ( vffi->dwFileVersionMS ) ),
|
|
static_cast< int > ( LOWORD ( vffi->dwFileVersionMS ) ), static_cast< int > ( HIWORD ( vffi->dwFileVersionLS ) ),
|
|
static_cast< int > ( LOWORD ( vffi->dwFileVersionLS ) ) );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CDenAgentApp::getVersionInfo ( LPCTSTR szFilename, int &iReleaseMajor, int &iReleaseMinor, int &iBuildMajor, int &iBuildMinor )
|
|
{
|
|
DWORD dwDummy,
|
|
dwVerSize = ::GetFileVersionInfoSize( const_cast< LPTSTR > ( szFilename ), &dwDummy );
|
|
if( dwVerSize == 0 )
|
|
return false;
|
|
|
|
BYTE *pbVersionInfo = reinterpret_cast< BYTE * >( ::_alloca( dwVerSize ) );
|
|
|
|
::GetFileVersionInfo( const_cast< LPTSTR > ( szFilename ), 0, dwVerSize, pbVersionInfo );
|
|
|
|
VS_FIXEDFILEINFO *vffi;
|
|
UINT nLength = sizeof( VS_FIXEDFILEINFO );
|
|
if( !::VerQueryValue( pbVersionInfo, _T( "\\" ), reinterpret_cast< LPVOID * >( &vffi ), &nLength ) )
|
|
return false;
|
|
|
|
// Got it, so format it
|
|
iReleaseMajor = static_cast< int > ( HIWORD ( vffi->dwFileVersionMS ) );
|
|
iReleaseMinor = static_cast< int > ( LOWORD ( vffi->dwFileVersionMS ) );
|
|
iBuildMajor = static_cast< int > ( HIWORD ( vffi->dwFileVersionLS ) );
|
|
iBuildMinor = static_cast< int > ( LOWORD ( vffi->dwFileVersionLS ) );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CDenAgentApp::getACVersionString ( CString &strVersion )
|
|
{
|
|
RegKey rk;
|
|
if ( rk.Open ( HKEY_LOCAL_MACHINE, _T( "Software\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00" ) ) != ERROR_SUCCESS )
|
|
{
|
|
::AfxMessageBox ( IDE_NOCLIENTEXE, MB_ICONWARNING );
|
|
return false;
|
|
}
|
|
|
|
TCHAR szClientPath[ MAX_PATH ];
|
|
DWORD dwPathLength = MAX_PATH;
|
|
if ( rk.QueryStringValue ( _T( "path" ), szClientPath, &dwPathLength ) != ERROR_SUCCESS )
|
|
{
|
|
::AfxMessageBox ( IDE_NOCLIENTEXE, MB_ICONWARNING );
|
|
return false;
|
|
}
|
|
|
|
::_tcscpy ( szClientPath + ( dwPathLength - 1 ), _T( "\\client.exe" ) );
|
|
|
|
bool bHasVersion = getVersionString ( szClientPath, strVersion );
|
|
|
|
if ( !bHasVersion )
|
|
::AfxMessageBox ( IDE_NOCLIENTVER, MB_ICONWARNING );
|
|
|
|
return bHasVersion;
|
|
}
|
|
|
|
bool CDenAgentApp::getCOMObjectDLL ( REFCLSID rclsid, CString &strFilename )
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
LPOLESTR oclsid;
|
|
HRESULT hRes = ::StringFromCLSID ( rclsid, &oclsid );
|
|
_ASSERTE ( SUCCEEDED ( hRes ) );
|
|
LPCTSTR clsidName = OLE2T ( oclsid );
|
|
::CoTaskMemFree ( oclsid );
|
|
|
|
TCHAR keyName[ MAX_PATH ];
|
|
::_stprintf ( keyName, _T( "CLSID\\%s\\InprocServer32" ), clsidName );
|
|
|
|
RegKey rk;
|
|
if ( rk.Open ( HKEY_CLASSES_ROOT, keyName ) != ERROR_SUCCESS )
|
|
return false;
|
|
|
|
DWORD dwPathSize = MAX_PATH;
|
|
|
|
long regResult = rk.QueryStringValue ( NULL, strFilename.GetBuffer ( MAX_PATH ), &dwPathSize );
|
|
|
|
strFilename.ReleaseBuffer();
|
|
|
|
if (regResult != ERROR_SUCCESS)
|
|
return false;
|
|
|
|
// Check to see if the default KeyValue points to the MS.NET core DLL
|
|
const char *dotNetProxy = "mscoree.dll";
|
|
|
|
CString dotNetMatchString = strFilename.Right(strlen(dotNetProxy));
|
|
|
|
if (dotNetMatchString.CompareNoCase(dotNetProxy) == 0)
|
|
{
|
|
// Get CodeBase KeyValue - Should point to the Plugin DLL
|
|
dwPathSize = MAX_PATH;
|
|
if (rk.QueryStringValue ( "CodeBase", strFilename.GetBuffer ( MAX_PATH ), &dwPathSize ) == ERROR_SUCCESS)
|
|
{
|
|
// Release extra buffer (Not doing this seem to cause the Left() and Delete() funcs to fail)
|
|
strFilename.ReleaseBuffer();
|
|
// Check for garbage in KeyValue and delete it
|
|
if (strFilename.Left(8) == "file:///")
|
|
strFilename.Delete(0,8);
|
|
}
|
|
else
|
|
{
|
|
// CodeBase isn't accessable - Possible that plugin is in GAC
|
|
// Return Path to MS.NET core DLL
|
|
dwPathSize = MAX_PATH;
|
|
if (rk.QueryStringValue ( NULL, strFilename.GetBuffer ( MAX_PATH ), &dwPathSize ) != ERROR_SUCCESS)
|
|
{
|
|
rk.Close();
|
|
strFilename.ReleaseBuffer();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
rk.Close();
|
|
return true;
|
|
}
|
|
|
|
bool CDenAgentApp::getAgentPath ( LPCTSTR szFilename, CString &strPath )
|
|
{
|
|
TCHAR *szAgentPath = strPath.GetBuffer ( MAX_PATH );
|
|
::GetModuleFileName ( NULL, szAgentPath, MAX_PATH );
|
|
|
|
TCHAR *filePath = ::_tcsrchr ( szAgentPath, _T( '\\' ) );
|
|
::strcpy ( filePath + 1, szFilename );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CDenAgentApp::checkXMLVersion ( CString &strClientVersion, CString &strXMLFile, CTrayWnd* pTrayWnd )
|
|
{
|
|
MSXML::IXMLDOMDocumentPtr pDoc;
|
|
|
|
try
|
|
{
|
|
pDoc.CreateInstance ( __uuidof ( MSXML::DOMDocument ), NULL, CLSCTX_INPROC_SERVER );
|
|
pDoc->async = false;
|
|
BOOL bSuccess = pDoc->load( static_cast< LPCTSTR > ( strXMLFile ) );
|
|
|
|
if( !bSuccess )
|
|
{
|
|
std::string szXML;
|
|
DecryptXML( static_cast< LPCSTR >( strXMLFile ), szXML );
|
|
|
|
if( szXML != "" )
|
|
bSuccess = pDoc->loadXML( _bstr_t( szXML.c_str() ) );
|
|
}
|
|
|
|
if( ! bSuccess )
|
|
{
|
|
CString strMessage;
|
|
strMessage.FormatMessage ( IDE_NOXMLDOC, static_cast< LPCTSTR > ( strXMLFile ) );
|
|
|
|
CString strUpdate;
|
|
strUpdate.LoadString( IDE_UPDATETEXT );
|
|
strMessage += strUpdate;
|
|
|
|
if ( ::AfxMessageBox ( strMessage, MB_YESNO | MB_ICONERROR ) == IDYES )
|
|
pTrayWnd->UpdateXMLFiles( );
|
|
|
|
return false;
|
|
}
|
|
|
|
// Read the client version string
|
|
MSXML::IXMLDOMNodePtr pVersionNode = pDoc->selectSingleNode ( _T( "/*/@version" ) );
|
|
if ( pVersionNode == NULL )
|
|
{
|
|
CString strError;
|
|
|
|
strError.FormatMessage ( IDE_NOXMLVER, static_cast< LPCTSTR > ( strXMLFile ) );
|
|
::AfxMessageBox ( strError, MB_ICONWARNING );
|
|
|
|
return false;
|
|
}
|
|
|
|
_variant_t vXMLVer = pVersionNode->text;
|
|
if ( vXMLVer.vt != VT_BSTR )
|
|
{
|
|
CString strError;
|
|
|
|
strError.FormatMessage ( IDE_NOXMLVER, static_cast< LPCTSTR > ( strXMLFile ) );
|
|
::AfxMessageBox ( strError, MB_ICONWARNING );
|
|
|
|
return false;
|
|
}
|
|
|
|
CString strXMLVer ( vXMLVer.bstrVal );
|
|
if ( strClientVersion.Compare ( strXMLVer ) != 0 )
|
|
{
|
|
CString str;
|
|
str.FormatMessage ( IDE_XMLCLIENTVERSIONMISMATCH, static_cast< LPCTSTR > ( strXMLFile ),
|
|
static_cast< LPCTSTR > ( strClientVersion ), static_cast< LPCTSTR > ( strXMLVer ) );
|
|
|
|
CString strUpdate;
|
|
strUpdate.LoadString( IDE_UPDATETEXT );
|
|
str += strUpdate;
|
|
|
|
if ( ::AfxMessageBox ( str, MB_YESNO | MB_ICONWARNING ) == IDYES )
|
|
pTrayWnd->UpdateXMLFiles( );
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch ( _com_error & )
|
|
{
|
|
CString strMessage;
|
|
strMessage.FormatMessage ( IDE_NOXMLDOC, static_cast< LPCTSTR > ( strXMLFile ) );
|
|
::AfxMessageBox ( strMessage, MB_ICONERROR );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CDenAgentApp::DecryptXML( const char *szPath, std::string &szXML )
|
|
{
|
|
if( szPath == NULL )
|
|
{
|
|
szXML = "";
|
|
return;
|
|
}
|
|
|
|
FILE *f = fopen( szPath, "rb" );
|
|
if( f == NULL )
|
|
{
|
|
szXML = "";
|
|
return;
|
|
}
|
|
|
|
szXML.clear();
|
|
unsigned char szBuffer[1025];
|
|
|
|
try
|
|
{
|
|
CCryptProv crypt;
|
|
if( crypt.Initialize( PROV_RSA_FULL, "Decal_Memlocs", MS_DEF_PROV ) == NTE_BAD_KEYSET )
|
|
crypt.Initialize( PROV_RSA_FULL, "Decal_Memlocs", MS_DEF_PROV, CRYPT_NEWKEYSET );
|
|
|
|
CCryptMD5Hash hash;
|
|
hash.Initialize( crypt );
|
|
hash.AddString( DECAL_KEY );
|
|
|
|
CCryptDerivedKey key;
|
|
key.Initialize( crypt, hash );
|
|
|
|
DWORD dwDecLen = 0;
|
|
|
|
while( ! feof(f) )
|
|
{
|
|
memset( szBuffer, 0, sizeof( szBuffer ) );
|
|
dwDecLen = fread( szBuffer, 1, 1024, f );
|
|
key.Decrypt( feof(f), (BYTE *) szBuffer, &dwDecLen );
|
|
szXML += (char *)szBuffer;
|
|
}
|
|
|
|
key.Destroy();
|
|
hash.Destroy();
|
|
crypt.Release();
|
|
}
|
|
|
|
catch( ... )
|
|
{
|
|
// crap...
|
|
szXML = "";
|
|
}
|
|
|
|
fclose( f );
|
|
}
|
|
|
|
bool CDenAgentApp::checkXMLVersions ( CTrayWnd* pTrayWnd )
|
|
{
|
|
bool bOK = true;
|
|
// Check the versions of the XML files
|
|
CString strClientVersion;
|
|
if ( getACVersionString ( strClientVersion ) )
|
|
{
|
|
CString strXMLFile;
|
|
if ( getAgentPath ( _T( "memlocs.xml" ), strXMLFile ) )
|
|
bOK = bOK && checkXMLVersion ( strClientVersion, strXMLFile, pTrayWnd );
|
|
//if ( getAgentPath ( _T( "messages.xml" ), strXMLFile ) )
|
|
//bOK = bOK && checkXMLVersion ( strClientVersion, strXMLFile );
|
|
}
|
|
|
|
return bOK;
|
|
}
|
|
|
|
void CDenAgentApp::getXMLBuilds ( cXMLBuild *pFirst, cXMLBuild *pLast )
|
|
{
|
|
MSXML::IXMLDOMDocumentPtr pDoc;
|
|
pDoc.CreateInstance ( __uuidof ( MSXML::DOMDocument ), NULL, CLSCTX_INPROC_SERVER );
|
|
pDoc->async = false;
|
|
|
|
for ( ; pFirst != pLast; ++ pFirst )
|
|
{
|
|
CString strPath;
|
|
getAgentPath ( pFirst->XMLFile, strPath );
|
|
|
|
try
|
|
{
|
|
BOOL bSuccess = pDoc->load( static_cast< LPCTSTR > ( pFirst->XMLFile ) );
|
|
|
|
if( ! bSuccess )
|
|
{
|
|
std::string szXML;
|
|
DecryptXML( static_cast< LPCSTR >( pFirst->XMLFile ), szXML );
|
|
|
|
if( szXML != "" )
|
|
bSuccess = pDoc->loadXML( _bstr_t( szXML.c_str() ) );
|
|
}
|
|
|
|
if( ! bSuccess )
|
|
{
|
|
CString strMessage;
|
|
strMessage.FormatMessage( IDE_NOXMLDOC, pFirst->XMLFile );
|
|
::AfxMessageBox ( strMessage, MB_ICONERROR );
|
|
|
|
pFirst->build = 0;
|
|
continue;
|
|
}
|
|
|
|
// Read the client version string
|
|
MSXML::IXMLDOMNodePtr pBuildNode = pDoc->selectSingleNode ( _T( "/*/@build" ) );
|
|
if ( pBuildNode == NULL )
|
|
{
|
|
pFirst->build = 0;
|
|
continue;
|
|
}
|
|
|
|
pFirst->build = pBuildNode->GetnodeValue ();
|
|
}
|
|
catch ( _com_error & )
|
|
{
|
|
pFirst->build = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CDenAgentApp::InitInstance()
|
|
{
|
|
HWND hDenAgent = FindWindow(NULL, "Decal Agent");
|
|
|
|
if(hDenAgent)
|
|
{
|
|
::MessageBox(hDenAgent, "Decal is already running!", "Decal", 0);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!CheckForHardwareMode ())
|
|
{
|
|
::MessageBox
|
|
(
|
|
NULL,
|
|
_T("Decal requires Asheron's Call to be installed with hardware 3d acceleration enabled! Decal will run, but will be unable to display any UI in-game."),
|
|
_T("Decal Agent Startup Warning"),
|
|
MB_OK
|
|
);
|
|
}
|
|
|
|
if (!CheckForIE5OrLater ())
|
|
{
|
|
::MessageBox
|
|
(
|
|
NULL,
|
|
"Decal requires Internet Explorer 5.01 or later!",
|
|
"Decal Agent Startup Error",
|
|
MB_OK
|
|
);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (!InitATL())
|
|
return FALSE;
|
|
|
|
|
|
CCommandLineInfo cmdInfo;
|
|
ParseCommandLine(cmdInfo);
|
|
|
|
if (cmdInfo.m_bRunEmbedded || cmdInfo.m_bRunAutomated)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// Set our current directory to the path of DenAgent.exe
|
|
// TODO: Fix all the code so that it doesn't rely on the current directory
|
|
TCHAR szAppPath[MAX_PATH];
|
|
::memset (szAppPath, 0, sizeof (szAppPath));
|
|
::GetModuleFileName (0, szAppPath, MAX_PATH);
|
|
|
|
TCHAR *szLastSlash = ::_tcsrchr (szAppPath, _T('\\'));
|
|
if (szLastSlash)
|
|
{
|
|
*szLastSlash = 0;
|
|
::SetCurrentDirectory (szAppPath);
|
|
}
|
|
|
|
// Move V1 plugins into the V2 registry format
|
|
importV1Plugins ();
|
|
|
|
// Standard initialization
|
|
// If you are not using these features and wish to reduce the size
|
|
// of your final executable, you should remove from the following
|
|
// the specific initialization routines you do not need.
|
|
m_pTrayWnd = new CTrayWnd;
|
|
m_pMainWnd = m_pTrayWnd;
|
|
|
|
m_pTrayWnd->CreateEx( 0, ::AfxRegisterWndClass( 0, NULL, NULL, NULL ), _T( "Decal Agent" ), WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL );
|
|
|
|
checkXMLVersions ( m_pTrayWnd );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
CDenAgentModule _Module;
|
|
|
|
BEGIN_OBJECT_MAP(ObjectMap)
|
|
END_OBJECT_MAP()
|
|
|
|
LONG CDenAgentModule::Unlock()
|
|
{
|
|
AfxOleUnlockApp();
|
|
return 0;
|
|
}
|
|
|
|
LONG CDenAgentModule::Lock()
|
|
{
|
|
AfxOleLockApp();
|
|
return 1;
|
|
}
|
|
LPCTSTR CDenAgentModule::FindOneOf(LPCTSTR p1, LPCTSTR p2)
|
|
{
|
|
while (*p1 != NULL)
|
|
{
|
|
LPCTSTR p = p2;
|
|
while (*p != NULL)
|
|
{
|
|
if (*p1 == *p)
|
|
return CharNext(p1);
|
|
p = CharNext(p);
|
|
}
|
|
p1++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int CDenAgentApp::ExitInstance()
|
|
{
|
|
delete m_pTrayWnd;
|
|
|
|
if (m_bATLInited)
|
|
{
|
|
_Module.RevokeClassObjects();
|
|
_Module.Term();
|
|
CoUninitialize();
|
|
}
|
|
|
|
return CWinApp::ExitInstance();
|
|
|
|
}
|
|
|
|
void CDenAgentApp::importV1Plugins ()
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
RegKey hkGroup;
|
|
if ( hkGroup.Open ( HKEY_LOCAL_MACHINE, _T ( "Software\\Decal\\Plugins" ) ) != ERROR_SUCCESS )
|
|
// No plugins - no problem
|
|
return;
|
|
|
|
DWORD dwValues = 0;
|
|
::RegQueryInfoKey ( hkGroup, NULL, NULL, NULL, NULL, NULL, NULL, &dwValues, NULL, NULL, NULL, NULL );
|
|
|
|
// Now - iterate through the values backwards
|
|
for ( int i = dwValues - 1; i >= 0; -- i )
|
|
{
|
|
TCHAR szCLSID[ 64 ];
|
|
DWORD dwCLSID = sizeof ( szCLSID );
|
|
DWORD dwEnabled;
|
|
DWORD dwEnabledSize = sizeof ( dwEnabled );
|
|
|
|
if ( ::RegEnumValue ( hkGroup, i, szCLSID, &dwCLSID, NULL, NULL, reinterpret_cast< BYTE * > ( &dwEnabled ), &dwEnabledSize ) != ERROR_SUCCESS )
|
|
continue;
|
|
|
|
// Try and convert the name to a CLSID
|
|
CLSID clsidPlugin;
|
|
HRESULT hRes = ::CLSIDFromString ( T2OLE ( szCLSID ), &clsidPlugin );
|
|
if ( FAILED ( hRes ) )
|
|
continue;
|
|
|
|
// Delete the value and ask questions later
|
|
hkGroup.DeleteValue ( szCLSID );
|
|
|
|
// Try and create a key to extract the friendly name
|
|
CComPtr< IPlugin > pPlugin;
|
|
hRes = ::CoCreateInstance ( clsidPlugin, NULL, CLSCTX_INPROC_SERVER, __uuidof ( IPlugin ),
|
|
reinterpret_cast< LPVOID * > ( &pPlugin ) );
|
|
|
|
if ( FAILED ( hRes ) )
|
|
// Bad plugin - skip
|
|
continue;
|
|
|
|
CComBSTR strName;
|
|
pPlugin->get_FriendlyName ( &strName );
|
|
|
|
// Create the Real registry key
|
|
// Key configuration copied from Decal/cActiveXSurrogate::Register
|
|
RegKey hkeyItem;
|
|
if ( hkeyItem.Create ( hkGroup, szCLSID ) != ERROR_SUCCESS )
|
|
continue;
|
|
|
|
// Friendly name
|
|
hkeyItem.SetStringValue( NULL, OLE2T( strName ) );
|
|
// Enabled by default
|
|
hkeyItem.SetDWORDValue( _T( "Enabled" ), dwEnabled );
|
|
// The V1 surrogate
|
|
hkeyItem.SetStringValue( _T( "Surrogate" ), _T( "{3D837F6E-B5CA-4604-885F-7AB45FCFA62A}" ) );
|
|
hkeyItem.Close();
|
|
}
|
|
}
|
|
|
|
BOOL CDenAgentApp::InitATL()
|
|
{
|
|
m_bATLInited = TRUE;
|
|
|
|
HRESULT hRes = CoInitialize(NULL);
|
|
|
|
if (FAILED(hRes))
|
|
{
|
|
m_bATLInited = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
_Module.Init(ObjectMap, AfxGetInstanceHandle());
|
|
_Module.dwThreadID = GetCurrentThreadId();
|
|
|
|
LPTSTR lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
|
|
TCHAR szTokens[] = _T("-/");
|
|
|
|
BOOL bRun = TRUE;
|
|
LPCTSTR lpszToken = _Module.FindOneOf(lpCmdLine, szTokens);
|
|
while (lpszToken != NULL)
|
|
{
|
|
if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
|
|
{
|
|
_Module.UpdateRegistryFromResource(IDR_DENAGENT, FALSE);
|
|
_Module.UnregisterServer(TRUE); //TRUE means typelib is unreg'd
|
|
bRun = FALSE;
|
|
break;
|
|
}
|
|
if (lstrcmpi(lpszToken, _T("RegServer"))==0)
|
|
{
|
|
_Module.UpdateRegistryFromResource(IDR_DENAGENT, TRUE);
|
|
_Module.RegisterServer(TRUE);
|
|
bRun = FALSE;
|
|
break;
|
|
}
|
|
lpszToken = _Module.FindOneOf(lpszToken, szTokens);
|
|
}
|
|
|
|
if (!bRun)
|
|
{
|
|
m_bATLInited = FALSE;
|
|
_Module.Term();
|
|
CoUninitialize();
|
|
return FALSE;
|
|
}
|
|
|
|
hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER,
|
|
REGCLS_MULTIPLEUSE);
|
|
if (FAILED(hRes))
|
|
{
|
|
m_bATLInited = FALSE;
|
|
CoUninitialize();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|