This sample illustrates SftButton creation and configuration from a C++/MFC application. It covers process-wide registration, attaching CSftButton instances to dialog template controls through DDX_Control, configuring buttons through SFTBUTTON_CONTROL, loading and freeing GDI+ images for the Picture1 / Picture2 slots, runtime dark-mode and theme toggles, and routing dark-mode painting through the SftDarkMode helper.
The dialog hosts three SftButton controls and two checkboxes:
The source code is located at C:\Program Files (x86)\Softelvdm\SftButton DLL 3.0\Samples\MFC\Simple\ (or C:\Program Files\Softelvdm\SftButton DLL 3.0\Samples\MFC\Simple\ on 32-bit Windows versions).
The CWinApp-derived class registers the SftButton window class in InitInstance and unregisters it in ExitInstance. SftDarkMode_Init runs alongside so dark-mode painting is available before the main dialog is shown.
/****************************************************************************/ /* SftButton/DLL 3.0 - Button Control for C/C++ */ /* Copyright (C) 2026 Softel vdm, Inc. All Rights Reserved. */ /****************************************************************************/ /* SftButton/DLL 3.0 sample. Guide: https://softelvdm.com/Vault/Softelvdm.com/llms/SftButton-DLL-3.0.txt, API reference: https://softelvdm.com/Vault/Softelvdm.com/llms/SftButton-DLL-3.0-reference.txt - see AGENTS.md. */ #include "stdafx.h" #include "Simple.h" #include "Maindlg.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif BEGIN_MESSAGE_MAP(CSimpleApp, CWinApp) END_MESSAGE_MAP() CSimpleApp::CSimpleApp() { } CSimpleApp NEAR theApp; BOOL CSimpleApp::InitInstance() { SftDarkMode_Init(); // Dark mode support CSftButton::RegisterApp(); // Register with SftButton/DLL CMainDlg dlg; m_pMainWnd = &dlg; dlg.DoModal(); return FALSE; } int CSimpleApp::ExitInstance() { CSftButton::UnregisterApp(); // Unregister from SftButton/DLL return CWinApp::ExitInstance(); }
CMainDlg embeds three CSftButton members - one per dialog control - and two LPVOID slots for the GDI+ images that Button 2 displays. DDX_Control attaches the embedded CSftButton instances to the dialog-template controls in DoDataExchange.
/****************************************************************************/
/* SftButton/DLL 3.0 - Button Control for C/C++ */
/* Copyright (C) 2026 Softel vdm, Inc. All Rights Reserved. */
/****************************************************************************/
class CMainDlg : public CDialog
{
public:
CMainDlg(CWnd* pParent = NULL);
enum { IDD = IDD_MAIN };
CSftButton m_Button1;
CSftButton m_Button2;
CSftButton m_Button3;
LPVOID m_pImg1; // GDI+ image for Button2 Picture1
LPVOID m_pImg2; // GDI+ image for Button2 Picture2
protected:
virtual void DoDataExchange(CDataExchange* pDX);
virtual BOOL OnInitDialog();
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
afx_msg void OnButton1();
afx_msg void OnButton2();
afx_msg void OnButton3();
afx_msg void OnButton3DropDown();
afx_msg void OnUseThemes();
afx_msg void OnDarkMode();
afx_msg void OnDestroy();
afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection);
DECLARE_MESSAGE_MAP()
};OnInitDialog configures each button through GetControlInfo / SetControlInfo, loads the GDI+ images for Button 2, and applies dark mode to the dialog itself with SftDarkMode_ApplyToDialog. ON_BN_CLICKED and ON_CONTROL entries in the message map dispatch click and drop-down notifications. OnDestroy frees the GDI+ images with SftButton_FreeGDIPlusImageLoadedFromFile after the controls have stopped using them. WindowProc forwards messages to SftDarkMode_HandleDialogMessage so the dialog repaints correctly under dark mode. OnSettingChange forwards WM_SETTINGCHANGE / ImmersiveColorSet to each button so AUTO-mode buttons re-render when the user flips the Windows "Choose your mode" setting at runtime.
/****************************************************************************/
/* SftButton/DLL 3.0 - Button Control for C/C++ */
/* Copyright (C) 2026 Softel vdm, Inc. All Rights Reserved. */
/****************************************************************************/
#include "stdafx.h"
#include "Simple.h"
#include "Maindlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMainDlg::IDD, pParent)
, m_pImg1(NULL)
, m_pImg2(NULL)
{
}
void CMainDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_SFTBUTTON1, m_Button1);
DDX_Control(pDX, IDC_SFTBUTTON2, m_Button2);
DDX_Control(pDX, IDC_SFTBUTTON3, m_Button3);
}
BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
ON_BN_CLICKED(IDC_SFTBUTTON1, OnButton1)
ON_BN_CLICKED(IDC_SFTBUTTON2, OnButton2)
ON_BN_CLICKED(IDC_SFTBUTTON3, OnButton3)
ON_CONTROL(SFTBUTTONN_DROPDOWNCLICK, IDC_SFTBUTTON3, OnButton3DropDown)
ON_BN_CLICKED(IDC_USE_THEMES, OnUseThemes)
ON_BN_CLICKED(IDC_DARK_MODE, OnDarkMode)
ON_WM_DESTROY()
ON_WM_SETTINGCHANGE()
END_MESSAGE_MAP()
BOOL CMainDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set dialog icon
HICON hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
SetIcon(hIcon, TRUE);
SetIcon(hIcon, FALSE);
// Apply dark mode to dialog
SftDarkMode_ApplyToDialog(m_hWnd);
// Configure SftButton control 1
{
SFTBUTTON_CONTROL Ctl;
Ctl.cbSize = sizeof(SFTBUTTON_CONTROL);
m_Button1.GetControlInfo(&Ctl);
Ctl.nDarkMode = SFTBUTTON_DARKMODE_AUTO;/* automatic dark mode support */
m_Button1.SetControlInfo(&Ctl);
}
// Configure SftButton control 2
{
SFTBUTTON_CONTROL Ctl;
Ctl.cbSize = sizeof(SFTBUTTON_CONTROL);
m_Button2.GetControlInfo(&Ctl);
Ctl.nDarkMode = SFTBUTTON_DARKMODE_AUTO;/* automatic dark mode support */
Ctl.Text.align = SFT_PICALIGN_LEFT;/* text horizontal alignment */
m_pImg1 = SftButton_LoadGDIPlusImageFromFile(_T("Res\\pic_world_48.png"));
if (m_pImg1) Sft_SetPictureGDIPlusImage(&Ctl.Picture1, m_pImg1);
Ctl.Picture1.align = SFT_PICALIGN_CENTER;
Ctl.Picture1.valign = SFT_PICALIGN_VCENTER;
m_pImg2 = SftButton_LoadGDIPlusImageFromFile(_T("Res\\pic_go_32.png"));
if (m_pImg2) Sft_SetPictureGDIPlusImage(&Ctl.Picture2, m_pImg2);
Ctl.Picture2.align = SFT_PICALIGN_LEFT;
Ctl.Picture2.valign = SFT_PICALIGN_VCENTER;
m_Button2.SetControlInfo(&Ctl);
}
// Configure SftButton control 3
{
SFTBUTTON_CONTROL Ctl;
Ctl.cbSize = sizeof(SFTBUTTON_CONTROL);
m_Button3.GetControlInfo(&Ctl);
Ctl.fShowDropDown = TRUE;/* show drop-down arrow */
Ctl.nDarkMode = SFTBUTTON_DARKMODE_AUTO;/* automatic dark mode support */
m_Button3.SetControlInfo(&Ctl);
}
CheckDlgButton(IDC_USE_THEMES, BST_CHECKED);
CheckDlgButton(IDC_DARK_MODE, SftDarkMode_IsActive() ? BST_CHECKED : BST_UNCHECKED);
return TRUE;
}
void CMainDlg::OnButton1()
{
AfxMessageBox(_T("Button 1 clicked!"));
}
void CMainDlg::OnButton2()
{
AfxMessageBox(_T("Button 2 clicked!"));
}
void CMainDlg::OnButton3()
{
AfxMessageBox(_T("Button 3 clicked!"));
}
void CMainDlg::OnButton3DropDown()
{
AfxMessageBox(_T("Button 3 drop-down clicked!"));
}
void CMainDlg::OnUseThemes()
{
int useThemes = (IsDlgButtonChecked(IDC_USE_THEMES) == BST_CHECKED)
? SFTBUTTON_THEME_YES : SFTBUTTON_THEME_NO;
CSftButton* btns[] = { &m_Button1, &m_Button2, &m_Button3 };
for (int i = 0; i < (int)(sizeof(btns) / sizeof(btns[0])); ++i) {
SFTBUTTON_CONTROL Ctl;
Ctl.cbSize = sizeof(SFTBUTTON_CONTROL);
btns[i]->GetControlInfo(&Ctl);
Ctl.nUseThemes = useThemes;
btns[i]->SetControlInfo(&Ctl);
}
}
void CMainDlg::OnDarkMode()
{
BOOL fDark = (IsDlgButtonChecked(IDC_DARK_MODE) == BST_CHECKED);
int btnMode = fDark ? SFTBUTTON_DARKMODE_ON : SFTBUTTON_DARKMODE_OFF;
m_Button1.SetDarkMode(btnMode);
m_Button2.SetDarkMode(btnMode);
m_Button3.SetDarkMode(btnMode);
SftDarkMode_SetActive(fDark);
SftDarkMode_ApplyToDialog(m_hWnd);
InvalidateRect(NULL, TRUE);
}
void CMainDlg::OnDestroy()
{
// Free GDI+ images now that the controls no longer reference them.
if (m_pImg1) { SftButton_FreeGDIPlusImageLoadedFromFile(m_pImg1); m_pImg1 = NULL; }
if (m_pImg2) { SftButton_FreeGDIPlusImageLoadedFromFile(m_pImg2); m_pImg2 = NULL; }
CDialog::OnDestroy();
}
LRESULT CMainDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// Route through SftDarkMode first so it can handle WM_CTLCOLOR*, WM_ERASEBKGND, etc.
INT_PTR dmResult;
if (SftDarkMode_HandleDialogMessage(m_hWnd, message, wParam, lParam, &dmResult))
return dmResult;
return CDialog::WindowProc(message, wParam, lParam);
}
void CMainDlg::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
CDialog::OnSettingChange(uFlags, lpszSection);
// Forward to the SftButton controls so they can update (AUTO mode)
if (lpszSection && lstrcmpW((LPCWSTR)lpszSection, L"ImmersiveColorSet") == 0) {
SftDarkMode_Init();
SftDarkMode_ApplyToDialog(m_hWnd);
m_Button1.SendMessage(WM_SETTINGCHANGE, uFlags, (LPARAM)lpszSection);
m_Button2.SendMessage(WM_SETTINGCHANGE, uFlags, (LPARAM)lpszSection);
m_Button3.SendMessage(WM_SETTINGCHANGE, uFlags, (LPARAM)lpszSection);
InvalidateRect(NULL, TRUE);
}
}See Also Using C++/MFC | MFC and Notifications | Dark Mode | GDI+