vs2019 - 用自定义对话框消息框替代MessageBox

文章目录

    • vs2019 - 用自定义对话框消息框替代MessageBox
    • 概述
    • 笔记
    • 效果
    • 用法
    • 调用方代码
    • 实现
    • MessageBoxDialog.h
    • MessageBoxDialog.cpp
    • END

vs2019 - 用自定义对话框消息框替代MessageBox

概述

当工程被逆向时,如果存在AfxMessageBox(), ::MessageBox()的调用,是一个明显的线索。
想用自定义对话框消息替代MessageBox()的API.

在codeproject上,看到前辈同学已经写好了一个实现(Enhanced MFC Message Boxes)。

用起来发现:

  • 这个实现的功能对于我的应用来说,功能太多了。
  • 将这个实现加入现有工程时,要在工程RC中添加的东西有点多。

做了一个剪裁版,插入一个新工程时,方便很多。

笔记

效果

在这里插入图片描述

用法

在工程RC中插入一个在类中定义的对话框ID

在RC的Dialog节点插入默认的对话框资源,然后将默认的2个按钮删掉即可。
在这里插入图片描述

MessageBoxDialog.h

 // 必须在RC中定义一个空的对话框资源
#define RC_DLG_ID_CMessageBoxDialog IDD_MY_MESSAGE_BOX

将插入的对框框资源的ID改为自己定义的名字(e.g. IDD_MY_MESSAGE_BOX)
在这里插入图片描述
在工程中插入MessageBoxDialog实现,定义好C++包含路径
在这里插入图片描述

调用方代码

void CDlgMessageBoxV1Dlg::OnBnClickedButton1()
{UINT nStyle = MB_OK | MB_ICONINFORMATION /* | MB_DEFBUTTON1*/;int nResult = 0;CString m_strTitle = TEXT("标题");CString m_strMessage = TEXT("消息");BOOL m_bTimeout = FALSE;UINT m_nTimeout = 0;BOOL m_bDisabledTimeout = FALSE;// Create a message box dialog.CMessageBoxDialog dlgMessageBox(this, m_strMessage, m_strTitle, nStyle);// Check whether a timeout was choosen.if (m_bTimeout){// Set the timeout for the message box.dlgMessageBox.SetTimeout(m_nTimeout, m_bDisabledTimeout);}// Display the dialog.nResult = (int)dlgMessageBox.DoModal();TRACE(TEXT("nResult = %d\n"), nResult);
}

实现

MessageBoxDialog.h

