openDecal/Native/DenAgent/OptionsDlg.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

553 lines
No EOL
16 KiB
C++

// OptionsDlg.cpp : implementation file
//
#include "stdafx.h"
#include "DenAgent.h"
#include "OptionsDlg.h"
#include "ChangePluginDirectory.h"
#include <strstream>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// cOptionsDlg dialog
cOptionsDlg::cOptionsDlg(CWnd* pParent /*=NULL*/)
: CDialog(cOptionsDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(cOptionsDlg)
m_nBarAlpha = 0;
m_nViewAlpha = 0;
m_nFontChoice = 0;
m_szCustomFont = _T("");
//}}AFX_DATA_INIT
// Default Decal and AC Client Font
m_szDefaultFont = "Times New Roman";
m_szACClientFont = "Times New Roman";
}
void cOptionsDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(cOptionsDlg)
DDX_Control(pDX, IDC_CUSTOM_FONT_EDIT, m_CustomFontEdit);
DDX_Control(pDX, IDC_VIEWALPHA_SPIN, m_ViewAlphaSpin);
DDX_Control(pDX, IDC_BARALPHA_SPIN, m_BarAlphaSpin);
DDX_Control(pDX, IDC_BARALPHA, m_BarAlpha);
DDX_Control(pDX, IDC_VIEWALPHA, m_ViewAlpha);
DDX_Control(pDX, IDC_PLUGINDIR, m_Url);
DDX_Text(pDX, IDC_BARALPHA, m_nBarAlpha);
DDV_MinMaxInt(pDX, m_nBarAlpha, 0, 255);
DDX_Text(pDX, IDC_VIEWALPHA, m_nViewAlpha);
DDV_MinMaxInt(pDX, m_nViewAlpha, 0, 255);
DDX_Radio(pDX, IDC_DEFAULT_FONT_RADIO, m_nFontChoice);
DDX_Text(pDX, IDC_CUSTOM_FONT_EDIT, m_szCustomFont);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(cOptionsDlg, CDialog)
//{{AFX_MSG_MAP(cOptionsDlg)
ON_BN_CLICKED(IDC_CHANGE_DIR, OnChangeDir)
ON_BN_CLICKED(IDC_BTN_RESET, OnReset)
ON_BN_CLICKED(IDC_DEFAULT_FONT_RADIO, OnDefaultFontRadio)
ON_BN_CLICKED(IDC_CLIENT_FONT_RADIO, OnClientFontRadio)
ON_BN_CLICKED(IDC_CUSTOM_FONT_RADIO, OnCustomFontRadio)
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_OLDINJECT, OnBnClickedOldInject)
ON_BN_CLICKED(IDC_TIMESTAMPON, OnBnClickedTimestampon)
ON_BN_CLICKED(IDC_FORMATHELP, OnBnClickedFormathelp)
ON_BN_CLICKED(IDC_PATCHHELP, OnBnClickedPatchHelp)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// cOptionsDlg message handlers
BOOL cOptionsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_bClientPatchesEnabled = true;
// TODO: Add extra initialization here
RegKey key;
if( key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal" )) != ERROR_SUCCESS )
return TRUE;
// Force spin ranges
m_ViewAlphaSpin.SetRange(0, 255);
m_BarAlphaSpin.SetRange(0, 255);
DWORD alpha;
if(key.QueryDWORDValue("BarAlpha", alpha)==ERROR_SUCCESS)
{
m_nBarAlpha = alpha;
//CString csa;
//csa.Format("%d", alpha);
//m_BarAlpha.SetWindowText(csa);
}
else
m_nBarAlpha = 255;
//m_BarAlpha.SetWindowText("255");
if(key.QueryDWORDValue("ViewAlpha", alpha)==ERROR_SUCCESS)
{
m_nViewAlpha = alpha;
//CString csa;
//csa.Format("%d", alpha);
//m_ViewAlpha.SetWindowText(csa);
}
else
m_nViewAlpha = 255;
//m_ViewAlpha.SetWindowText("255");
DWORD dwRadarDraw = 1;
key.QueryDWORDValue( "BarRadarDraw", dwRadarDraw );
//::SendMessage( GetDlgItem( IDC_RADARNO )->m_hWnd, BM_SETCHECK, !dwRadarDraw, 0 );
::SendMessage( GetDlgItem( IDC_RADARYES )->m_hWnd, BM_SETCHECK, !dwRadarDraw, 0 );
DWORD dwTimestamp = 0;
key.QueryDWORDValue( "Timestamp", dwTimestamp );
//::SendMessage( GetDlgItem( IDC_TIMESTAMPOFF )->m_hWnd, BM_SETCHECK, !dwTimestamp, 0 );
::SendMessage( GetDlgItem( IDC_TIMESTAMPON )->m_hWnd, BM_SETCHECK, dwTimestamp, 0 );
//setup timestamp options
::SendMessage( GetDlgItem( IDC_FORMATSTR )->m_hWnd, EM_SETLIMITTEXT, MAX_PATH - 1, 0 );
::EnableWindow( GetDlgItem( IDC_FORMATSTR )->m_hWnd, dwTimestamp );
::EnableWindow( GetDlgItem( IDC_FORMATCLR )->m_hWnd, dwTimestamp );
DWORD dwTSColor = 12;
key.QueryDWORDValue( "TimestampColor", dwTSColor );
::SendMessage( GetDlgItem( IDC_FORMATCLR )->m_hWnd, CB_SETCURSEL, ++dwTSColor, 0 );
DWORD dwDockPos = 0;
key.QueryDWORDValue( "BarDock", dwDockPos );
::SendMessage( GetDlgItem( IDC_DOCKPOS )->m_hWnd, CB_SETCURSEL, dwDockPos, 0 );
char szFormat[MAX_PATH];
DWORD dwFormatLen = MAX_PATH;
if( key.QueryStringValue( "TimestampFormat", szFormat, &dwFormatLen ) != ERROR_SUCCESS ) //just thieved from achooks
memset( szFormat, 0, sizeof(szFormat) ), strncpy( szFormat, "[%H:%M]", sizeof( szFormat ) );
::SendMessage( GetDlgItem( IDC_FORMATSTR )->m_hWnd, WM_SETTEXT, 0, (LPARAM)szFormat );
// Get font type
DWORD dwFontType;
if (key.QueryDWORDValue("FontType", dwFontType) == ERROR_SUCCESS)
{
m_nFontChoice = (int) dwFontType;
}
// Get the custom font name (might not be enabled)
TCHAR szFontName[512];
DWORD dwCount = 512;
if (key.QueryStringValue("FontName", szFontName, &dwCount) == ERROR_SUCCESS)
{
m_szCustomFont = szFontName;
}
DWORD dwAlphaBlendMode;
// para - dialog clean up
if(key.QueryDWORDValue("AlphaBlendMode", dwAlphaBlendMode)==ERROR_SUCCESS)
if(dwAlphaBlendMode==0x2)
::SendMessage(GetDlgItem(IDC_BLENDINGGDIPLUS)->m_hWnd, BM_SETCHECK, 1, 0);
DWORD dwViewMode;
// para - dialog clean up
if( key.QueryDWORDValue( "ViewMode", dwViewMode )== ERROR_SUCCESS )
if( dwViewMode == 1 )
::SendMessage( GetDlgItem( IDC_VIEWMULTI )->m_hWnd, BM_SETCHECK, 1, 0 );
if( key.QueryDWORDValue( "AllowWindowed", dwViewMode )== ERROR_SUCCESS )
if( dwViewMode == 1 )
{
::SendMessage( GetDlgItem( IDC_WINDOWED )->m_hWnd, BM_SETCHECK, 1, 0 );
}
if( key.QueryDWORDValue( "AllowDualLog", dwViewMode )== ERROR_SUCCESS )
if( dwViewMode == 1 )
{
::SendMessage( GetDlgItem( IDC_DUALLOG )->m_hWnd, BM_SETCHECK, 1, 0 );
}
if( key.QueryDWORDValue( "NoMovies", dwViewMode )== ERROR_SUCCESS )
if( dwViewMode == 1 )
{
::SendMessage( GetDlgItem( IDC_NOMOVIES )->m_hWnd, BM_SETCHECK, 1, 0 );
}
if( key.QueryDWORDValue( "NoSplash", dwViewMode )== ERROR_SUCCESS )
if( dwViewMode == 1 )
{
::SendMessage( GetDlgItem( IDC_NOLOGOS )->m_hWnd, BM_SETCHECK, 1, 0 );
}
if( key.QueryDWORDValue( "OldInjection", dwViewMode )== ERROR_SUCCESS )
if( dwViewMode == 1 )
{
::SendMessage( GetDlgItem( IDC_OLDINJECT )->m_hWnd, BM_SETCHECK, 1, 0 );
m_bClientPatchesEnabled = true;
::EnableWindow( GetDlgItem( IDC_WINDOWED )->m_hWnd, FALSE );
::EnableWindow( GetDlgItem( IDC_DUALLOG )->m_hWnd, FALSE );
}
key.Close();
if( key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal\\Agent" )) != ERROR_SUCCESS )
return TRUE;
TCHAR szURLDirectory[ 1024 ];
DWORD dwSize = 1024;
if(key.QueryStringValue( _T( "DecalDirectory" ), szURLDirectory, &dwSize )==ERROR_SUCCESS)
m_Url.SetWindowText(szURLDirectory);
else
{
key.SetStringValue("DecalDirectory", "http://decal.acdev.org");
m_Url.SetWindowText("http://decal.acdev.org");
}
RegKey k;
k.Create(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"));
TCHAR szPath[ MAX_PATH ];
DWORD dwPathSize = MAX_PATH;
if (k.QueryStringValue("Decal", szPath, &dwPathSize) == ERROR_SUCCESS) {
::SendMessage(GetDlgItem(IDC_CHECK_AUTOSTART)->m_hWnd, BM_SETCHECK, 1, 0);
}
k.Close();
// Get the AC Client font
k.Create(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00"));
dwCount = 512;
if (k.QueryStringValue("Font", szFontName, &dwCount) == ERROR_SUCCESS)
{
m_szACClientFont = szFontName;
}
k.Close();
UpdateData(FALSE);
UpdateCustomEdit();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void cOptionsDlg::OnOK()
{
UpdateData(TRUE);
RegKey key;
key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal" ) );
CString csa;
m_BarAlpha.GetWindowText(csa);
DWORD alpha = atoi(csa);
if((alpha<0) || (alpha>255))
alpha = 255;
key.SetDWORDValue("BarAlpha", alpha);
m_ViewAlpha.GetWindowText(csa);
alpha = atoi(csa);
if((alpha<0) || (alpha>255))
alpha = 255;
key.SetDWORDValue("ViewAlpha", alpha);
DWORD dwRadarDraw = 1;
key.QueryDWORDValue( "BarRadarDraw", dwRadarDraw );
if( ::SendMessage( GetDlgItem( IDC_RADARYES )->m_hWnd, BM_GETCHECK, 0, 0 ) )
{
key.SetDWORDValue( "BarRadarDraw", (DWORD)0 );
// Drakier: No longer need BarDelta
//if( dwRadarDraw )
//key.SetDWORDValue( "BarDelta", (DWORD)0 );
}
else
{
key.SetDWORDValue( "BarRadarDraw", (DWORD)1 );
// Drakier: No longer need BarDelta
//if( !dwRadarDraw )
//key.SetDWORDValue( "BarDelta", (DWORD)0 );
}
DWORD dwTimestamp = 1;
key.QueryDWORDValue( "Timestamp", dwTimestamp );
if( ::SendMessage( GetDlgItem( IDC_TIMESTAMPON )->m_hWnd, BM_GETCHECK, 0, 0 ) )
key.SetDWORDValue( "Timestamp", (DWORD)1 );
else
key.SetDWORDValue( "Timestamp", (DWORD)0 );
DWORD dwColor = ::SendMessage(GetDlgItem(IDC_FORMATCLR)->m_hWnd, CB_GETCURSEL, 0, 0);
key.SetDWORDValue( "TimestampColor", --dwColor );
DWORD dwDockPos = ::SendMessage(GetDlgItem(IDC_DOCKPOS)->m_hWnd, CB_GETCURSEL, 0, 0);
key.SetDWORDValue( "BarDock", dwDockPos);
char szFormat[MAX_PATH];
::SendMessage( GetDlgItem(IDC_FORMATSTR)->m_hWnd, WM_GETTEXT, MAX_PATH, (LPARAM)szFormat);
key.SetStringValue( "TimestampFormat", szFormat );
if(::SendMessage(GetDlgItem(IDC_BLENDINGGDIPLUS)->m_hWnd, BM_GETCHECK, 0, 0))
key.SetDWORDValue("AlphaBlendMode", 0x2L);
else
key.SetDWORDValue("AlphaBlendMode", 0x1L);
bool bMessage = false;
DWORD dwViewMode = 0;
if( ::SendMessage( GetDlgItem( IDC_WINDOWED )->m_hWnd, BM_GETCHECK, 0, 0 ) )
{
// enabled, but old inject is on
if( ! m_bClientPatchesEnabled )
MessageBox( "One drawback of the old injection method is that Decal is not loaded before Asheron's Call.\nThis means any client patches will not work.", "Decal Agent", MB_OK ), bMessage = true;
key.SetDWORDValue( "AllowWindowed", 0x1L );
}
else
key.SetDWORDValue( "AllowWindowed", 0x0L );
if( ::SendMessage( GetDlgItem( IDC_DUALLOG )->m_hWnd, BM_GETCHECK, 0, 0 ) )
{
// enabled, but old inject is on
if( ! m_bClientPatchesEnabled )
if( ! bMessage )
MessageBox( "One drawback of the old injection method is that Decal is not loaded before Asheron's Call.\nThis means any client patches will not work.", "Decal Agent", MB_OK ), bMessage = true;
key.SetDWORDValue( "AllowDualLog", 0x1L );
}
else
key.SetDWORDValue( "AllowDualLog", 0x0L );
if( ::SendMessage( GetDlgItem( IDC_NOLOGOS )->m_hWnd, BM_GETCHECK, 0, 0 ) )
{
// enabled, but old inject is on
if( ! m_bClientPatchesEnabled )
if( ! bMessage )
MessageBox( "One drawback of the old injection method is that Decal is not loaded before Asheron's Call.\nThis means any client patches will not work.", "Decal Agent", MB_OK ), bMessage = true;
key.SetDWORDValue( "NoMovies", 0x1L );
}
else
key.SetDWORDValue( "NoMovies", 0x0L );
if( ::SendMessage( GetDlgItem( IDC_NOLOGOS )->m_hWnd, BM_GETCHECK, 0, 0 ) )
{
// enabled, but old inject is on
if( ! m_bClientPatchesEnabled )
if( ! bMessage )
MessageBox( "One drawback of the old injection method is that Decal is not loaded before Asheron's Call.\nThis means any client patches will not work.", "Decal Agent", MB_OK ), bMessage = true;
key.SetDWORDValue( "NoSplash", 0x1L );
}
else
key.SetDWORDValue( "NoSplash", 0x0L );
// cbt hook injection
if( ::SendMessage(GetDlgItem(IDC_OLDINJECT)->m_hWnd, BM_GETCHECK, 0, 0) )
{
if( key.QueryDWORDValue( "OldInjection", dwViewMode ) == ERROR_SUCCESS )
{
if( dwViewMode != 1 )
{
key.SetDWORDValue("OldInjection", 0x1L);
MessageBox( "You must restart DenAgent for injection method changes to take effect!", "DenAgent", MB_OK );
}
}
else
{
key.SetDWORDValue("OldInjection", 0x1L);
MessageBox( "You must restart DenAgent for injection method changes to take effect!", "DenAgent", MB_OK );
}
}
else
{
if( key.QueryDWORDValue( "OldInjection", dwViewMode ) == ERROR_SUCCESS )
if( dwViewMode != 0 )
{
key.SetDWORDValue("OldInjection", 0x0L);
MessageBox( "You must restart DenAgent for injection method changes to take effect!", "DenAgent", MB_OK );
}
}
// para - dropped viewsingle, switched around
if( ::SendMessage( GetDlgItem( IDC_VIEWMULTI )->m_hWnd, BM_GETCHECK, 0, 0 ) )
key.SetDWORDValue( "ViewMode", (DWORD) 1L );
else
key.SetDWORDValue( "ViewMode", 0L );
// Set the font info
key.SetDWORDValue("FontType", (DWORD)m_nFontChoice);
key.SetStringValue("FontName", (LPCTSTR)m_szCustomFont);
key.Close();
// Auto-Start on Bootup
RegKey k;
k.Create(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"));
if (::SendMessage(GetDlgItem(IDC_CHECK_AUTOSTART)->m_hWnd, BM_GETCHECK, 0, 0)) {
std::string szCmdLine = GetCommandLine();
if (szCmdLine[0] == '\"' && szCmdLine[szCmdLine.length() - 2] == '\"') {
szCmdLine.erase((int)0, 1); // STL is odd
szCmdLine.erase(szCmdLine.length() - 2, 1);
}
k.SetStringValue("Decal", szCmdLine.data());
}
else {
k.DeleteValue("Decal");
}
k.Close();
CDialog::OnOK();
}
void cOptionsDlg::OnChangeDir()
{
// TODO: Add your control notification handler code here
cChangePluginDirectory cpddlg(this);
if(cpddlg.DoModal() == IDOK )
{
RegKey keyAgent;
if( keyAgent.Open( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal\\Agent" ), KEY_READ ) == ERROR_SUCCESS )
{
TCHAR szURLDirectory[ 1024 ];
DWORD dwSize = 1024;
keyAgent.QueryStringValue( _T( "DecalDirectory" ), szURLDirectory, &dwSize );
m_Url.SetWindowText(szURLDirectory);
}
}
}
void cOptionsDlg::OnReset()
{
RegKey key;
if( key.Create( HKEY_LOCAL_MACHINE, "Software\\Decal", REG_NONE, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS ) != ERROR_SUCCESS )
return;
//key.DeleteValue( _T( "BarDelta" ) );
// Drakier: New Bar stuff
key.DeleteValue( _T( "BarLength" ) );
key.DeleteValue( _T( "BarStart" ) );
::AfxMessageBox( _T( "The Decal bar's position has been reset." ), MB_ICONINFORMATION | MB_OK, 0 );
}
void cOptionsDlg::UpdateCustomEdit(void)
{
UpdateData(TRUE);
// Enable for editing only for custom font only
m_CustomFontEdit.SetReadOnly(m_nFontChoice != 2);
// Update the font name as needed
switch (m_nFontChoice)
{
case 0: // Default Font
{
m_szCustomFont = m_szDefaultFont;
}
break;
case 1: // Current AC Client Font
{
m_szCustomFont = m_szACClientFont;
}
break;
}
UpdateData(FALSE);
}
void cOptionsDlg::OnDefaultFontRadio()
{
UpdateCustomEdit();
}
void cOptionsDlg::OnClientFontRadio()
{
UpdateCustomEdit();
}
void cOptionsDlg::OnCustomFontRadio()
{
UpdateCustomEdit();
}
void cOptionsDlg::OnBnClickedOldInject()
{
if( ::SendMessage( GetDlgItem( IDC_OLDINJECT )->m_hWnd, BM_GETCHECK, 0, 0 ) )
{
::EnableWindow( GetDlgItem( IDC_WINDOWED )->m_hWnd, FALSE );
::EnableWindow( GetDlgItem( IDC_DUALLOG )->m_hWnd, FALSE );
::EnableWindow( GetDlgItem( IDC_NOMOVIES )->m_hWnd, FALSE );
::EnableWindow( GetDlgItem( IDC_NOLOGOS )->m_hWnd, FALSE );
m_bClientPatchesEnabled = false;
}
else
{
::EnableWindow( GetDlgItem( IDC_WINDOWED )->m_hWnd, TRUE );
::EnableWindow( GetDlgItem( IDC_DUALLOG )->m_hWnd, TRUE );
::EnableWindow( GetDlgItem( IDC_NOMOVIES )->m_hWnd, TRUE );
::EnableWindow( GetDlgItem( IDC_NOLOGOS )->m_hWnd, TRUE );
m_bClientPatchesEnabled = true;
}
}
void cOptionsDlg::OnBnClickedTimestampon()
{
//we need to activate the options when this is enabled
if( ::SendMessage( GetDlgItem( IDC_TIMESTAMPON )->m_hWnd, BM_GETCHECK, 0, 0 ) )
{
::EnableWindow( GetDlgItem( IDC_FORMATSTR )->m_hWnd, true );
::EnableWindow( GetDlgItem( IDC_FORMATCLR )->m_hWnd, true );
}
else
{
::EnableWindow( GetDlgItem( IDC_FORMATSTR )->m_hWnd, false );
::EnableWindow( GetDlgItem( IDC_FORMATCLR )->m_hWnd, false );
}
}
void cOptionsDlg::OnBnClickedFormathelp()
{
//open up ie and point at.... <Heyus> TimestampFormat.htm
ShellExecute(m_hWnd, _T("open"), _T("http://decal.acdev.org/TimestampFormat.htm"), 0, 0, 0);
}
void cOptionsDlg::OnBnClickedPatchHelp()
{
ShellExecute(m_hWnd, _T("open"), _T("http://decal.acdev.org/clientpatchinfo.html"), 0, 0, 0);
}