/**	Extended MFC message boxes -- Version 1.1a*	Copyright (c) 2004 Michael P. Mehl. All rights reserved.**	The contents of this file are subject to the Mozilla Public License*	Version 1.1a (the "License"); you may not use this file except in*	compliance with the License. You may obtain a copy of the License at *	http://www.mozilla.org/MPL/.**	Software distributed under the License is distributed on an "AS IS" basis,*	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License*	for the specific language governing rights and limitations under the*	License. **	The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights*	reserved. The Initial Developer of the Original Code is Michael P. Mehl*	<michael.mehl@web.de>.**	Alternatively, the contents of this file may be used under the terms of*	the GNU Lesser General Public License Version 2.1 (the "LGPL License"),*	in which case the provisions of LGPL License are applicable instead of*	those above. If you wish to allow use of your version of this file only*	under the terms of the LGPL License and not to allow others to use your*	version of this file under the MPL, indicate your decision by deleting*	the provisions above and replace them with the notice and other provisions*	required by the LGPL License. If you do not delete the provisions above,*	a recipient may use your version of this file under either the MPL or*	the LGPL License.*/#pragma once#include "Resource.h" // for CMessageBoxDialog rc defined// 必须在RC中定义一个空的对话框资源
#define RC_DLG_ID_CMessageBoxDialog IDD_MY_MESSAGE_BOX// 自己手工在.rc中添加空的对话框代码
/*
IDD_MESSAGE_BOX DIALOGEX 0, 0, 186, 95
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
END
*/// 自己手工在resource.h中添加ID定义
// #define IDD_MESSAGE_BOX                 103//
// Message box style definitions (mostly taken from WinUser.h).#define IDS_MESSAGEBOX_OK               9001
#define IDS_MESSAGEBOX_CANCEL           9002
#define IDS_MESSAGEBOX_ABORT            9003
#define IDS_MESSAGEBOX_RETRY            9004
#define IDS_MESSAGEBOX_IGNORE           9005
#define IDS_MESSAGEBOX_IGNOREALL        9006
#define IDS_MESSAGEBOX_YES              9007
#define IDS_MESSAGEBOX_YES_TO_ALL       9008
#define IDS_MESSAGEBOX_NO               9009
#define IDS_MESSAGEBOX_NO_TO_ALL        9010
#define IDS_MESSAGEBOX_CONTINUE         9011
#define IDS_MESSAGEBOX_SKIP             9012
#define IDS_MESSAGEBOX_SKIPALL          9013
#define IDS_MESSAGEBOX_HELP             9014
//#define IDS_MESSAGEBOX_DONT_DISPLAY_AGAIN 9015
//#define IDS_MESSAGEBOX_DONT_ASK_AGAIN   9016#ifndef MB_CANCELTRYCONTINUE
#define MB_CANCELTRYCONTINUE		0x00000006L	// Standard for Win 5.x.
#endif#define MB_CONTINUEABORT			0x00000007L	// Additional style.
#define MB_SKIPSKIPALLCANCEL		0x00000008L	// Additional style.
#define MB_IGNOREIGNOREALLCANCEL	0x00000009L	// Additional style.#define MB_DONT_DISPLAY_AGAIN		0x01000000L	// Additional style.
#define MB_DONT_ASK_AGAIN			0x02000000L	// Additional style.
#define MB_DEFAULT_CHECKED			0x03000000L	// Additional style.
#define MB_YES_TO_ALL				0x04000000L	// Additional style.
#define MB_NO_TO_ALL				0x08000000L	// Additional style.#define MB_RIGHT_ALIGN				0x10000000L	// Additional style.
#define MB_NO_SOUND					0x20000000L	// Additional style.#define MB_DEFBUTTON5				0x00000400L	// Additional style.
#define MB_DEFBUTTON6				0x00000500L	// Additional style.//
// Dialog element IDs.#ifndef IDTRYAGAIN
#define IDTRYAGAIN					10			// Standard for Win 5.x.
#endif#ifndef IDCONTINUE
#define IDCONTINUE					11			// Standard for Win 5.x.
#endif#define IDYESTOALL					14			// Additional element.
#define IDNOTOALL					15			// Additional element.
#define IDSKIP						16			// Additional element.
#define IDSKIPALL					17			// Additional element.
#define IDIGNOREALL					18			// Additional element.
#define IDCHECKBOX					19			// Additional element.//
// Name of the registry section for storing the message box results.// #define REGISTRY_SECTION_MESSAGEBOX	_T("MessageBoxes")//
// Class definition.class CMessageBoxDialog : public CDialog
{// DECLARE_DYNAMIC(CMessageBoxDialog)
public:CString LoadString(UINT nID);public://// Constructors and destructors of the class.// Constructor of the class for direct providing of the message strings.CMessageBoxDialog ( CWnd* pParent, CString strMessage, CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0 );// Constructor of the class for loading the strings from the resources.CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, UINT nTitleID = 0,UINT nStyle = MB_OK, UINT nHelp = 0 );// Default destructor of the class.virtual ~CMessageBoxDialog ( );enum { IDD = RC_DLG_ID_CMessageBoxDialog};public://// Methods for setting and retrieving dialog options.// Method for setting the style of the message box.void SetStyle ( UINT nStyle );// Method for retrieving the style of the message box.UINT GetStyle ( );// Methods for setting the message to be displayed in the message box.void SetMessage ( CString strMessage );void SetMessage ( UINT nMessageID );// Method for retrieving the message to be displayed in the message box.CString GetMessage ( );// Methods for setting the title to be displayed in the message box.void SetTitle ( CString strTitle );void SetTitle ( UINT nTitleID );// Method for retrieving the title to be displayed in the message box.CString GetTitle ( );// Methods for setting the icon to be displayed in the message box.void SetMessageIcon ( HICON hIcon );void SetMessageIcon ( UINT nIconID );// Method for retrieving the icon to be displayed in the message box.HICON GetMessageIcon ( );// Method for setting a timeout.void SetTimeout ( UINT nSeconds, BOOL bDisabled = FALSE );// Method for retrieving the seconds for the timeout.UINT GetTimeoutSeconds ( );// Method for retrieving whether a timeout is disabled.BOOL GetTimeoutDisabled ( );public://// Methods for handling the stored states.// Method for resetting the message boxes stored in the registry.// static void ResetMessageBoxes ( );public://// Methods for handling common window functions.// Method for displaying the dialog.virtual INT_PTR DoModal ( );// Method for closing the dialog.void EndDialog ( int nResult );// Method for initializing the dialog.virtual BOOL OnInitDialog ( );// Method for handling command messages.virtual BOOL OnCmdMsg ( UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo );// Method for handling messages before dispatching them.virtual BOOL PreTranslateMessage ( MSG* pMsg );// Method for handling a timer event.afx_msg void OnTimer (UINT_PTR nIDEvent );protected://// Other methods for handling common window functions.// Method for handling window messages.virtual BOOL OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam,LRESULT* pResult );DECLARE_MESSAGE_MAP()private://// Private member variables of this dialog.CString		m_strMessage;		// Message to be displayed.CString		m_strTitle;			// Title to be used.UINT		m_nStyle;			// Style of the message box.UINT		m_nHelp;			// Help context of the message box.HICON		m_hIcon;			// Icon to be displayed in the dialog.UINT		m_nTimeoutSeconds;	// Seconds for a timeout.BOOL		m_bTimeoutDisabled;	// Flag whether the timeout is disabled.UINT		m_nTimeoutTimer;	// Timer for the timeout.// CString		m_strRegistryKey;	// Entry for storing the result in the// registry, if the MB_DONT_DISPLAY_AGAIN// or MB_DONT_ASK_AGAIN flag is given.private://// Control handling types and variables.typedef struct tagMSGBOXBTN{int		nID;				// ID of a dialog button.UINT	nTitle;				// ID of the title string resource.} MSGBOXBTN;CArray<MSGBOXBTN, const MSGBOXBTN&> m_aButtons;// List of all buttons in the dialog.int			m_nDefaultButton;	// ID of the default button.int			m_nEscapeButton;	// ID of the escape button.CStatic		m_stcIcon;			// Static control for the icon.CStatic		m_stcMessage;		// Static control for the message.private://// Size handling variables.CSize		m_sDialogUnit;		// Variable for the size of a dialog unit.CSize		m_sIcon;			// Variable for the size of the icon.CSize		m_sMessage;			// Variable for the size of the message.CSize		m_sCheckbox;		// Variable for the size of the checkbox.CSize		m_sButton;			// Variable for the size of a button.private://// Helper methods.// Method for generating the registry key.// CString	GenerateRegistryKey ( );// Method for adding a button to the list of buttons.void AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault = FALSE,BOOL bIsEscape = FALSE );// Methods for converting a dialog units to a pixel values.int XDialogUnitToPixel ( int x );int YDialogUnitToPixel ( int y );// Method for parsing the given style.void ParseStyle ( );// Method for creating the icon control.void CreateIconControl ( );// Method for creating the message control.void CreateMessageControl ( );// Method for creating the checkbox control.void CreateCheckboxControl ( );// Method for creating the button controls.void CreateButtonControls ( );// Method for defining the layout of the dialog.void DefineLayout ( );};

MessageBoxDialog.cpp

/**	Extended MFC message boxes -- Version 1.1a*	Copyright (c) 2004 Michael P. Mehl. All rights reserved.**	The contents of this file are subject to the Mozilla Public License*	Version 1.1a (the "License"); you may not use this file except in*	compliance with the License. You may obtain a copy of the License at *	http://www.mozilla.org/MPL/.**	Software distributed under the License is distributed on an "AS IS" basis,*	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License*	for the specific language governing rights and limitations under the*	License. **	The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights*	reserved. The Initial Developer of the Original Code is Michael P. Mehl*	<michael.mehl@web.de>.**	Alternatively, the contents of this file may be used under the terms of*	the GNU Lesser General Public License Version 2.1 (the "LGPL License"),*	in which case the provisions of LGPL License are applicable instead of*	those above. If you wish to allow use of your version of this file only*	under the terms of the LGPL License and not to allow others to use your*	version of this file under the MPL, indicate your decision by deleting*	the provisions above and replace them with the notice and other provisions*	required by the LGPL License. If you do not delete the provisions above,*	a recipient may use your version of this file under either the MPL or*	the LGPL License.*/#include "pch.h"
#include <assert.h>#include "MessageBoxDialog.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif// IMPLEMENT_DYNAMIC(CMessageBoxDialog, CDialog)//
// Layout values (in dialog units).#define CX_BORDER					8		// Width of the border.
#define CY_BORDER					8		// Height of the border.#define CX_CHECKBOX_ADDON			14		// Additional width of the checkbox.#define CX_BUTTON					40		// Standard width of a button.
#define CY_BUTTON					14		// Standard height of a button.
#define CX_BUTTON_BORDER			4		// Standard border for a button.
#define CY_BUTTON_BORDER			1		// Standard border for a button.
#define CX_BUTTON_SPACE				4		// Standard space for a button.#define CX_DLGUNIT_BASE				1000	// Values used for converting
#define CY_DLGUNIT_BASE				1000	// dialog units to pixels.//
// Timer values.#define MESSAGE_BOX_TIMER			2201	// Event identifier for the timer.//CString CMessageBoxDialog::LoadString(UINT nID)
{CString csRc;// 后续要隐藏字符串,就在函数内做了。switch (nID){//IDS_MESSAGEBOX_OK       "&Ok"case IDS_MESSAGEBOX_OK:{csRc = TEXT("确定");}break;//   IDS_MESSAGEBOX_CANCEL   "&Cancel"case IDS_MESSAGEBOX_CANCEL:{csRc = TEXT("取消");}break;//   IDS_MESSAGEBOX_ABORT    "&Abort"case IDS_MESSAGEBOX_ABORT:{csRc = TEXT("放弃");}break;//   IDS_MESSAGEBOX_RETRY    "&Retry"case IDS_MESSAGEBOX_RETRY:{csRc = TEXT("重试");}break;//   IDS_MESSAGEBOX_IGNORE   "&Ignore"case IDS_MESSAGEBOX_IGNORE:{csRc = TEXT("忽略");}break;//   IDS_MESSAGEBOX_IGNOREALL "Ignore &all"case IDS_MESSAGEBOX_IGNOREALL:{csRc = TEXT("忽略所有");}break;//   IDS_MESSAGEBOX_YES      "&Yes"case IDS_MESSAGEBOX_YES:{csRc = TEXT("是");}break;default:{assert(false);}break;}return csRc;
}// Constructors and destructors of the class./**	Constructor of the class.**	This constructor is used to provide the strings directly without providing*	resource IDs from which these strings should be retrieved. If no title is*	given, the application name will be used as the title of the dialog.*/CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, CString strMessage, CString strTitle, UINT nStyle, UINT nHelp ) : CDialog ( CMessageBoxDialog::IDD, pParent )
{// Enable the active accessibility.EnableActiveAccessibility();ASSERT(!strMessage.IsEmpty());// Save the information about the message box.m_strMessage		= strMessage;m_strTitle			= strTitle.IsEmpty() ? AfxGetAppName() : strTitle;m_nStyle			= nStyle;m_nHelp				= nHelp;// Do the default initialization.m_hIcon				= NULL;m_nTimeoutSeconds	= 0;m_bTimeoutDisabled	= FALSE;m_nTimeoutTimer		= 0;// m_strRegistryKey	= _T("");m_nDefaultButton	= IDC_STATIC;m_nEscapeButton		= IDC_STATIC;m_sDialogUnit		= CSize(0, 0);m_sIcon				= CSize(0, 0);m_sMessage			= CSize(0, 0);m_sCheckbox			= CSize(0, 0);m_sButton			= CSize(0, 0);m_aButtons.RemoveAll();
}/**	Constructor of the class.**	This constructor is used to load the strings for the title and the message*	text from the resources of this project. If no title is given, the*	application name will be used as the title of the dialog.*/
CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, UINT nMessageID,UINT nTitleID, UINT nStyle, UINT nHelp ) : CDialog ( CMessageBoxDialog::IDD, pParent )
{// Enable the active accessibility.EnableActiveAccessibility();// Check whether a title was given.if ( nTitleID == 0 ){// Use the application name.m_strTitle = AfxGetAppName();}else{// Try to load the title from the resources.VERIFY(m_strTitle = LoadString(nTitleID));}// Save the information about the message box.VERIFY(m_strMessage = LoadString(nMessageID));m_nStyle			= nStyle;m_nHelp				= nHelp;// Do the default initialization.m_hIcon				= NULL;m_nTimeoutSeconds	= 0;m_bTimeoutDisabled	= FALSE;m_nTimeoutTimer		= 0;// m_strRegistryKey	= _T("");m_nDefaultButton	= IDC_STATIC;m_nEscapeButton		= IDC_STATIC;m_sDialogUnit		= CSize(0, 0);m_sIcon				= CSize(0, 0);m_sMessage			= CSize(0, 0);m_sCheckbox			= CSize(0, 0);m_sButton			= CSize(0, 0);m_aButtons.RemoveAll();
}/**	Destructor of the class.*/
CMessageBoxDialog::~CMessageBoxDialog ( )
{// Check whether an icon was loaded.if ( m_hIcon != NULL ){// Free the icon.DestroyIcon(m_hIcon);// Reset the icon handle.m_hIcon = NULL;}
}//
// Methods for setting and retrieving dialog options./**	Method for setting the style of the message box.*/
inline void CMessageBoxDialog::SetStyle ( UINT nStyle )
{// Set the style of the message box.m_nStyle = nStyle;
}/**	Method for retrieving the style of the message box.*/
inline UINT CMessageBoxDialog::GetStyle ( )
{// Return the current style of the message box.return m_nStyle;
}/**	Method for setting the message to be displayed in the message box.*/
inline void CMessageBoxDialog::SetMessage ( CString strMessage )
{ASSERT(!strMessage.IsEmpty());// Save the message text.m_strMessage = strMessage;
}/**	Methods for setting the message to be displayed in the message box.*/
inline void CMessageBoxDialog::SetMessage ( UINT nMessageID )
{// Create a string for storing the message.CString strMessage = _T("");// Load the message from the resources.VERIFY(strMessage = LoadString(nMessageID));ASSERT(!strMessage.IsEmpty());// Save the message text.m_strMessage = strMessage;
}/**	Method for retrieving the message to be displayed in the message box.*/
inline CString CMessageBoxDialog::GetMessage ( )
{// Return the message text.return m_strMessage;
}/**	Method for setting the title to be displayed in the message box.*/
inline void CMessageBoxDialog::SetTitle ( CString strTitle )
{// Check whether a title was given.if ( strTitle.IsEmpty() ){// Use the application name as the title.strTitle = AfxGetAppName();}// Save the title.m_strTitle = strTitle;
}/**	Method for setting the title to be displayed in the message box.*/
inline void CMessageBoxDialog::SetTitle ( UINT nTitleID )
{// Create a string for storing the title.CString strTitle = _T("");// Check whether an ID was given.if ( nTitleID == 0 ){// Use the application name as the title.strTitle = AfxGetAppName();}else{// Try to load the string from the resources.VERIFY(strTitle = LoadString(nTitleID));ASSERT(!strTitle.IsEmpty());}// Save the title.m_strTitle = strTitle;
}/**	Method for retrieving the title to be displayed in the message box.*/
inline CString CMessageBoxDialog::GetTitle ( )
{// Return the title of the message box.return m_strTitle;
}/**	Method for setting the icon to be displayed in the message box.*/
inline void CMessageBoxDialog::SetMessageIcon ( HICON hIcon )
{ASSERT(hIcon != NULL);// Save the icon.m_hIcon = hIcon;
}/**	Method for setting the icon to be displayed in the message box.*/
inline void CMessageBoxDialog::SetMessageIcon ( UINT nIconID )
{// Try to load the given icon.m_hIcon = AfxGetApp()->LoadIcon(nIconID);ASSERT(m_hIcon != NULL);
}/**	Method for retrieving the icon to be displayed in the message box.*/
inline HICON CMessageBoxDialog::GetMessageIcon ( )
{// Return the icon for the message box.return m_hIcon;
}/**	Method for setting a timeout.**	A timeout is a countdown, which starts, when the message box is displayed.*	There are two modes for a timeout: The "un-disabled" or "enabled" timeout*	means, that the user can choose any button, but if he doesn't choose one,*	the default button will be assumed as being chossen, when the countdown is*	finished. The other mode, a "disabled" countdown is something like a nag*	screen. All buttons will be disabled, until the countdown is finished.*	After that, the user can click any button.*/
void CMessageBoxDialog::SetTimeout ( UINT nSeconds, BOOL bDisabled )
{// Save the settings for the timeout.m_nTimeoutSeconds	= nSeconds;m_bTimeoutDisabled	= bDisabled;
}/**	Method for retrieving the seconds for a timeout.*/
inline UINT CMessageBoxDialog::GetTimeoutSeconds ( )
{// Return the seconds for the timeout.return m_nTimeoutSeconds;
}/**	Method for retrieving whether a timeout is disabled.*/
inline BOOL CMessageBoxDialog::GetTimeoutDisabled ( )
{// Return the flag whether the timeout is disabled.return m_bTimeoutDisabled;
}//
// Methods for handling the stored states./**	Method for resetting the message boxes stored in the registry.**	This method removes all results of formerly displayed message boxes from*	the registry and therefore resets the state of the message boxes. Even*	those, where the user checked "Don't display/ask again" will again be*	displayed.*/
//void CMessageBoxDialog::ResetMessageBoxes ( )
//{
//	// Try to retrieve a handle to the application object.
//	CWinApp* pApplication = AfxGetApp();
//
//	ASSERT(pApplication);
//
//	// Check whether a handle was retrieved.
//	if ( pApplication != NULL )
//	{
//		// Create the registry key for this application.
//		CString strKey = _T("Software\\");
//		strKey += pApplication->m_pszRegistryKey;
//		strKey += _T("\\");
//		strKey += pApplication->m_pszProfileName;
//		strKey += _T("\\");
//		strKey += REGISTRY_SECTION_MESSAGEBOX;
//
//		// Delete the message box results stored in the registry.
//		pApplication->DelRegTree(HKEY_CURRENT_USER, strKey);
//	}
//}//
// Methods for handling common window functions./**	Method for displaying the dialog.**	If the MB_DONT_DISPLAY_AGAIN or MB_DONT_ASK_AGAIN flag is set, this*	method will check, whether a former result for this dialog was stored*	in the registry. If yes, the former result will be returned without*	displaying the dialog. Otherwise the message box will be displayed in*	the normal way.*/
INT_PTR CMessageBoxDialog::DoModal ( )
{// Check whether the result may be retrieved from the registry.if ( ( m_nStyle & MB_DONT_DISPLAY_AGAIN ) ||( m_nStyle & MB_DONT_ASK_AGAIN ) ){ Check whether the registry key was already generated.//if ( m_strRegistryKey.IsEmpty() )//{//	// Create the registry key for this dialog.//	m_strRegistryKey = GenerateRegistryKey();//} Try to read the former result of the message box from the registry.//int nFormerResult = AfxGetApp()->GetProfileInt(//	REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, (-1)); Check whether a result was retrieved.//if ( nFormerResult != (-1) )//{//	// Return the former result without displaying the dialog.//	return nFormerResult;//}}// Call the parent method.return __super::DoModal();
}/**	Method for closing the dialog.**	If the MB_DONT_DISPLAY_AGAIN or MB_DONT_ASK_AGAIN flag is set, this*	method will check, one of the checkbox was marked to save the result in*	the registry. If yes, the result of this dialog will be stored in the*	registry.*/
void CMessageBoxDialog::EndDialog ( int nResult )
{// Create a variable for storing the state of the checkbox.BOOL bDontDisplayAgain = FALSE;// Try to access the checkbox control.CWnd* pCheckboxWnd = GetDlgItem(IDCHECKBOX);// Check whether the control can be accessed.if ( pCheckboxWnd != NULL ){// Check whether the checkbox is checked.bDontDisplayAgain = ( ((CButton*)pCheckboxWnd)->GetCheck() == BST_CHECKED );}// Check whether the result may be stored in the registry.//if ( ( ( m_nStyle & MB_DONT_DISPLAY_AGAIN ) && bDontDisplayAgain ) ||//	( ( m_nStyle & MB_DONT_ASK_AGAIN ) && bDontDisplayAgain ) )//{//	// Check whether the registry key was already generated.//	if ( m_strRegistryKey.IsEmpty() )//	{//		// Create the registry key for this dialog.//		m_strRegistryKey = GenerateRegistryKey();//	}//	//	// Store the result of the dialog in the registry.//	//AfxGetApp()->WriteProfileInt(REGISTRY_SECTION_MESSAGEBOX, //	//	m_strRegistryKey, nResult);//}// Call the parent method.__super::EndDialog(nResult);
}/**	Method for initializing the dialog.**	This method is used for initializing the dialog. It will create the*	content of the dialog, which means it will create all controls and will*	size the dialog to fit it's content.*/
BOOL CMessageBoxDialog::OnInitDialog ( )
{// Call the parent method.if ( !__super::OnInitDialog() ){// Return with an error.return FALSE;}// Set the title of the dialog.SetWindowText(m_strTitle);// Set the help ID of the dialog.SetHelpID(m_nHelp);// Parse the style of the message box.ParseStyle();// Create the elements of the dialog.CreateIconControl();CreateMessageControl();CreateCheckboxControl();CreateButtonControls();// Define the layout of the dialog.DefineLayout();// Check whether no sound should be generated.if ( !( m_nStyle & MB_NO_SOUND ) ){// Do a beep.MessageBeep(m_nStyle & MB_ICONMASK);}// Check whether the window should be system modal.if ( m_nStyle & MB_SYSTEMMODAL ){// Modify the style of the window.ModifyStyle(0, DS_SYSMODAL);}// Check whether to bring the window to the foreground.if ( m_nStyle & MB_SETFOREGROUND ){// Bring the window to the foreground.SetForegroundWindow();}// Check whether the window should be the topmost window.if ( m_nStyle & MB_TOPMOST ){// Modify the style of the window.ModifyStyleEx(0, WS_EX_TOPMOST);}// Check whether an escape button was defined.if ( m_nEscapeButton == IDC_STATIC ){// Disable the close item from the system menu.GetSystemMenu(FALSE)->EnableMenuItem(SC_CLOSE, MF_GRAYED);}// Check whether a timeout is set.if ( m_nTimeoutSeconds > 0 ){// Check whether it's a disabled timeout.if ( m_bTimeoutDisabled ){// Run through all created buttons.for ( int i = 0; i < m_aButtons.GetCount(); i++ ){// Try to retrieve a handle for the button.CWnd* pButtonWnd = GetDlgItem(m_aButtons.GetAt(i).nID);ASSERT(pButtonWnd);// Check whether the handle was retrieved.if ( pButtonWnd != NULL ){// Disable the button.pButtonWnd->EnableWindow(FALSE);}}// Try to retrieve the handle of the checkbox.CWnd* pCheckboxWnd = GetDlgItem(IDCHECKBOX);// Check whether the checkbox handle was retrieved.if ( pCheckboxWnd != NULL ){// Disable the checkbox.pCheckboxWnd->EnableWindow(FALSE);}}// Install a timer.m_nTimeoutTimer = (UINT)SetTimer(MESSAGE_BOX_TIMER, 1000, NULL);}// Check whether a default button was defined.if ( m_nDefaultButton != IDC_STATIC ){// Set the focus to the default button.GetDlgItem(m_nDefaultButton)->SetFocus();// Set the default ID of the dialog.SetDefID(m_nDefaultButton);// Return FALSE to set the focus correctly.return FALSE;}// Everything seems to be done successfully.return TRUE;
}/**	Method for handling command messages.**	This method will handle command messages, which are those messages, which*	are generated, when a user clicks a button of the dialog.*/
BOOL CMessageBoxDialog::OnCmdMsg ( UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo )
{// Check whether it's the help button.if ( ( nID == IDHELP ) && ( nCode == CN_COMMAND ) ){// Display the help for this message box.OnHelp();// The message has been processed successfully.return TRUE;}// Check whether the ID of the control element is interesting for us.if ( ( nID != IDC_STATIC ) && ( nID != IDCHECKBOX ) && ( nCode == CN_COMMAND ) ){// End the dialog with the given ID.EndDialog(nID);// The message has been processed successfully.return TRUE;}// Call the parent method.return __super::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}/**	Method for handling messages before dispatching them.**	This message will handle message before they get dispatched the normal way*	and will therefore implement the additional behavior of this dialog.*/
BOOL CMessageBoxDialog::PreTranslateMessage ( MSG* pMsg )
{// Check whether it's a key message and whether it's not a disable timeout.if ( pMsg->message == WM_KEYDOWN ){// Check whether a disabled timeout is running.if ( m_bTimeoutDisabled && ( m_nTimeoutSeconds > 0 ) ){// Stop here and do nothing until the timeout is finished.return TRUE;}// Check whether it's the return key.if ( pMsg->wParam == VK_RETURN ){// Try to retrieve the current focus.CWnd* pFocusWnd = GetFocus();// Check whether a handle was retrieved.if ( pFocusWnd != NULL ){// Try to determine the ID of the element.int nID = pFocusWnd->GetDlgCtrlID();// Run through the list of defined buttons.for ( int i = 0; i < m_aButtons.GetCount(); i++ ){// Check whether the ID is a button.if ( m_aButtons.GetAt(i).nID == nID ){// Save this ID as the default ID.m_nDefaultButton = nID;// Break the loop to save time.break;}}// End the dialog with the default command.EndDialog(m_nDefaultButton);// The message has been processed successfully.return TRUE;}}// Check whether it's the escape key.if ( ( pMsg->wParam == VK_ESCAPE ) || ( pMsg->wParam == VK_CANCEL ) ){// Check whether an escape button was defined.if ( m_nEscapeButton != IDC_STATIC ){// End the dialog with this ID.EndDialog(m_nEscapeButton);}// The message has been processed successfully.return TRUE;}}// Call the parent method.return __super::PreTranslateMessage(pMsg);
}/**	Method for handling a timer event.**	When a timeout for the message box is set, this method will perform the*	update of the dialog controls every second.*/
void CMessageBoxDialog::OnTimer (UINT_PTR nIDEvent )
{// Check whether the event is interesting for us.if ( nIDEvent == MESSAGE_BOX_TIMER ){// Decrease the remaining seconds.m_nTimeoutSeconds--;// Check whether the timeout is finished.if ( m_nTimeoutSeconds == 0 ){// Kill the timer for this event and reset the handle.KillTimer(m_nTimeoutTimer);// Check whether it has been a disabled timeout.if ( m_bTimeoutDisabled ){// Run through all defined buttons.for ( int i = 0; i < m_aButtons.GetCount(); i++ ){// Try to retrieve a handle to access the button.CWnd* pButtonWnd = GetDlgItem(m_aButtons.GetAt(i).nID);ASSERT(pButtonWnd);// Check whether a handle was retrieved.if ( pButtonWnd != NULL ){// Enable the button again.pButtonWnd->EnableWindow(TRUE);}}// Try to retrieve a handle for the checkbox.CWnd* pCheckboxWnd = GetDlgItem(IDCHECKBOX);// Check whether the checkbox was found.if ( pCheckboxWnd != NULL ){// Enable the checkbox.pCheckboxWnd->EnableWindow(TRUE);}}else{// End the dialog with the default button.EndDialog(m_nDefaultButton);}}// Run through the list of defined buttons.for ( int i = 0; i < m_aButtons.GetCount(); i++ ){// Check whether this button is the default button.if ( m_aButtons.GetAt(i).nID == m_nDefaultButton ){// Create two strings for the button text.CString strButtonText	= _T("");CString strFullText		= _T("");// Try to load the text for the button.VERIFY(strButtonText = LoadString(m_aButtons.GetAt(i).nTitle));// Use the button text as the full text.strFullText = strButtonText;// Check whether the timeout is finished.if ( m_nTimeoutSeconds > 0 ){// Add the remaining seconds to the text of the button.strFullText.Format(_T("%s = %d"), strButtonText.GetString(), m_nTimeoutSeconds);}// Try to retrieve a handle for the button.CWnd* pButtonWnd = GetDlgItem(m_aButtons.GetAt(i).nID);ASSERT(pButtonWnd);// Check whether the handle was retrieved successfully.if ( pButtonWnd != NULL ){// Set the text of the button.pButtonWnd->SetWindowText(strFullText);}}}}// Call the parent method.__super::OnTimer(nIDEvent);
}//
// Other dialog handling methods./**	Method for handling window messages.*/
BOOL CMessageBoxDialog::OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam,LRESULT* pResult )
{// Check whether to close the dialog.if ( message == WM_CLOSE ){// Check whether a disabled timeout is running.if ( m_bTimeoutDisabled && ( m_nTimeoutSeconds > 0 ) ){// Stop here and do nothing until the timeout is finished.return TRUE;}// Check whether an escape button is defined.if ( m_nEscapeButton != IDC_STATIC ){// End the dialog with this command.EndDialog(m_nEscapeButton);}// The message was handled successfully.return TRUE;}// Call the parent method.return __super::OnWndMsg(message, wParam, lParam, pResult);
}BEGIN_MESSAGE_MAP(CMessageBoxDialog, CDialog)ON_WM_TIMER()
END_MESSAGE_MAP()//
// Helper methods./**	Method for generating a registry key.**	This method tries to create a registry key, which will be used for storing*	the result of the message box, if the MB_DONT_DISPLAY_AGAIN or the*	MB_DONT_ASK_AGAIN flag is set.*/
//CString CMessageBoxDialog::GenerateRegistryKey ( )
//{
//	// Create a string to store the registry key.
//	CString strRegistryKey = _T("");
//
//	// Check whether a help ID is given.
//	if ( m_nHelp != 0 )
//	{
//		// Simply use the help ID, because we assume, it's unique.
//		strRegistryKey.Format(_T("%d"), m_nHelp);
//	}
//	else
//	{
//		// POSSIBLE BUG: The following algorithm for creating a checksum is
//		// very simple and may not ensure, the registry key is really unique.
//		// But for now it may be enough.
//
//		// Create a variable to store the checksum.
//		int nChecksum = 0;
//
//		// Run through the message string.
//		for ( int i = 0; i < m_strMessage.GetLength(); i++ )
//		{
//			// Get the char at the given position and add it to the checksum.
//			nChecksum += ((int)m_strMessage.GetAt(i)) * i;
//		}
//
//		// Convert the checksum to a string.
//		strRegistryKey.Format(_T("%d"), nChecksum);
//	}
//
//	// Return the registry key.
//	return strRegistryKey;
//}/**	Method for adding a button to the list of buttons.**	This method adds a button to the list of buttons, which will be created in*	the dialog, but it will not create the button control itself.*/
void CMessageBoxDialog::AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault,BOOL bIsEscape )
{// Create a new structure to store the button information.MSGBOXBTN bButton = { (int)nID, nTitle };// Add the button to the list of buttons.m_aButtons.Add(bButton);// Check whether this button is the default button.if ( bIsDefault ){// Save the ID of the button as the ID of the default button.m_nDefaultButton = nID;}// Check whether this button is the escape button.if ( bIsEscape ){// Save the ID of the button as the ID of the escape button.m_nEscapeButton = nID;}
}/**	Method for converting a dialog unit x value to a pixel value.*/
inline int CMessageBoxDialog::XDialogUnitToPixel ( int x )
{// Check whether the dimension of a dialog unit has already been determined.if ( m_sDialogUnit.cx == 0 ){// Create a rect for mapping it to the dialog rect.CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE);// Map the rect to the dialog.MapDialogRect(rcDialog);// Save the rect.m_sDialogUnit = rcDialog.Size();}// Return the converted value.return ( x * m_sDialogUnit.cx / CX_DLGUNIT_BASE );
}/**	Method for converting a dialog unit y value to a pixel value.*/
inline int CMessageBoxDialog::YDialogUnitToPixel ( int y )
{// Check whether the dimension of a dialog unit has already been determined.if ( m_sDialogUnit.cy == 0 ){// Create a rect for mapping it to the dialog rect.CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE);// Map the rect to the dialog.MapDialogRect(rcDialog);// Save the rect.m_sDialogUnit = rcDialog.Size();}// Return the converted value.return ( y * m_sDialogUnit.cy / CY_DLGUNIT_BASE );
}/**	Method for parsing the given style.**	This method will parse the given style for the message box and will create*	the elements of the dialog box according to it. If you want to add more*	user defined styles, simply modify this method.*/
void CMessageBoxDialog::ParseStyle ( )
{// Switch the style of the buttons.switch ( m_nStyle & MB_TYPEMASK ){case MB_OKCANCEL:// Add two buttons: "Ok" and "Cancel".AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE);AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE);break;case MB_ABORTRETRYIGNORE:// Add three buttons: "Abort", "Retry" and "Ignore".AddButton(IDABORT, IDS_MESSAGEBOX_ABORT, TRUE);AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY);AddButton(IDIGNORE, IDS_MESSAGEBOX_IGNORE);break;case MB_YESNOCANCEL:// Add three buttons: "Yes", "No" and "Cancel".AddButton(IDYES, IDS_MESSAGEBOX_YES, TRUE);// Check whether to add a "Yes to all" button.if ( m_nStyle & MB_YES_TO_ALL ){// Add the additional button.AddButton(IDYESTOALL, IDS_MESSAGEBOX_YES_TO_ALL);}AddButton(IDNO, IDS_MESSAGEBOX_NO);// Check whether to add a "No to all" button.if ( m_nStyle & MB_NO_TO_ALL ){// Add the additional button.AddButton(IDNOTOALL, IDS_MESSAGEBOX_NO_TO_ALL);}AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE);break;case MB_YESNO:// Add two buttons: "Yes" and "No".AddButton(IDYES, IDS_MESSAGEBOX_YES, TRUE);// Check whether to add a "Yes to all" button.if ( m_nStyle & MB_YES_TO_ALL ){// Add the additional button.AddButton(IDYESTOALL, IDS_MESSAGEBOX_YES_TO_ALL);}AddButton(IDNO, IDS_MESSAGEBOX_NO);// Check whether to add a "No to all" button.if ( m_nStyle & MB_NO_TO_ALL ){// Add the additional button.AddButton(IDNOTOALL, IDS_MESSAGEBOX_NO_TO_ALL);}break;case MB_RETRYCANCEL:// Add two buttons: "Retry" and "Cancel".AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY, TRUE);AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE);break;case MB_CANCELTRYCONTINUE:// Add three buttons: "Cancel", "Try again" and "Continue".AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, TRUE, TRUE);AddButton(IDTRYAGAIN, IDS_MESSAGEBOX_RETRY);AddButton(IDCONTINUE, IDS_MESSAGEBOX_CONTINUE);break;case MB_CONTINUEABORT:// Add two buttons: "Continue" and "Abort".AddButton(IDCONTINUE, IDS_MESSAGEBOX_CONTINUE, TRUE);AddButton(IDABORT, IDS_MESSAGEBOX_ABORT);break;case MB_SKIPSKIPALLCANCEL:// Add three buttons: "Skip", "Skip all" and "Cancel".AddButton(IDSKIP, IDS_MESSAGEBOX_SKIP, TRUE);AddButton(IDSKIPALL, IDS_MESSAGEBOX_SKIPALL);AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE);break;case MB_IGNOREIGNOREALLCANCEL:// Add three buttons: "Ignore", "Ignore all" and "Cancel".AddButton(IDIGNORE, IDS_MESSAGEBOX_IGNORE, TRUE);AddButton(IDIGNOREALL, IDS_MESSAGEBOX_IGNOREALL);AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE);break;default:case MB_OK:// Add just one button: "Ok".AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE, TRUE);break;}// Check whether to add a help button.if ( m_nStyle & MB_HELP ){// Add the help button.AddButton(IDHELP, IDS_MESSAGEBOX_HELP);}// Check whether a default button was defined.if ( m_nStyle & MB_DEFMASK ){// Create a variable to store the index of the default button.int nDefaultIndex = 0;// Switch the default button.switch ( m_nStyle & MB_DEFMASK ){case MB_DEFBUTTON1:// Set the index of the default button.nDefaultIndex = 0;break;case MB_DEFBUTTON2:// Set the index of the default button.nDefaultIndex = 1;break;case MB_DEFBUTTON3:// Set the index of the default button.nDefaultIndex = 2;break;case MB_DEFBUTTON4:// Set the index of the default button.nDefaultIndex = 3;break;case MB_DEFBUTTON5:// Set the index of the default button.nDefaultIndex = 4;break;case MB_DEFBUTTON6:// Set the index of the default button.nDefaultIndex = 5;break;}// Check whether enough buttons are available.if ( m_aButtons.GetCount() >= ( nDefaultIndex + 1 ) ){// Set the new default button.m_nDefaultButton = m_aButtons.GetAt(nDefaultIndex).nID;}}// Check whether an icon was specified.if ( ( m_nStyle & MB_ICONMASK ) && ( m_hIcon == NULL ) ){// Switch the icon.switch ( m_nStyle & MB_ICONMASK ){case MB_ICONEXCLAMATION:// Load the icon with the exclamation mark.m_hIcon = AfxGetApp()->LoadStandardIcon(IDI_EXCLAMATION);break;case MB_ICONHAND:// Load the icon with the error symbol.m_hIcon = AfxGetApp()->LoadStandardIcon(IDI_HAND);break;case MB_ICONQUESTION:// Load the icon with the question mark.m_hIcon = AfxGetApp()->LoadStandardIcon(IDI_QUESTION);break;case MB_ICONASTERISK:// Load the icon with the information symbol.m_hIcon = AfxGetApp()->LoadStandardIcon(IDI_ASTERISK);break;}}
}/**	Method for creating the icon control.**	This method will check whether the handle for an icon was defined and if*	yes it will create an control in the dialog to display that icon.*/
void CMessageBoxDialog::CreateIconControl ( )
{// Check whether an icon was defined.if ( m_hIcon != NULL ){// Create a structure to read information about the icon.ICONINFO iiIconInfo;// Retrieve information about the icon.GetIconInfo(m_hIcon, &iiIconInfo);ASSERT(iiIconInfo.fIcon);// Create a handle to access the bitmap information of the icon.BITMAP bmIcon;// Retrieve the bitmap information of the icon.GetObject((HGDIOBJ)iiIconInfo.hbmColor, sizeof(bmIcon), &bmIcon);// Save the size of the icon.m_sIcon.cx = bmIcon.bmWidth;m_sIcon.cy = bmIcon.bmHeight;// Create a dummy rect for the icon control.CRect rcDummy;// Create the control for the icon.m_stcIcon.Create(NULL, WS_CHILD | WS_VISIBLE | WS_DISABLED | SS_ICON,rcDummy, this, (UINT)IDC_STATIC);// Set the icon of the control.m_stcIcon.SetIcon(m_hIcon);}
}/**	Method for creating the text control.**	This method create the control displaying the text of the message for the*	message box. It will also try to determine the size required for the*	message.*/
void CMessageBoxDialog::CreateMessageControl ( )
{ASSERT(!m_strMessage.IsEmpty());// Create a DC for accessing the display driver.CDC dcDisplay;dcDisplay.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);// Select the new font and store the old one.CFont* pOldFont = dcDisplay.SelectObject(GetFont());// Define the maximum width of the message.int nMaxWidth = ( GetSystemMetrics(SM_CXSCREEN) / 2 ) + 100;// Check whether an icon is displayed.if ( m_hIcon != NULL ){// Decrease the maximum width.nMaxWidth -= m_sIcon.cx + 2 * XDialogUnitToPixel(CX_BORDER);}// Create a rect with the maximum width.CRect rcMessage(0, 0, nMaxWidth, nMaxWidth);// Draw the text and retrieve the size of the text.dcDisplay.DrawText(m_strMessage, rcMessage, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);// Save the size required for the message.m_sMessage = rcMessage.Size();// Select the old font again.dcDisplay.SelectObject(pOldFont);// Create a dummy rect for the control.CRect rcDummy;// Create a variable with the style of the control.DWORD dwStyle = WS_CHILD | WS_VISIBLE;// Check whether the text should be right aligned.if ( m_nStyle & MB_RIGHT ){// Align the text to the right.dwStyle |= SS_RIGHT;}else{// Align the text to the left.dwStyle |= SS_LEFT;}// Create the static control for the message.m_stcMessage.Create(m_strMessage,  dwStyle, rcDummy, this, (UINT)IDC_STATIC);// Check whether the text will be read from right to left.if ( m_nStyle & MB_RTLREADING ){// Change the extended style of the control.m_stcMessage.ModifyStyleEx(0, WS_EX_RTLREADING);}// Set the font of the dialog.m_stcMessage.SetFont(GetFont());
}/**	Method for creating the checkbox control.**	If the user either specified the MB_DONT_DISPLAY_AGAIN or*	MB_DONT_ASK_AGAIN flag, this method will create a checkbox in the dialog*	for enabling the user to disable this dialog in the future.*/
void CMessageBoxDialog::CreateCheckboxControl ( )
{// Check whether a checkbox is required.if ( ( m_nStyle & MB_DONT_DISPLAY_AGAIN ) ||( m_nStyle & MB_DONT_ASK_AGAIN ) ){// Create a variable for storing the title of the checkbox.CString	strCheckboxTitle = _T("");// Check which style is used.if ( m_nStyle & MB_DONT_DISPLAY_AGAIN ){// Load the string for the checkbox.// VERIFY(strCheckboxTitle = LoadString(IDS_MESSAGEBOX_DONT_DISPLAY_AGAIN));}else{// Check which style is used.if ( m_nStyle & MB_DONT_ASK_AGAIN ){// Load the string for the checkbox.// VERIFY(strCheckboxTitle = LoadString(IDS_MESSAGEBOX_DONT_ASK_AGAIN));}}ASSERT(!strCheckboxTitle.IsEmpty());// Create a handle to access the DC of the dialog.CClientDC dc(this);// Retrieve the font for this dialog and select it.CFont* pWndFont = GetFont();CFont* pOldFont = dc.SelectObject(pWndFont);// Retrieve the size of the text.m_sCheckbox = dc.GetTextExtent(strCheckboxTitle);// Add the additional value to the width of the checkbox.m_sCheckbox.cx += XDialogUnitToPixel(CX_CHECKBOX_ADDON);// Select the old font again.dc.SelectObject(pOldFont);// Create a dummy rect for the checkbox.CRect rcDummy;// Create a handle for the checkbox.CButton btnCheckbox;// Create the checkbox.btnCheckbox.Create(strCheckboxTitle, WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX, rcDummy, this, IDCHECKBOX);// Check whether the checkbox should be marked checked at startup.if ( m_nStyle & MB_DEFAULT_CHECKED ){// Mark the checkbox.btnCheckbox.SetCheck(BST_CHECKED);}// Set the font of the control.btnCheckbox.SetFont(pWndFont);// Remove the subclassing again.btnCheckbox.UnsubclassWindow();}
}/**	Method for creating the button controls.**	According to the list of buttons, which should be displayed in this*	message box, this method will create them and add them to the dialog.*/
void CMessageBoxDialog::CreateButtonControls ( )
{int iTmp = 0;UINT uTmp = 0;// Initialize the control with the size of the button.m_sButton.SetSize(XDialogUnitToPixel(CX_BUTTON),YDialogUnitToPixel(CY_BUTTON));// Create a handle to access the DC of the dialog.CClientDC dc(this);// Retrieve the font for this dialog and select it.CFont* pWndFont = GetFont();CFont* pOldFont = dc.SelectObject(pWndFont);// Create a dummy rect.CRect rcDummy;// Run through all buttons defined in the list of the buttons.iTmp = (int)m_aButtons.GetCount();for ( int i = 0; i < m_aButtons.GetCount(); i++ ){// Create a string and load the title of the button.CString strButtonTitle;uTmp = m_aButtons.GetAt(i).nTitle;VERIFY(strButtonTitle = LoadString(uTmp));// Create a string with the text used to determine the length.CString strLengthTest = strButtonTitle;// Check whether there's a timeout set.if ( m_nTimeoutSeconds > 0 ){// Create a string with the longest timeout text.CString strTimeoutText = _T("");strTimeoutText.Format(_T("%s = %d"), strLengthTest.GetString(), m_nTimeoutSeconds);// Use this text to determine the length of the string.strLengthTest = strTimeoutText;}// Retrieve the size of the text.CSize sButtonText = dc.GetTextExtent(strLengthTest);// Resize the button.m_sButton.cx = max(m_sButton.cx, sButtonText.cx);m_sButton.cy = max(m_sButton.cy, sButtonText.cy);// Create a new handle for creating a button control.CButton btnControl;// Create the button.btnControl.Create(strButtonTitle, WS_CHILD | WS_VISIBLE | WS_TABSTOP,rcDummy, this, m_aButtons.GetAt(i).nID);// Set the font of the control.btnControl.SetFont(pWndFont);// Remove the subclassing again.btnControl.UnsubclassWindow();}// Add margins to the button size.m_sButton.cx += 2 * XDialogUnitToPixel(CX_BUTTON_BORDER);m_sButton.cy += 2 * XDialogUnitToPixel(CY_BUTTON_BORDER);// Select the old font again.dc.SelectObject(pOldFont);
}/**	Method for defining the layout of the dialog.**	This method will define the actual layout of the dialog. This layout is*	based on the created controls for the dialog.*/
void CMessageBoxDialog::DefineLayout ( )
{// Create a variable for storing the size of the dialog.CSize sClient = CSize(2 * XDialogUnitToPixel(CX_BORDER),2 * YDialogUnitToPixel(CY_BORDER));// Create a variable to store the left position for a control element.int nXPosition = XDialogUnitToPixel(CX_BORDER);int nYPosition = YDialogUnitToPixel(CY_BORDER);// Check whether an icon is defined.if ( m_hIcon != NULL ){// Move the icon control.m_stcIcon.MoveWindow(XDialogUnitToPixel(CX_BORDER), YDialogUnitToPixel(CY_BORDER), m_sIcon.cx, m_sIcon.cy);// Add the size of the icon to the size of the dialog.sClient.cx += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER);sClient.cy += m_sIcon.cy + YDialogUnitToPixel(CY_BORDER);// Increase the x position for following control elements.nXPosition += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER);}// Change the size of the dialog according to the size of the message.sClient.cx += m_sMessage.cx + XDialogUnitToPixel(CX_BORDER);sClient.cy = max(sClient.cy, m_sMessage.cy + 2 * YDialogUnitToPixel(CY_BORDER) + YDialogUnitToPixel(CY_BORDER / 2));// Set the position of the message text.m_stcMessage.MoveWindow(nXPosition, nYPosition, m_sMessage.cx,m_sMessage.cy);// Define the new y position.nYPosition += m_sMessage.cy + YDialogUnitToPixel(CY_BORDER) +YDialogUnitToPixel(CY_BORDER / 2);// Check whether an checkbox is defined.if ( ( m_nStyle & MB_DONT_DISPLAY_AGAIN ) ||( m_nStyle & MB_DONT_ASK_AGAIN ) ){// Try to determine the control element for the checkbox.CWnd* pCheckboxWnd = GetDlgItem(IDCHECKBOX);ASSERT(pCheckboxWnd);// Check whether the control was retrieved.if ( pCheckboxWnd != NULL ){// Move the checkbox window.pCheckboxWnd->MoveWindow(nXPosition, nYPosition, m_sCheckbox.cx,m_sCheckbox.cy);// Resize the dialog if necessary.sClient.cx = max(sClient.cx, nXPosition + m_sCheckbox.cx +XDialogUnitToPixel(CX_BORDER));sClient.cy = max(sClient.cy, nYPosition + m_sCheckbox.cy +YDialogUnitToPixel(CY_BORDER));// Define the y positions.nYPosition += m_sCheckbox.cy + YDialogUnitToPixel(CY_BORDER);}}// Calculate the width of the buttons.int cxButtons =(int)(( m_aButtons.GetCount() - 1 ) * XDialogUnitToPixel(CX_BUTTON_SPACE) +m_aButtons.GetCount() * m_sButton.cx);int cyButtons = m_sButton.cy;// Add the size of the buttons to the dialog.sClient.cx = max(sClient.cx, 2 * XDialogUnitToPixel(CX_BORDER) + cxButtons);sClient.cy += cyButtons + YDialogUnitToPixel(CY_BORDER);// Calculate the start y position for the buttons.int nXButtonPosition = ( sClient.cx - cxButtons ) / 2;int nYButtonPosition = sClient.cy - YDialogUnitToPixel(CY_BORDER) - m_sButton.cy;// Check whether the buttons should be right aligned.if ( m_nStyle & MB_RIGHT_ALIGN ){// Right align the buttons.nXButtonPosition = sClient.cx - cxButtons - XDialogUnitToPixel(CX_BORDER);}// Run through all buttons.for ( int i = 0; i < m_aButtons.GetCount(); i++ ){// Try to retrieve the handle to access the button.CWnd* pButton = GetDlgItem(m_aButtons.GetAt(i).nID);ASSERT(pButton);// Check whether the handle was retrieved successfully.if ( pButton != NULL ){// Move the button.pButton->MoveWindow(nXButtonPosition, nYButtonPosition, m_sButton.cx, m_sButton.cy);// Set the new x position of the next button.nXButtonPosition += m_sButton.cx + XDialogUnitToPixel(CX_BUTTON_SPACE);}}// Set the dimensions of the dialog.CRect rcClient(0, 0, sClient.cx, sClient.cy);// Calculate the window rect.CalcWindowRect(rcClient);// Move the window.MoveWindow(rcClient);// Center the window.CenterWindow();
}

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/318862.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】第一门课 神经网络和深度学习 Week 4 深层神经网络

&#x1f680;Write In Front&#x1f680; &#x1f4dd;个人主页&#xff1a;令夏二十三 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;深度学习 &#x1f4ac;总结&#xff1a;希望你看完之后&#xff0c;能对…

Jupyter Notebook魔术命令

Jupyter Notebook是一个基于网页的交互式笔记本&#xff0c;支持运行多种编程语言。 Jupyter Notebook 的本质式一个Web应用程序&#xff0c;便于创建和共享文学化程序文档&#xff0c;支持实现代码&#xff0c;数学方程&#xff0c;可视化和markdown。用途包括&#xff1a;数据…

spring cloud eureka 初始化报错(A bean with that name has already been defined)

报错内容 The bean ‘eurekaRegistration’, defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration E u r e k a C l i e n t C o n f i g u r a t i o n . c l a s s ] , c o u l d n o t b e r e g i s t e r e d . A …

Adobe PS 2023、Adobe Photoshop 2023下载教程、安装教程

Adobe Photoshop &#xff08;<-下载连接&#xff09;简介&#xff1a; Adobe Photoshop是一款广泛使用的图像处理软件&#xff0c;由Adobe公司开发。它提供了许多强大的工具和功能&#xff0c;可以用于图像编辑、合成、修饰、设计等各个领域。用户可以使用Photoshop来调整…

golang学习笔记(协程的基础知识)

golang的协程 协程是一种轻量级的线程&#xff0c;它可以实现并发执行的并行操作。协程是Go语言中的一个核心特性&#xff0c;它使得程序能够以并发的方式运行&#xff0c;并且非常高效。与传统的线程相比&#xff0c;协程的创建和销毁成本非常低&#xff0c;可以方便地启动大…

k8s 资源组版本支持列表

1 kubernetes的资源注册表 kube-apiserver组件启动后的第一件事情是将Kubernetes所支持的资源注册到Scheme资源注册表中,这样后面启动的逻辑才能够从Scheme资源注册表中拿到资源信息并启动和运行API服务。 kube-apiserver资源注册分为两步:第1步,初始化Scheme资源注册表;…

thinkphp家政上门预约服务小程序家政保洁师傅上门服务小程序上门服务在线派单安装教程

介绍 thinkphp家政上门预约服务小程序家政保洁师傅上门服务小程序上门服务在线派单安装教程 上门预约服务派单小程序家政小程序同城预约开源代码独立版安装教程 程序完整&#xff0c;经过安装检测&#xff0c;可放心下载安装。 适合本地的一款上门预约服务小程序&#xff0…

数据结构------栈的介绍和实现

目录 1.栈的一些初步认识 2.栈的实现 3.相关的函数介绍 &#xff08;1&#xff09;栈的初始化 &#xff08;2&#xff09;栈的销毁 &#xff08;3&#xff09;栈的数据插入 &#xff08;6&#xff09;判断是否为空 &#xff08;7&#xff09;栈的大小 4.栈的实现完整…

iBarcoder for Mac:一站式条形码生成软件

在数字化时代&#xff0c;条形码的应用越来越广泛。iBarcoder for Mac作为一款专业的条形码生成软件&#xff0c;为用户提供了一站式的解决方案。无论是零售、出版还是物流等行业&#xff0c;iBarcoder都能轻松应对&#xff0c;助力用户实现高效管理。 iBarcoder for Mac v3.14…

win11 Terminal 部分窗口美化

需求及分析&#xff1a;因为在 cmd、anaconda prompt 窗口中输入命令较多&#xff0c;而命令输入行和输出结果都是同一个颜色&#xff0c;不易阅读&#xff0c;故将需求定性为「美化窗口」。 美化结束后&#xff0c;我在想是否能不安装任何软件&#xff0c;简单地通过调整主题颜…

windows驱动开发-PNP管理器

PNP技术是由Microsoft提出的&#xff0c;英文Plug and play的缩写&#xff0c;中译即插即用&#xff0c;意思是系统自动侦测周边设备和板卡并自动安装设备驱动程序&#xff0c;做到插上就能用&#xff0c;无须人工干预&#xff0c;是Windows自带的一项技术。所谓即插即用是指将…

从零开始搭建一个vue项目

从零开始搭建一个vue项目 一、环境准备 1.1 安装node.js 选择合适的LTS版本&#xff0c;然后下载安装&#xff0c;安装地址&#xff1a;https://nodejs.org/en/download 在命令行中查看已安装的node.js版本 node -v v14.14.01.2 切换为淘宝的镜像源 解决国内下载慢的问题,…

极简shell制作

&#x1f30e;自定义简单shell制作 &#xff08;ps: 文末有完整代码&#xff09; 文章目录&#xff1a; 自定义简单shell制作 简单配置Linux文件 自定义Shell编写 命令行解释器       获取输入的命令       字符串分割       子进程进行进程替换 内建命令…

.NET 检测地址/主机/域名是否正常

&#x1f331;PING 地址/主机名/域名 /// <summary>/// PING/// </summary>/// <param name"ip">ip</param>/// <returns></returns>public static bool PingIp(string ip){System.Net.NetworkInformation.Ping p new System.N…

OpenAI 新推出 AI 问答搜索引擎——SearchGPT 震撼登场

您的浏览器不支持 video 标签。 OpenAI-SearchGPT 近日&#xff0c;OpenAI 曝光了自己的一款令人瞩目的 AI 问答搜索引擎——SearchGPT。这款搜索引擎带来了全新的搜索体验&#xff0c;给整个行业带来了巨大的压力。 SearchGPT 支持多种强大的功能。首先&#xff0c;它能够通过…

蓝桥杯练习系统(算法训练)ALGO-949 勇士和地雷阵

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 勇士们不小心进入了敌人的地雷阵&#xff08;用n行n列的矩阵表示&#xff0c;*表示某个位置埋有地雷&#xff0c;-表示某个…

ARP防火墙能够为网络安全贡献什么样的力量

ARP防火墙&#xff08;Address Resolution Protocol Firewall&#xff09;作为网络安全的一环&#xff0c;起到保护网络免受ARP欺骗攻击的关键作用。今天德迅云安全给您介绍ARP防火墙的相关方面&#xff0c;帮助您深入了解和认识这一关键的安全措施。 网络安全对于现代社会的信…

金三银四面试题(二十四):享元模式知多少?

什么是享元模式 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;旨在通过共享对象来减少内存使用&#xff0c;从而提高性能。它主要用于处理大量细粒度对象的情况&#xff0c;通过将这些对象的可共享部分&#xff08;内部状态&#xff09…

毫米波雷达原理(含代码)(含ARS548 4D毫米波雷达数据demo和可视化视频)

毫米波雷达原理 1. 传统毫米波雷达1.1 雷达工作原理1.2 单目标距离估计1.3 单目标速度估计1.4 单目标角度估计1.5 多目标距离估计1.6 多目标速度估计1.7多目标角度估计1.7 总结 3. FMCW雷达数据处理算法4. 毫米波雷达的目标解析(含python代码)5. ARS548 4D毫米波雷达数据demo(含…

MYSQL从入门到精通(二)

1、MYSQL高级概述 【1】架构概述 【2】索引优化 【3】查询截取 【4】mysql锁机制 【5】主从复制 2、MYSQL概述 【1】mysql内核 【2】sql优化工程师 【3】mysql服务器的优化 【4】各种参数常量设定 【5】查询语句优化 【6】主从复制 【7】软硬件升级 【8】容灾百分 【9】sql编…