|
Hi,
i extend Uwe Keims Version of XMessageBox ....
http://der-albert.com/codeproject/XMessageBox.zip
The new feature ist automatic button sizing ...
ButtonWidth is now the minimum button size.
I works great with the custom buttons, should also work with the standard buttons.
It's not tested so much ... so feedback is welcome. Feel free to use it.
Regards
Der Albert
|
|
|
|
|
|
Hi,
with FitButtonToText and RightJustifyButtons MessageBox fits to buttons, but with only FitButtonToText MessageBox does not fit to buttons (MessageBox ist to small with long buttontext).
Regards
Max
|
|
|
|
|
How can we change the messagebox and message text color ?
Thanks
|
|
|
|
|
Your XMessageBox is very useful. One question to this yet. Is it possible to adapt the size of customised buttons to the button's text length. I tested a little bit your demo app and the only trick I found is to reduce the button's text to fit.
|
|
|
|
|
For my own project, i made an addition, see
The additions allow for passing the texts for the buttons and the checkboxes from the caller to the function, so that it does not depend on loading from a resource.
I encapsulated my addition within //-[UK and //-]UK comments.
Maybe you like it and include it within the next version.
--
- Free Windows-based CMS: www.zeta-software.de/enu/producer/freeware/download.html
- See me: www.magerquark.de
- MSN Messenger: uwe_keim@hotmail.com
|
|
|
|
|
Really a great work, make life easy
Well, the document isnot very clear tell about the return value. e.g MB_DONOTASKAGAIN is different with IDOK. It is an AND value. I hope the document maybe improved for the newbie like me.
e.g. usage:
int rc = XMessageBox( AfxGetMainWnd()->m_hWnd, strText, strCaption,
MB_OKCANCEL | MB_DEFBUTTON1 | MB_DONOTASKAGAIN | MB_ICONQUESTION | MB_NORESOURCE | MB_SETFOREGROUND );
int choice = rc & ~MB_DONOTASKAGAIN;
if ( MB_DONOTASKAGAIN == (rc & MB_DONOTASKAGAIN) )
; // do not ask again .....
if ( IDOK == choice )
; // OK is pressed
|
|
|
|
|
|
|
Uwe Keim wrote:
It would be cool to clear the registry settings for the "don't show again" stuff.
Yes, I mention this under "lpszModule" - I leave it to the programmer to decide when to clear the registry entry, and to determine the persistence. One thing I will probably add is a separate function to clear the registry entry, although there are some problems with doing that.
Best wishes,
Hans
|
|
|
|
|
There may be many reasons not to put these sttings in the registry.
I suggest separate overridable CXMessageBoxSaveSetting that would allow to ClearAll();
Pierre Couderc
www.tol.fr
|
|
|
|
|
In the function "int CDialogTemplate::Display(LPCTSTR lpszCaption)"
the first for cycle didn't use "MultiByteToWideChar" to caculate memory buffer, but the second for cyle used "MultiByteToWideChar" to allocate the memory. So in some kinds of language, such as Chinese, it don't work.
Fixed:
Change the code in the first cyle
"int nChars = _tcslen(m_pDlgItemArray[i]->m_szCaption) + 1;
nItemLength += nChars * sizeof(WCHAR);
"
To
"int nActualChars = MultiByteToWideChar(CP_ACP, 0,
m_pDlgItemArray[i]->m_szCaption, -1, NULL, 0);
ASSERT(nActualChars > 0);
nItemLength += nActualChars * sizeof(WCHAR);
"
|
|
|
|
|
Thanks so much for your fix!
|
|
|
|
|
Hello,
thanks a lot for providing this message box. It works fine if you don't use Unicode. Can anyone give me tips where I have to adjust the code in order to use this message box with unicode? Thanks a lot for every hint!
Jens
|
|
|
|
|
I have submitted an update that includes Unicode support. It may be delayed because of the holidays. Check back in a few days - if it still isn't posted, send email to me and I will email new version to you.
|
|
|
|
|
That is very kind! Thanks a lot in advance. I wish you nice holidays.
Jens
|
|
|
|
|
Hello,
thanks a lot for providing this message box. It works fine if you don't use Unicode. Can anyone give me tips where I have to adjust the code in order to use this message box with unicode? Thanks a lot for every hint!
rekeu
|
|
|
|
|
Hi Hans , Beeks & Markus,
Thanks for your usual stuff.
Following Modification i did to use in my project.
- Modelss MessageBox
- implemented with Timer.
There may be lot of junks in the code.Will clear it later.
//New implementatation of XMessageBox.cpp
// XMessageBox.cpp
//
// Original Author: Hans Dietrich
// hdietrich2@hotmail.com
//
// Some parts of this software are from information in the
// Microsoft SDK.
// Code downloaded from The Code Project http://codeproject.com or http://thecodeproject.com
//
// This software is released into the public domain.
// You are free to use it in any way you like.
//
// This software is provided "as is" with no expressed
// or implied warranty. I accept no liability for any
// damage or loss of business that this software may cause.
//
// Code is adjusted by Anne Jan Beeks
// - making it MFC free
// - removing of static variables. so you can use it in case you have more boxes at one time
// Which could happen in a Multithread app
// - addition of Report button
// - correct character counts in case _TCHAR is multi-byte
// - make the messagebox, in case called with parent-wnd NULL, a child of the current active window
//
// Code Modified by Uma Maheswaran
// - Modless XMessageBox
// - And also implemeted with Timer
//////////////////////////////////////////////////////////////////////////////
// XMessageBox.h
//
// This software is released into the public domain.
// You are free to use it in any way you like.
//
// This software is provided "as is" with no expressed
// or implied warranty. I accept no liability for any
// damage or loss of business that this software may cause.
//
///////////////////////////////////////////////////////////////////////////////
#define MB_DEFBUTTON5 0x00000400L
#define MB_DEFBUTTON6 0x00000500L
#define MB_CONTINUEABORT 0x00000008L // adds two buttons, "Continue" and "Abort"
#define MB_DONOTASKAGAIN 0x01000000L // add checkbox "Do not ask me again"
#define MB_DONOTTELLAGAIN 0x02000000L // add checkbox "Do not tell me again"
#define MB_YESTOALL 0x04000000L // must be used with either MB_YESNO or MB_YESNOCANCEL
#define MB_NOTOALL 0x08000000L // must be used with either MB_YESNO or MB_YESNOCANCEL
#define MB_NORESOURCE 0x10000000L // do not try to load button strings from resources
#define MB_NOSOUND 0x80000000L // do not play sound when mb is displayed
#define MB_REPORT 0x20000000L // Add a report button
#define IDCONTINUE 10
#define IDYESTOALL 11
#define IDNOTOALL 12
#define IDS_OK 9001
#define IDS_CANCEL 9002
#define IDS_IGNORE 9003
#define IDS_RETRY 9004
#define IDS_ABORT 9005
#define IDS_HELP 9006
#define IDS_YES 9007
#define IDS_NO 9008
#define IDS_CONTINUE 9009
#define IDS_DONOTASKAGAIN 9010
#define IDS_DONOTTELLAGAIN 9011
#define IDS_YESTOALL 9012
#define IDS_NOTOALL 9013
/*
int XMessageBox(HWND hwnd,
LPCTSTR lpszMessage,
LPCTSTR lpszCaption = NULL,
UINT uStyle = MB_OK|MB_ICONEXCLAMATION,
UINT uHelpId = 0);
*/
#include <afxmt.h>
///////////////////////////////////////////////////////////////////////////////
//
// Class definitions
//
class CXMessageBox;
class CDialogItem
{
public:
DLGITEMTEMPLATE m_dlgItemTemplate;
enum Econtroltype {ICON = 0x7F, BUTTON, EDITCONTROL, STATICTEXT, CHECKBOX};
Econtroltype m_controltype;
_TCHAR m_szCaption[1024];
public:
CDialogItem(Econtroltype cType); // default constructor will fill in default values
CDialogItem() {}; // default constructor, not to be called directly
void AddItem(CXMessageBox& dialog, Econtroltype cType,
UINT nID,
RECT* prect = NULL,
LPCTSTR pszCaption = NULL);
};
class CXMessageBox
{
protected:
enum { FirstControlId = 1001};
enum { MaxButtonStringSize = 100};
enum
{
SpacingSize = 8,
ButtonWidth = 82,
ButtonHeight = 23,
ButtonSpacing = 6,
BottomMargin = 10,
MinimalHeight = 70,
DoNotAskAgainHeight = 16,
IdExHelp = 300,
IdExReport = 301,
IdDoNotAskAgian = 5555,
// if you change the value for MaxItems, make sure that the code
// in CXMessageBox remains consistent with your changes.
MaxItems = 20, // max no. of items in the dialog
};
CDialogItem**m_pDlgItemArray;//[MaxItems];
static BOOL CALLBACK MsgBoxDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM me);
int m_indicator;
int m_nButton; // current button no.
int m_nDefButton; // Default button
UINT m_nMaxID; // max control id (one more)
UINT m_nDefId; // button number of default button
UINT m_nHelpId; // help context id
HWND m_parentHwnd; // handle of owner window
HWND m_hWnd; // handle of owner window
HLOCAL hLocal;
const _TCHAR* m_lpszMessage; // The message retain pointer for Report functiom
HICON m_hIcon; // Handle of icon
HANDLE m_hFont; // handle to font for the message box
DLGTEMPLATE m_dlgTempl; // message box dialog template
_TCHAR szOK[MaxButtonStringSize];
_TCHAR szCancel[MaxButtonStringSize];
_TCHAR szIgnore[MaxButtonStringSize];
_TCHAR szRetry[MaxButtonStringSize];
_TCHAR szAbort[MaxButtonStringSize];
_TCHAR szHelp[MaxButtonStringSize];
_TCHAR szYes[MaxButtonStringSize];
_TCHAR szNo[MaxButtonStringSize];
_TCHAR szContinue[MaxButtonStringSize];
_TCHAR szDoNotAskAgain[MaxButtonStringSize];
_TCHAR szDoNotTellAgain[MaxButtonStringSize];
_TCHAR szYesToAll[MaxButtonStringSize];
_TCHAR szNoToAll[MaxButtonStringSize];
_TCHAR szReport[MaxButtonStringSize];
enum EOpt
{
DoNotAskAgain = 0x01, //include Do Not Ask checkbox
DoNotTellAgain = 0x02, //include Do Not Tell checkbox
CancelButton = 0x04, //include Cancel button
OkButton = 0x08, //MB_OK used
CancelOrOkButton = CancelButton | OkButton,
EDefault = 0x00
};
void Unset(EOpt id) { m_indicator &= ~id;};
void Set(EOpt id) { m_indicator |= id;};
int Option(EOpt id) const { return m_indicator & id;};
void LoadButtonStrings();
void LoadButtonStringsFromResources();
protected:
// the map is needed in the GlobalTimerProc
// to find the corresponding class for a timer-id
static CMapPtrToPtr m_mapTimerIdToClassMe;
// used to get thread-save
static CCriticalSection m_sectMap;
static void CALLBACK GlobalTimerProc(HWND hwnd, UINT uiMsg, UINT_PTR idEvent, DWORD dwTime);
HWND m_hDefaultButton;
DWORD m_dwTimeout,m_dwStarted;
UINT m_idTimer;
BOOL m_bRunning;
UINT m_DefaultReturn;
CString m_Title;
public:
const _TCHAR* MessageText() const { return m_lpszMessage;};
int& ButtonCount() { return m_nButton;};
void DefaultButtonId(UINT nDefId) { m_nDefId = nDefId;};
int DefaultButton() const { return m_nDefButton;};
//UINT MaxControlId() const ( return m_nMaxID;};
CXMessageBox(); //default const
CXMessageBox(HWND hWnd, LPCTSTR lpszMessage, UINT nStyle, UINT nHelpId);
void Init(HWND hWnd, LPCTSTR lpszMessage, UINT nStyle, UINT nHelpId);
virtual ~CXMessageBox();
int Display(LPCTSTR lpszCaption);
void AddItem(CDialogItem::Econtroltype cType,
UINT nID,
RECT* prect = NULL,
LPCTSTR pszCaption = NULL);
int XMessageBox(HWND hwnd, LPCTSTR lpszMessage,
LPCTSTR lpszCaption = NULL,
UINT uStyle = MB_OK|MB_ICONEXCLAMATION,
UINT uHelpId = 0,DWORD dwTimeOut=5000);
void GetWindowHandles(void);
void LocalTimerProc(void);
};
//#include //std::bad_alloc
//#include
//#include
//#pragma hdrstop
//#include "amsqo/QOInclude.h" // TRACE ASSERT TException Reminder QOGetAppName QOReportError
// We include our own TRACE ASSERT and a TException class.
// I include some dummy definetions to make it compilable.
#include "stdafx.h"
#include <tchar.h>
#include "XMessageBox.h"
#ifndef KLM_UTIL_AMSQO_QOINCLUDE_H
#ifndef TRACE
#define TRACE (void)0
#endif
#ifndef ASSERT
#define ASSERT (void)0
#endif
#define TException //just throw a const char*
const _TCHAR* QOGetAppName() { return _T("My Application");};
void QOReportError(const _TCHAR) {}; // function will be called in case the user.....
// ...presses the Report button. Our implementation sends an email to our support team.
#endif //KLM_UTIL_AMSQO_QOINCLUDE_H
inline const int Width(const RECT&rect) { return rect.right-rect.left;};
inline const int Height(const RECT&rect) { return rect.bottom-rect.top;};
extern BOOL AFXAPI AfxIsDescendant(HWND hWndParent, HWND hWndChild);
CMapPtrToPtr CXMessageBox::m_mapTimerIdToClassMe;
CCriticalSection CXMessageBox::m_sectMap;
int CXMessageBox::XMessageBox(HWND hwnd,LPCTSTR lpszMessage,LPCTSTR lpszCaption /* = NULL */,UINT nStyle /* = MB_OK|MB_ICONEXCLAMATION */,UINT nHelpId /* = 0 */,DWORD dwTimeOut)
{
ASSERT(lpszMessage);
if (hwnd == NULL)
{
hwnd = ::GetActiveWindow() ;
if (hwnd != NULL)
{
hwnd = ::GetLastActivePopup(hwnd) ;
}
};
if ((nStyle & MB_ICONHAND) && (nStyle & MB_SYSTEMMODAL))
{
// NOTE: When an application calls MessageBox and specifies the
// MB_ICONHAND and MB_SYSTEMMODAL flags for the nStyle parameter,
// the system displays the resulting message box regardless of
// available memory.
return ::MessageBox(hwnd, lpszMessage, lpszCaption, nStyle);
}
if (lpszCaption == NULL || lpszCaption[0] == 0)
{
lpszCaption = AfxGetApp()->m_pszAppName;
}
m_dwTimeout = dwTimeOut;
//CXMessageBox dlg(hwnd, lpszMessage, nStyle, nHelpId);
Init(hwnd, lpszMessage, nStyle, nHelpId);
if ((nStyle & MB_NOSOUND) == 0)
{
::MessageBeep(nStyle & MB_ICONMASK);
}
m_Title= lpszCaption;
int rc = Display(lpszCaption);
return rc;
}
///////////////////////////////////////////////////////////////////////////////
// IconProc
LONG CALLBACK IconProc(HWND hwnd, UINT message, WPARAM, LPARAM)
{
if (message == WM_PAINT)
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
DrawIcon(hdc, 0, 0, reinterpret_cast<hicon>(::GetWindowLong(hwnd, GWL_USERDATA)));
EndPaint(hwnd, &ps);
}
return FALSE;
}
CXMessageBox::CXMessageBox()
{
m_pDlgItemArray = NULL;
m_parentHwnd = NULL;
m_nHelpId = 0;
m_indicator = 0;
m_hIcon = NULL;
m_hFont = NULL;
m_nButton = 0; // current button no.
m_nDefId = 1; // button number of default button
m_nMaxID = 0; // control id
hLocal = NULL;
}
///////////////////////////////////////////////////////////////////////////////
// CXMessageBox class
///////////////////////////////////////////////////////////////////////////////
// CXMessageBox ctor
CXMessageBox::CXMessageBox(HWND hWnd, LPCTSTR lpszMessage, UINT nStyle, UINT nHelpId)
{
Init(hWnd,lpszMessage,nStyle,nHelpId);
}
void CXMessageBox::Init(HWND hWnd, LPCTSTR lpszMessage, UINT nStyle, UINT nHelpId)
{
if(m_pDlgItemArray == NULL)
m_pDlgItemArray = new CDialogItem *[MaxItems];
m_parentHwnd = hWnd;
m_lpszMessage = lpszMessage;
m_nHelpId = nHelpId;
m_indicator = EDefault;
m_hIcon = NULL;
m_hFont = NULL;
m_nButton = 0; // current button no.
m_nDefId = 1; // button number of default button
m_nMaxID = FirstControlId; // control id
hLocal = NULL;
m_DefaultReturn = 0;
m_hDefaultButton = NULL;
m_bRunning = FALSE;
// if (nStyle & MB_NORESOURCE)
LoadButtonStrings(); // use English strings
// else
// LoadButtonStringsFromResources(); // try to load from resource strings
HDC hdc = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
ASSERT(hdc);
// get font for message box
/*
LOGFONT lf;
memset(&lf, 0, sizeof(lf));
_tcscpy(lf.lfFaceName, _T("MS Sans Serif"));
lf.lfHeight = -12;
lf.lfWeight = FW_NORMAL;
m_hFont = ::CreateFontIndirect(&lf);
*/
NONCLIENTMETRICS ncm;
memset(&ncm, 0, sizeof(ncm));
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
m_hFont = ::CreateFontIndirect(&ncm.lfMessageFont);
HFONT hOldFont = (HFONT)::SelectObject(hdc, m_hFont);
int nMaxWidth = (::GetSystemMetrics(SM_CXSCREEN) / 2) + 100;
if (nStyle & MB_ICONMASK)
{
nMaxWidth -= GetSystemMetrics(SM_CXICON) + 2*SpacingSize;
}
RECT msgrect;
SetRect(&msgrect, 0, 0, nMaxWidth, nMaxWidth);
::DrawText(hdc, MessageText(), -1, &msgrect, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
msgrect.right += 12;
msgrect.bottom += 5;
msgrect.left = 2 * SpacingSize;
msgrect.top = 2 * SpacingSize;
msgrect.right += 2 * SpacingSize;
msgrect.bottom += 2 * SpacingSize;
// client rect
RECT mbrect;
SetRect(&mbrect, 0, 0,
Width(msgrect) + (2 * SpacingSize),
Height(msgrect) + (2 * SpacingSize));
if (Height(mbrect) < MinimalHeight)
mbrect.bottom = MinimalHeight;
// now initialize the DLGTEMPLATE structure
m_dlgTempl.x = 0;
m_dlgTempl.y = 0;
m_dlgTempl.cdit = 0;
m_dlgTempl.style = WS_CAPTION | WS_VISIBLE | WS_SYSMENU |
WS_POPUP | DS_MODALFRAME | DS_CENTER;
m_dlgTempl.dwExtendedStyle = 0;
if (nStyle & MB_SYSTEMMODAL)
{
m_dlgTempl.style |= DS_SYSMODAL;
}
for (int j = 0; j < MaxItems; j++)
{
m_pDlgItemArray[j] = NULL;
}
int x, y;
RECT iconrect;
SetRect(&iconrect, 0, 0, 0, 0);
RECT rect;
if (nStyle & MB_ICONMASK)
{
int cxIcon;
int cyIcon;
LPSTR lpIcon = NULL;
switch (nStyle & MB_ICONMASK)
{
case MB_ICONEXCLAMATION:
lpIcon = (LPSTR)IDI_EXCLAMATION;
break;
case MB_ICONHAND:
lpIcon = (LPSTR)IDI_HAND;
break;
case MB_ICONQUESTION:
lpIcon = (LPSTR)IDI_QUESTION;
break;
case MB_ICONASTERISK:
lpIcon = (LPSTR)IDI_ASTERISK;
break;
}
if (lpIcon)
{
m_hIcon = ::LoadIcon(NULL, lpIcon);
cxIcon = GetSystemMetrics(SM_CXICON);
cyIcon = GetSystemMetrics(SM_CYICON);
int icon_x = SpacingSize;
int icon_y = SpacingSize;
msgrect.left += cxIcon + icon_x;
msgrect.right += cxIcon + icon_x;
mbrect.right = msgrect.right + SpacingSize;
SetRect(&iconrect, icon_x, icon_y, icon_x + cxIcon + 2, icon_y + cyIcon + 2);
AddItem(CDialogItem::STATICTEXT, 1000, &iconrect, _T(""));
}
}
AddItem(CDialogItem::STATICTEXT, m_nMaxID++, &msgrect, MessageText());
int cItems = 0;
switch (nStyle & MB_TYPEMASK)
{
case MB_OK :
cItems = 1;
break;
case MB_OKCANCEL :
cItems = 2;
break;
case MB_YESNO :
cItems = 2;
break;
case MB_YESNOCANCEL :
cItems = 3;
break;
case MB_ABORTRETRYIGNORE :
cItems = 3;
break;
case MB_RETRYCANCEL :
cItems = 2;
break;
case MB_CONTINUEABORT :
cItems = 2;
break;
}
if (nStyle & MB_HELP)
{
cItems++;
}
if (nStyle & MB_YESTOALL)
{
if ((nStyle & MB_YESNO) || (nStyle & MB_YESNOCANCEL))
{
cItems++;
}
else
{
ASSERT(FALSE); // must have either MB_YESNO or MB_YESNOCANCEL
}
}
if (nStyle & MB_NOTOALL)
{
if ((nStyle & MB_YESNO) || (nStyle & MB_YESNOCANCEL))
{
cItems++;
}
else
{
ASSERT(FALSE); // must have either MB_YESNO or MB_YESNOCANCEL
}
}
if (nStyle & MB_REPORT)
{
cItems++;
}
if (nStyle & MB_DONOTASKAGAIN)
{
Set(DoNotAskAgain);
}
else if (nStyle & MB_DONOTTELLAGAIN)
{
Set(DoNotTellAgain);
};
ASSERT(cItems > 0);
RECT buttonrow;
y = (msgrect.bottom > iconrect.bottom) ? msgrect.bottom : iconrect.bottom;
y += SpacingSize;
int w = ButtonWidth * cItems + (ButtonSpacing * (cItems - 1));
SetRect(&buttonrow,0, y, w,
y + ButtonHeight);
switch (nStyle & MB_DEFMASK)
{
case MB_DEFBUTTON1 :
m_nDefButton = 1;
break;
case MB_DEFBUTTON2 :
m_nDefButton = 2;
break;
case MB_DEFBUTTON3 :
m_nDefButton = 3;
break;
case MB_DEFBUTTON4 :
m_nDefButton = 4;
break;
case MB_DEFBUTTON5 :
m_nDefButton = 5;
break;
case MB_DEFBUTTON6 :
m_nDefButton = 6;
break;
default:
m_nDefButton = 1;
}
if (m_nDefButton > cItems)
{
m_nDefButton = 1;
}
x = (Width(mbrect) - Width(buttonrow)) / 2;
mbrect.bottom = buttonrow.bottom + BottomMargin;
int bw = Width(buttonrow);
int bleft = 2 * SpacingSize;
int bright = bleft + bw;
if (mbrect.right <= (bright + (2 * SpacingSize)))
{
mbrect.right = bright + (2 * SpacingSize);
}
x = (Width(mbrect) - bw) / 2;
y = buttonrow.top;
switch (nStyle & MB_TYPEMASK)
{
case MB_OK:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDOK, &rect, szOK);
Set(OkButton);
break;
case MB_OKCANCEL:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDOK, &rect, szOK);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDCANCEL, &rect, szCancel);
Set(CancelButton);
break;
case MB_YESNO:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDYES, &rect, szYes);
if (nStyle & MB_YESTOALL)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDYESTOALL, &rect, szYesToAll);
}
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDNO, &rect, szNo);
if (nStyle & MB_NOTOALL)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDNOTOALL, &rect, szNoToAll);
}
break;
case MB_YESNOCANCEL:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDYES, &rect, szYes);
if (nStyle & MB_YESTOALL)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDYESTOALL, &rect, szYesToAll);
}
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDNO, &rect, szNo);
if (nStyle & MB_NOTOALL)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDNOTOALL, &rect, szNoToAll);
}
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDCANCEL, &rect, szCancel);
Set(CancelButton);
break;
case MB_ABORTRETRYIGNORE:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDABORT, &rect, szAbort);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDRETRY, &rect, szRetry);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDIGNORE, &rect, szIgnore);
break;
case MB_RETRYCANCEL:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDRETRY, &rect, szRetry);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDCANCEL, &rect, szCancel);
Set(CancelButton);
break;
case MB_CONTINUEABORT:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDCONTINUE, &rect, szContinue);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDABORT, &rect, szAbort);
break;
default:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDOK, &rect, szOK);
break;
}
if (nStyle & MB_HELP)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IdExHelp, &rect, szHelp);
}
nMaxWidth = ::GetSystemMetrics(SM_CXSCREEN) / 3;
RECT checkboxrect;
SetRect(&checkboxrect,0, 0, nMaxWidth, DoNotAskAgainHeight);
if (nStyle & MB_DONOTASKAGAIN)
{
x = 2 * ButtonSpacing + 5;
y += ButtonHeight + (2 * ButtonSpacing);
::DrawText(hdc, szDoNotAskAgain, -1, &checkboxrect,
DT_LEFT | DT_NOPREFIX | DT_CALCRECT | DT_SINGLELINE);
int w = checkboxrect.right - checkboxrect.left;
w += w/3;
//rect.SetRect(x, y, x + MSGBOXEX_DONOTASKAGAIN_WIDTH, y + DoNotAskAgainHeight);
SetRect(&rect,x, y, x + w, y + DoNotAskAgainHeight);
AddItem(CDialogItem::CHECKBOX, IdDoNotAskAgian, &rect, szDoNotAskAgain);
buttonrow.bottom = y + DoNotAskAgainHeight;
mbrect.bottom = buttonrow.bottom + SpacingSize;
if (Width(mbrect) < (x + w))
mbrect.right = mbrect.left + x + w;
}
else if (nStyle & MB_DONOTTELLAGAIN)
{
x = 2 * ButtonSpacing + 5;
y += ButtonHeight + (2 * ButtonSpacing);
::DrawText(hdc, szDoNotTellAgain, -1, &checkboxrect,
DT_LEFT | DT_NOPREFIX | DT_CALCRECT | DT_SINGLELINE);
int w = checkboxrect.right - checkboxrect.left;
w += w/3;
//rect.SetRect(x, y, x + MSGBOXEX_DONOTASKAGAIN_WIDTH, y + DoNotAskAgainHeight);
SetRect(&rect,x, y, x + w, y + DoNotAskAgainHeight);
AddItem(CDialogItem::CHECKBOX, IdDoNotAskAgian, &rect, szDoNotTellAgain);
buttonrow.bottom = y + DoNotAskAgainHeight;
mbrect.bottom = buttonrow.bottom + SpacingSize;
if (Width(mbrect) < (x + w))
{
mbrect.right = mbrect.left + x + w;
}
}
if (nStyle & MB_REPORT)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IdExReport, &rect, szReport);
}
if (buttonrow.bottom >= mbrect.bottom)
{
mbrect.bottom = buttonrow.bottom + (2 * SpacingSize);
}
if (mbrect.right < (buttonrow.right + (2 * SpacingSize)))
{
mbrect.right = buttonrow.right + (2 * SpacingSize);
}
short hidbu = HIWORD(GetDialogBaseUnits());
short lodbu = LOWORD(GetDialogBaseUnits());
m_dlgTempl.x = 0;
m_dlgTempl.y = 0;
m_dlgTempl.cx = (short)((Width(mbrect) * 4) / lodbu);
m_dlgTempl.cy = (short)((Height(mbrect) * 8) / hidbu);
::SelectObject(hdc, hOldFont);
::DeleteDC(hdc);
}
///////////////////////////////////////////////////////////////////////////////
// CXMessageBox dtor
CXMessageBox::~CXMessageBox()
{
if (m_hIcon)
{
DestroyIcon(m_hIcon);
}
if (m_hFont)
{
::DeleteObject(m_hFont);
}
for (int i = 0; i < MaxItems; i++)
{
if (m_pDlgItemArray[i])
{
delete m_pDlgItemArray[i];
m_pDlgItemArray[i] = NULL;
}
}
delete m_pDlgItemArray;
if(hLocal != NULL)
{
LocalUnlock(hLocal);
LocalFree(hLocal);
}
CXMessageBox::m_sectMap.Lock();
{
::KillTimer(NULL, m_idTimer);
m_idTimer = 0;
CXMessageBox::m_mapTimerIdToClassMe.RemoveKey((void*)m_idTimer);
}
CXMessageBox::m_sectMap.Unlock();
}
///////////////////////////////////////////////////////////////////////////////
// LoadButtonStrings
void CXMessageBox::LoadButtonStrings()
{
_tcscpy(szOK, _T("OK"));
_tcscpy(szCancel, _T("Cancel"));
_tcscpy(szIgnore, _T("&Ignore"));
_tcscpy(szRetry, _T("&Retry"));
_tcscpy(szAbort, _T("&Abort"));
_tcscpy(szHelp, _T("&Help"));
_tcscpy(szYes, _T("&Yes"));
_tcscpy(szNo, _T("&No"));
_tcscpy(szContinue, _T("&Continue"));
_tcscpy(szDoNotAskAgain, _T("Don't ask me again"));
_tcscpy(szDoNotTellAgain, _T("Don't tell me again"));
_tcscpy(szYesToAll, _T("Yes to &All"));
_tcscpy(szNoToAll, _T("No to A&ll"));
_tcscpy(szReport, _T("Re&port"));
}
///////////////////////////////////////////////////////////////////////////////
// LoadButtonStringsFromResources
void CXMessageBox::LoadButtonStringsFromResources()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
if (::LoadString(hInstance, IDS_OK, szOK, MaxButtonStringSize) == 0)
{
_tcscpy(szOK, _T("OK"));
}
szOK[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_CANCEL, szCancel, MaxButtonStringSize) == 0)
{
_tcscpy(szCancel, _T("Cancel"));
}
szCancel[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_IGNORE, szIgnore, MaxButtonStringSize) == 0)
{
_tcscpy(szIgnore, _T("&Ignore"));
}
szIgnore[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_RETRY, szRetry, MaxButtonStringSize) == 0)
{
_tcscpy(szRetry, _T("&Retry"));
}
szRetry[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_ABORT, szAbort, MaxButtonStringSize) == 0)
{
_tcscpy(szAbort, _T("&Abort"));
}
szAbort[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_HELP, szHelp, MaxButtonStringSize) == 0)
{
_tcscpy(szHelp, _T("&Help"));
}
szHelp[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_YES, szYes, MaxButtonStringSize) == 0)
{
_tcscpy(szYes, _T("&Yes"));
}
szYes[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_NO, szNo, MaxButtonStringSize) == 0)
{
_tcscpy(szNo, _T("&No"));
}
szNo[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_CONTINUE, szContinue, MaxButtonStringSize) == 0)
{
_tcscpy(szContinue, _T("&Continue"));
}
szContinue[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_DONOTASKAGAIN, szDoNotAskAgain, MaxButtonStringSize) == 0)
{
_tcscpy(szDoNotAskAgain, _T("Don't ask me again"));
}
szDoNotAskAgain[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_DONOTTELLAGAIN, szDoNotTellAgain, MaxButtonStringSize) == 0)
{
_tcscpy(szDoNotTellAgain, _T("Don't tell me again"));
}
szDoNotTellAgain[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_YESTOALL, szYesToAll, MaxButtonStringSize) == 0)
{
_tcscpy(szYesToAll, _T("Yes to &All"));
}
szYesToAll[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_NOTOALL, szNoToAll, MaxButtonStringSize) == 0)
{
_tcscpy(szNoToAll, _T("No to A&ll"));
}
szNoToAll[MaxButtonStringSize-1] = _T('\0');
}
///////////////////////////////////////////////////////////////////////////////
// MsgBoxDlgProc
BOOL CALLBACK CXMessageBox::MsgBoxDlgProc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
CXMessageBox* Me = reinterpret_cast<cxmessagebox*>(::GetWindowLong(hwnd, GWL_USERDATA));
HWND hwndChild;
switch (message)
{
case WM_INITDIALOG:
{
::SetWindowLong(hwnd, GWL_USERDATA, lParam); // safe it for the others
Me = reinterpret_cast<cxmessagebox*>(lParam);
HDC hdc = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
ASSERT(hdc);
::SelectObject(hdc, Me->m_hFont);
::DeleteDC(hdc);
UINT nID;
for (nID = FirstControlId; nID < Me->m_nMaxID; nID++)
{
hwndChild = ::GetDlgItem(hwnd, nID);
if (::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
}
else
{
break;
}
}
for (nID = 1; nID < 18; nID++)
{
hwndChild = ::GetDlgItem(hwnd, nID);
if (hwndChild && ::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
}
}
hwndChild = ::GetDlgItem(hwnd, IdExHelp);
if (hwndChild && ::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
}
hwndChild = ::GetDlgItem(hwnd, IdDoNotAskAgian);
if (hwndChild && ::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
CheckDlgButton(hwnd, IdDoNotAskAgian, 0);
}
hwndChild = ::GetDlgItem(hwnd, IdExReport);
if (hwndChild && ::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
}
hwndChild = ::GetDlgItem(hwnd, Me->m_nDefId);
if (hwndChild && ::IsWindow(hwndChild))
{
::SetFocus(hwndChild);
}
// disable close button just like real MessageBox
if (!Me->Option(CancelOrOkButton))
{
EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_CLOSE, MF_GRAYED);
};
if (Me->m_hIcon)
{
HWND hwndIcon;
hwndIcon = ::GetDlgItem(hwnd, 1000);
::SetWindowLong(hwndIcon, GWL_WNDPROC, reinterpret_cast<long>(IconProc));
::SetWindowLong(hwndIcon, GWL_USERDATA, reinterpret_cast<long>(Me->m_hIcon));
}
return FALSE;
}
case WM_CLOSE:
return TRUE;
case WM_DESTROY:
{
delete Me;
Me = NULL;
return TRUE;
}
case WM_COMMAND:
{
switch(wParam)
{
case IDCLOSE:
return TRUE;
case IDCANCEL:
if (Me->Option(CancelButton))
{
::SetWindowLong(hwnd,DWL_MSGRESULT,IDCANCEL);
::EndDialog(hwnd, IDCANCEL);
}
else if (Me->Option(OkButton))
{
SetWindowLong(hwnd,DWL_MSGRESULT,IDOK);
::EndDialog(hwnd, IDOK);
}
DestroyWindow(hwnd);
return TRUE;
case IdExHelp:
{
_TCHAR szBuf[_MAX_PATH*2];
szBuf[0] = 0;
GetModuleFileName(NULL, szBuf, (sizeof(szBuf)/sizeof(szBuf[0])) - 1); //AfxGetInstanceHandle()
if (strlen(szBuf) > 0)
{
_TCHAR *cp = _tcsrchr(szBuf, _T('.'));
if (cp)
{
_tcscpy(cp, _T(".hlp"));
::WinHelp(hwnd, szBuf,
(Me->m_nHelpId == 0) ? HELP_PARTIALKEY : HELP_CONTEXT,
Me->m_nHelpId);
}
}
return FALSE;
}
case IdExReport:
{
// OReportError(Me->MessageText());
//QODumpStack(Me->MessageText());
return FALSE;
}
case IdDoNotAskAgian: //IdDoNotAskAgian & DoNotTellAgain share the same id!!
return FALSE;
default:
//if (wParam != IdExHelp && wParam != IdDoNotAskAgian)
{
hwndChild = ::GetDlgItem(hwnd, IdDoNotAskAgian);
BOOL bFlag = FALSE;
if (hwndChild && ::IsWindow(hwndChild))
{
bFlag = ::SendMessage(hwndChild, BM_GETCHECK, 0, 0);
}
if (Me->Option(DoNotAskAgain))
{
wParam |= bFlag ? MB_DONOTASKAGAIN : 0;
}
else if (Me->Option(DoNotTellAgain))
{
wParam |= bFlag ? MB_DONOTTELLAGAIN : 0;
}
SetWindowLong(hwnd,DWL_MSGRESULT,wParam);
::EndDialog(hwnd, wParam);
DestroyWindow(hwnd);
}
return FALSE;
}
}
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
// CXMessageBox::AddItem
void CXMessageBox::AddItem(CDialogItem::Econtroltype cType, UINT nID, RECT* prect, LPCTSTR pszCaption)
{
ASSERT(m_pDlgItemArray[m_dlgTempl.cdit] == NULL);
CDialogItem::Econtroltype ct = cType;
if (ct == CDialogItem::CHECKBOX)
{
ct = CDialogItem::BUTTON;
}
m_pDlgItemArray[m_dlgTempl.cdit] = new CDialogItem(ct);
ASSERT(m_pDlgItemArray[m_dlgTempl.cdit]);
m_pDlgItemArray[m_dlgTempl.cdit]->AddItem(*this, cType, nID, prect, pszCaption);
m_dlgTempl.cdit++;
ASSERT(m_dlgTempl.cdit < MaxItems);
}
///////////////////////////////////////////////////////////////////////////////
// CXMessageBox::Display
int CXMessageBox::Display(LPCTSTR lpszCaption)
{
// The first step is to allocate memory to define the dialog. The information to be
// stored in the allocated buffer is the following:
//
// 1. DLGTEMPLATE structure
// typedef struct
// {
// DWORD style;
// DWORD dwExtendedStyle;
// WORD cdit;
// short x;
// short y;
// short cx;
// short cy;
// } DLGTEMPLATE;
// 2. 0x0000 (Word) indicating the dialog has no menu
// 3. 0x0000 (Word) Let windows assign default class to the dialog
// 4. (Caption) Null terminated unicode string
// 5. 0x000B (size of the font to be used)
// 6. "MS Sans Serif" (name of the typeface to be used)
// 7. DLGITEMTEMPLATE structure for the button (HAS TO BE DWORD ALIGNED)
// typedef struct
// {
// DWORD style;
// DWORD dwExtendedStyle;
// short x;
// short y;
// short cx;
// short cy;
// WORD id;
// } DLGITEMTEMPLATE;
// 8. 0x0080 to indicate the control is a button
// 9. (Title). Unicode null terminated string with the caption
// 10. 0x0000 0 extra bytes of data for this control
// 11. DLGITEMTEMPLATE structure for the Static Text (HAS TO BE DWORD ALIGNED)
// 12. 0x0081 to indicate the control is static text
// 13. (Title). Unicode null terminated string with the text
// 14 0x0000. 0 extra bytes of data for this control
int rc = IDCANCEL;
_TCHAR szTitle[1024];
_tcsncpy(szTitle, lpszCaption, (sizeof(szTitle)/sizeof(szTitle[0]))-1);
szTitle[(sizeof(szTitle)/sizeof(szTitle[0]))-1] = _T('\0');
int nTitleLen = _tcslen(szTitle);
int i;
TRY // catch memory exceptions and don't worry about allocation failures
{
int nBufferSize = sizeof(DLGTEMPLATE) +
(2 * sizeof(WORD)) + // menu and class
((nTitleLen + 1) * sizeof(WCHAR));
// NOTE - font is set in MsgBoxDlgProc
nBufferSize = (nBufferSize + 3) & ~3; // adjust size to make
// first control DWORD aligned
// loop to calculate size of buffer we need -
// add size of each control:
// sizeof(DLGITEMTEMPLATE) +
// sizeof(WORD) + // atom value flag 0xFFFF
// sizeof(WORD) + // ordinal value of control's class
// sizeof(WORD) + // no. of bytes in creation data array
// sizeof title in WCHARs
for (i = 0; i < m_dlgTempl.cdit; i++)
{
int nItemLength = sizeof(DLGITEMTEMPLATE) + 3 * sizeof(WORD);
int nChars = _tcslen(m_pDlgItemArray[i]->m_szCaption) + 1;
nItemLength += nChars * sizeof(WCHAR);
if (i != m_dlgTempl.cdit - 1) // the last control does not need extra bytes
{
nItemLength = (nItemLength + 3) & ~3; // take into account gap
} // so next control is DWORD aligned
nBufferSize += nItemLength;
}
hLocal = LocalAlloc(LHND, nBufferSize);
if (hLocal == NULL)
{
throw TException("XMessageBox: Out of memory");
}
BYTE* pBuffer = (BYTE*)LocalLock(hLocal);
if (pBuffer == NULL)
{
LocalFree(hLocal);
throw TException("XMessageBox: Lock failed");
}
BYTE* pdest = pBuffer;
// transfer DLGTEMPLATE structure to the buffer
memcpy(pdest, &m_dlgTempl, sizeof(DLGTEMPLATE));
pdest += sizeof(DLGTEMPLATE);
*(WORD*)pdest = 0; // no menu
*(WORD*)(pdest + 1) = 0; // use default window class
pdest += 2 * sizeof(WORD);
// transfer title
WCHAR* pchCaption;
int nActualChars;
pchCaption = new WCHAR[nTitleLen + 1];
nActualChars = MultiByteToWideChar(CP_ACP, 0, szTitle, -1, pchCaption, nTitleLen + 1);
ASSERT(nActualChars > 0);
memcpy(pdest, pchCaption, nActualChars * sizeof(WCHAR));
pdest += nActualChars * sizeof(WCHAR);
delete pchCaption;
// will now transfer the information for each one of the item templates
for (i = 0; i < m_dlgTempl.cdit; i++)
{
pdest = (BYTE*)(((DWORD)pdest + 3) & ~3); // make the pointer DWORD aligned
memcpy(pdest, (void *)&m_pDlgItemArray[i]->m_dlgItemTemplate, sizeof(DLGITEMTEMPLATE));
pdest += sizeof(DLGITEMTEMPLATE);
*(WORD*)pdest = 0xFFFF; // indicating atom value
pdest += sizeof(WORD);
*(WORD*)pdest = (WORD)m_pDlgItemArray[i]->m_controltype; // atom value for the control
pdest += sizeof(WORD);
// transfer the caption even when it is an empty string
WCHAR* pchCaption;
int nChars = _tcslen(m_pDlgItemArray[i]->m_szCaption) + 1;
pchCaption = new WCHAR[nChars];
int nActualChars = MultiByteToWideChar(CP_ACP, 0,
m_pDlgItemArray[i]->m_szCaption, -1, pchCaption, nChars);
ASSERT(nActualChars > 0);
memcpy(pdest, pchCaption, nActualChars * sizeof(WCHAR));
pdest += nActualChars * sizeof(WCHAR);
delete pchCaption;
*(WORD*)pdest = 0; // How many bytes in data for control
pdest += sizeof(WORD);
}
ASSERT(pdest - pBuffer == nBufferSize); // just make sure we did not overrun the heap
HINSTANCE hInstance = GetModuleHandle(NULL);
//rc = ::DialogBoxIndirectParam(hInstance, reinterpret_cast<lpdlgtemplate>(pBuffer),
//m_parentHwnd, MsgBoxDlgProc, reinterpret_cast<lparam>(this));
m_hWnd = ::CreateDialogIndirectParam(hInstance, reinterpret_cast<lpdlgtemplate>(pBuffer),m_parentHwnd, MsgBoxDlgProc, reinterpret_cast<lparam>(this));
// start timer
CXMessageBox::m_sectMap.Lock();
{
m_idTimer = ::SetTimer(NULL, 0, 1000, (TIMERPROC) CXMessageBox::GlobalTimerProc);
CXMessageBox::m_mapTimerIdToClassMe.SetAt((void*)m_idTimer, this);
}
CXMessageBox::m_sectMap.Unlock();
// show MessageBox
m_bRunning = TRUE;
m_dwStarted = ::GetTickCount();
ShowWindow(m_hWnd,SW_SHOW);
}
CATCH (CMemoryException, e)
{
/*::MessageBox(m_parentHwnd, _T("Memory allocation for dialog template failed."),e->,
MB_ICONEXCLAMATION | MB_OK);*/
e->ReportError();
rc = IDCANCEL;
}
END_CATCH
return rc;
}
///////////////////////////////////////////////////////////////////////////////
// CDialogItem class
///////////////////////////////////////////////////////////////////////////////
// CDialogItem ctor
CDialogItem::CDialogItem(CDialogItem::Econtroltype ctrlType)
{
m_controltype = ctrlType;
}
///////////////////////////////////////////////////////////////////////////////
// CDialogItem::AddItem
void CDialogItem::AddItem(CXMessageBox& dialog, Econtroltype ctrltype, UINT nID, RECT* prect, LPCTSTR lpszCaption)
{
short hidbu = HIWORD(GetDialogBaseUnits());
short lodbu = LOWORD(GetDialogBaseUnits());
// first fill in the type, location and size of the control
m_controltype = ctrltype;
if (m_controltype == CHECKBOX)
{
m_controltype = BUTTON;
}
if (prect != NULL)
{
m_dlgItemTemplate.x = (short)((prect->left * 4) / lodbu);
m_dlgItemTemplate.y = (short)((prect->top * 8) / hidbu);
m_dlgItemTemplate.cx = (short)((Width(*prect) * 4) / lodbu);
m_dlgItemTemplate.cy = (short)((Height(*prect) * 8) / hidbu);
}
else
{
m_dlgItemTemplate.x = 0;
m_dlgItemTemplate.y = 0;
m_dlgItemTemplate.cx = 10; // some useless default
m_dlgItemTemplate.cy = 10;
}
m_dlgItemTemplate.dwExtendedStyle = 0;
m_dlgItemTemplate.id = (WORD)nID;
switch (ctrltype)
{
case ICON:
m_dlgItemTemplate.style = WS_CHILD | SS_ICON | WS_VISIBLE;
break;
case BUTTON:
dialog.ButtonCount()++;
m_dlgItemTemplate.style = WS_VISIBLE | WS_CHILD | WS_TABSTOP;
if (dialog.ButtonCount() == dialog.DefaultButton())
{
m_dlgItemTemplate.style |= BS_DEFPUSHBUTTON;
dialog.DefaultButtonId(nID);
}
else
{
m_dlgItemTemplate.style |= BS_PUSHBUTTON;
}
break;
case CHECKBOX:
m_dlgItemTemplate.style = WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_AUTOCHECKBOX;
break;
case EDITCONTROL:
m_dlgItemTemplate.style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE | ES_LEFT;
break;
case STATICTEXT:
m_dlgItemTemplate.style = WS_CHILD | WS_VISIBLE | SS_LEFT;
break;
default:
ASSERT(FALSE); // should never get here
}
_tcsncpy(m_szCaption, (lpszCaption != NULL) ? lpszCaption : _T(""), (sizeof(m_szCaption)/sizeof(m_szCaption[0]))-1);
m_szCaption[(sizeof(m_szCaption)/sizeof(m_szCaption[0]))-1] = _T('\0');
}
void CALLBACK CXMessageBox::GlobalTimerProc(HWND hwnd, UINT uiMsg, UINT_PTR idEvent, DWORD dwTime)
{
//TRACE("Global timer with id=%u\n", idEvent);
CXMessageBox *pMe = NULL;
// Find the corresponding class by the timer-id
CXMessageBox::m_sectMap.Lock();
{
CXMessageBox::m_mapTimerIdToClassMe.Lookup((void*)idEvent, (void *&) pMe);
}
CXMessageBox::m_sectMap.Unlock();
if( pMe!=NULL )
pMe->LocalTimerProc();
}
void CXMessageBox::LocalTimerProc(void)
{
//TRACE("Local timer with id=%u (%s)\n", m_idTimer, m_Title);
if( !m_bRunning )
return;
// lookup the handles
GetWindowHandles();
if( !m_hWnd )
return;
DWORD now = GetTickCount()-m_dwStarted;
if( now >= (m_dwTimeout) )
{
// done with the box
// m_bStoppedByTimer = TRUE;
::PostMessage(m_hWnd, WM_COMMAND, (WPARAM) m_DefaultReturn, (LPARAM) m_hDefaultButton);
}
}
void CXMessageBox::GetWindowHandles(void)
{
HWND hWnd;
CWnd *pWnd;
CString title;
CPtrList allButtons;
//
// Handle of the messageBox
//
if( !m_hWnd )
{
hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
while( (hWnd!=NULL) )
{
pWnd = CWnd::FromHandle(hWnd);
pWnd->GetWindowText(title);
if( AfxIsDescendant(m_parentHwnd, hWnd) && ::IsWindowVisible(hWnd) && (m_Title.CompareNoCase(title)==0) )
{
m_hWnd = hWnd;
break;
}
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}
}
//
// Handle of the static text
// TODO only if text-replace is needed
//
if( m_hWnd )
{
// not sure if this will work always
// under Win2000 it did
//m_hStaticText = ::GetDlgItem(m_hMsgBox, 0xFFFF);
// not sure, so lets find it dynamically!
char className[_MAX_PATH];
CString classNameOk("STATIC");
LONG id;
hWnd = ::GetWindow(m_hWnd, GW_CHILD);
while( (hWnd!=NULL) )
{
id = ::GetWindowLong(hWnd, GWL_ID);
// small ids only for buttons
if( id > IDHELP )
{
if( ::GetClassName(hWnd, className, _MAX_PATH) )
{
// looking only for a static
if( classNameOk.CompareNoCase(className) == 0 )
{
// not check the text
pWnd = CWnd::FromHandle(hWnd);
pWnd->GetWindowText(title);
/*if( m_CurrentMessage.CompareNoCase(title) == 0 )
{
m_hStaticText = hWnd;
break;
}*/
}
}
}
else
{
allButtons.AddTail(hWnd);
}
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}
}
//
// Handle of the default button
//
if( m_hWnd && !m_hDefaultButton )
{
m_hDefaultButton = ::GetDlgItem(m_hWnd, m_DefaultReturn);
// Problem: (reported from Keith Brown)
// if generated with MB_OK the button has NOT IDOK, but IDCANCEL !!
// then lets take the first button we find !
// (with and IDCANCEL this works, because it is the only button
// if this problem encounters also with 2 buttons, I have no chance
// to find out which one is the better one!)
while( allButtons.GetCount()>0 && !m_hDefaultButton )
{
m_hDefaultButton = (HWND) allButtons.GetHead();
allButtons.RemoveHead();
if( m_hDefaultButton )
m_DefaultReturn = ::GetWindowLong(m_hDefaultButton, GWL_ID);
}
}
}
Best Wishes,
Uma Mahes
|
|
|
|
|
Thanks for sharing this.
I was curious why you would want it modeless?
Best wishes,
Hans
|
|
|
|
|
My Project is Client Server communication. Server sends Error Message
to the Client. Client will Popup the MessageBox and server will wait till
to get the Response from the client.If the Client doesn't response,
server will be deadlocked state. So i need to implement same like a
modelss MessageBox with timer. I found your fantastic article and changed
it to my own way.
Regards,
Uma
|
|
|
|
|
The text of common dialogs like File Open is in the(/an) OS language,
i.e. only one language is used, maybe not the one the user would prefer,
maybe not the one used by the invoking application.
MessageBox (and AfxMessageBox) mix things up,
with the message text coming from the application
and the button text from the OS.
Having two languages in the one interaction is something that
international users have maybe come to accept/ignore/overlook,
but to me it makes a shoddy (and schizophrenic) impression.
It also prevents the meticulous designer from using message texts like
"If <bla bla>, press Yes"
I tried out XMessageBox because it offers the possibility of forcing
the button text to be in the same language as the message text.
It has a bug here: LoadButtonStringsFromResources uses ghInst.
If the application switches languages e.g. by loading a resource dll,
the message text is in the dll language but
the button text stays in the exe language.
To correct this, use the resource handle instead:
static void LoadButtonStringsFromResources()
{
HINSTANCE hRes=AfxGetResourceHandle();
if (::LoadString(hRes, IDS_OK, szOK, MAXBUTTONSTRING) == 0)
repeatedly passing hRes to LoadString instead of ghInst.
Robin Bannister
|
|
|
|
|
The file afxpriv.h contains useful classes that are documented only in the MFC Technical Notes. These classes may change from version to version.
If you are including "afxpriv.h" into your project then you have to rename CDialogTemplate in XMessageBox.cpp as it is implemented in these useful MFC classes in "afxpriv.h". Atleast in MFC 4.2 (MSDEV 6).
ook
|
|
|
|
|
Hi,
just to let you know that IDCONTINUE is now defined in the november 2001 platform SDK update, so yours is in conflict with it.
Regards
Nicolas Cadilhac
CAE Inc.
|
|
|
|
|
longer-labeled check-boxes are better with
#if 0 //t!
w += w/3;
#else
w += (checkboxrect.bottom - checkboxrect.top) * 2;
#endif
(and still better with big fonts too, i hope noone will set smaller ones; generaly: it has not depend on font size but i do not know how to find system-defined box size and box-text-distance; what about control and dialog resizing after their creation?)
t!
|
|
|
|
|
Hi Hans,
Thank you for your usefull code.
I have adjusted the code to suit our project needs. Things I did were:
- making it MFC free
- removing of all static/global variables. so you can use it in case you have more msg boxes at one time (in e.g. a multithreaded app)
- addition of Report button
- correct character counts in case _TCHAR is multi-byte
- make the messagebox, in case called with parentwnd NULL, a child of the current active window
Add this line to the header
#define MB_REPORT 0x20000000L // Add a report button
New implementatation of XMessageBox.cpp
// XMessageBox.cpp
//
// Original Author: Hans Dietrich
// hdietrich2@hotmail.com
//
// Some parts of this software are from information in the
// Microsoft SDK.
// Code downloaded from The Code Project http://codeproject.com or http://thecodeproject.com
//
// This software is released into the public domain.
// You are free to use it in any way you like.
//
// This software is provided "as is" with no expressed
// or implied warranty. I accept no liability for any
// damage or loss of business that this software may cause.
//
// Code is adjusted by Anne Jan Beeks
// - making it MFC free
// - removing of static variables. so you can use it in case you have more boxes at one time
// Which could happen in a Multithread app
// - addition of Report button
// - correct character counts in case _TCHAR is multi-byte
// - make the messagebox, in case called with parent-wnd NULL, a child of the current active window
//
///////////////////////////////////////////////////////////////////////////////
#include <new> //std::bad_alloc
#include <windows.h>
#include <tchar.h>
#pragma hdrstop
//#include "amsqo/QOInclude.h" // TRACE ASSERT TException Reminder QOGetAppName QOReportError
// We include our own TRACE ASSERT and a TException class.
// I include some dummy definetions to make it compilable.
#ifndef KLM_UTIL_AMSQO_QOINCLUDE_H
#ifndef TRACE
#define TRACE (void)0
#endif
#ifndef ASSERT
#define ASSERT (void)0
#endif
#define TException //just throw a const char*
const _TCHAR* QOGetAppName() { return _T("My Application");};
void QOReportError(const _TCHAR* /*errortext*/) {}; // function will be called in case the user.....
// ...presses the Report button. Our implementation sends an email to our support team.
#endif //KLM_UTIL_AMSQO_QOINCLUDE_H
#include "XMessageBox.h"
inline const int Width(const RECT&rect) { return rect.right-rect.left;};
inline const int Height(const RECT&rect) { return rect.bottom-rect.top;};
///////////////////////////////////////////////////////////////////////////////
//
// Class definitions
//
class CDialogTemplate;
class CDialogItem
{
public:
DLGITEMTEMPLATE m_dlgItemTemplate;
enum Econtroltype {ICON = 0x7F, BUTTON, EDITCONTROL, STATICTEXT, CHECKBOX};
Econtroltype m_controltype;
_TCHAR m_szCaption[1024];
public:
CDialogItem(Econtroltype cType); // default constructor will fill in default values
CDialogItem() {}; // default constructor, not to be called directly
void AddItem(CDialogTemplate& dialog, Econtroltype cType,
UINT nID,
RECT* prect = NULL,
LPCTSTR pszCaption = NULL);
};
class CDialogTemplate
{
protected:
enum { FirstControlId = 1001};
enum { MaxButtonStringSize = 100};
enum
{
SpacingSize = 8,
ButtonWidth = 82,
ButtonHeight = 23,
ButtonSpacing = 6,
BottomMargin = 10,
MinimalHeight = 70,
DoNotAskAgainHeight = 16,
IdExHelp = 300,
IdExReport = 301,
IdDoNotAskAgian = 5555,
// if you change the value for MaxItems, make sure that the code
// in CDialogTemplate remains consistent with your changes.
MaxItems = 20, // max no. of items in the dialog
};
CDialogItem* m_pDlgItemArray[MaxItems];
static BOOL CALLBACK MsgBoxDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM me);
int m_indicator;
int m_nButton; // current button no.
int m_nDefButton; // Default button
UINT m_nMaxID; // max control id (one more)
UINT m_nDefId; // button number of default button
UINT m_nHelpId; // help context id
HWND m_hWnd; // handle of owner window
const _TCHAR* m_lpszMessage; // The message retain pointer for Report functiom
HICON m_hIcon; // Handle of icon
HANDLE m_hFont; // handle to font for the message box
DLGTEMPLATE m_dlgTempl; // message box dialog template
_TCHAR szOK[MaxButtonStringSize];
_TCHAR szCancel[MaxButtonStringSize];
_TCHAR szIgnore[MaxButtonStringSize];
_TCHAR szRetry[MaxButtonStringSize];
_TCHAR szAbort[MaxButtonStringSize];
_TCHAR szHelp[MaxButtonStringSize];
_TCHAR szYes[MaxButtonStringSize];
_TCHAR szNo[MaxButtonStringSize];
_TCHAR szContinue[MaxButtonStringSize];
_TCHAR szDoNotAskAgain[MaxButtonStringSize];
_TCHAR szDoNotTellAgain[MaxButtonStringSize];
_TCHAR szYesToAll[MaxButtonStringSize];
_TCHAR szNoToAll[MaxButtonStringSize];
_TCHAR szReport[MaxButtonStringSize];
enum EOpt
{
DoNotAskAgain = 0x01, //include Do Not Ask checkbox
DoNotTellAgain = 0x02, //include Do Not Tell checkbox
CancelButton = 0x04, //include Cancel button
OkButton = 0x08, //MB_OK used
CancelOrOkButton = CancelButton | OkButton,
EDefault = 0x00
};
void Unset(EOpt id) { m_indicator &= ~id;};
void Set(EOpt id) { m_indicator |= id;};
int Option(EOpt id) const { return m_indicator & id;};
void LoadButtonStrings();
void LoadButtonStringsFromResources();
public:
const _TCHAR* MessageText() const { return m_lpszMessage;};
int& ButtonCount() { return m_nButton;};
void DefaultButtonId(UINT nDefId) { m_nDefId = nDefId;};
int DefaultButton() const { return m_nDefButton;};
//UINT MaxControlId() const ( return m_nMaxID;};
CDialogTemplate(HWND hWnd, LPCTSTR lpszMessage, UINT nStyle, UINT nHelpId);
virtual ~CDialogTemplate();
int Display(LPCTSTR lpszCaption);
void AddItem(CDialogItem::Econtroltype cType,
UINT nID,
RECT* prect = NULL,
LPCTSTR pszCaption = NULL);
};
int XMessageBox(HWND hwnd,
LPCTSTR lpszMessage,
LPCTSTR lpszCaption /* = NULL */,
UINT nStyle /* = MB_OK|MB_ICONEXCLAMATION */,
UINT nHelpId /* = 0 */)
{
ASSERT(lpszMessage);
if (hwnd == NULL)
{
hwnd = ::GetActiveWindow() ;
if (hwnd != NULL)
{
hwnd = ::GetLastActivePopup(hwnd) ;
}
};
if ((nStyle & MB_ICONHAND) && (nStyle & MB_SYSTEMMODAL))
{
// NOTE: When an application calls MessageBox and specifies the
// MB_ICONHAND and MB_SYSTEMMODAL flags for the nStyle parameter,
// the system displays the resulting message box regardless of
// available memory.
return ::MessageBox(hwnd, lpszMessage, lpszCaption, nStyle);
}
if (lpszCaption == NULL || lpszCaption[0] == 0)
{
lpszCaption = QOGetAppName();
}
CDialogTemplate dlg(hwnd, lpszMessage, nStyle, nHelpId);
if ((nStyle & MB_NOSOUND) == 0)
{
::MessageBeep(nStyle & MB_ICONMASK);
}
int rc = dlg.Display(lpszCaption);
return rc;
}
///////////////////////////////////////////////////////////////////////////////
// IconProc
LONG CALLBACK IconProc(HWND hwnd, UINT message, WPARAM, LPARAM)
{
if (message == WM_PAINT)
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
DrawIcon(hdc, 0, 0, reinterpret_cast<hicon>(::GetWindowLong(hwnd, GWL_USERDATA)));
EndPaint(hwnd, &ps);
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
// CDialogTemplate class
///////////////////////////////////////////////////////////////////////////////
// CDialogTemplate ctor
CDialogTemplate::CDialogTemplate(HWND hWnd, LPCTSTR lpszMessage, UINT nStyle, UINT nHelpId) :
m_hWnd(hWnd),
m_lpszMessage(lpszMessage),
m_nHelpId(nHelpId),
m_indicator(EDefault),
m_hIcon(NULL),
m_hFont(NULL),
m_nButton(0), // current button no.
m_nDefId(1), // button number of default button
m_nMaxID(FirstControlId) // control id
{
// if (nStyle & MB_NORESOURCE)
LoadButtonStrings(); // use English strings
// else
// LoadButtonStringsFromResources(); // try to load from resource strings
HDC hdc = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
ASSERT(hdc);
// get font for message box
/*
LOGFONT lf;
memset(&lf, 0, sizeof(lf));
_tcscpy(lf.lfFaceName, _T("MS Sans Serif"));
lf.lfHeight = -12;
lf.lfWeight = FW_NORMAL;
m_hFont = ::CreateFontIndirect(&lf);
*/
NONCLIENTMETRICS ncm;
memset(&ncm, 0, sizeof(ncm));
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
m_hFont = ::CreateFontIndirect(&ncm.lfMessageFont);
HFONT hOldFont = (HFONT)::SelectObject(hdc, m_hFont);
int nMaxWidth = (::GetSystemMetrics(SM_CXSCREEN) / 2) + 100;
if (nStyle & MB_ICONMASK)
{
nMaxWidth -= GetSystemMetrics(SM_CXICON) + 2*SpacingSize;
}
RECT msgrect;
SetRect(&msgrect, 0, 0, nMaxWidth, nMaxWidth);
::DrawText(hdc, MessageText(), -1, &msgrect, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
msgrect.right += 12;
msgrect.bottom += 5;
msgrect.left = 2 * SpacingSize;
msgrect.top = 2 * SpacingSize;
msgrect.right += 2 * SpacingSize;
msgrect.bottom += 2 * SpacingSize;
// client rect
RECT mbrect;
SetRect(&mbrect, 0, 0,
Width(msgrect) + (2 * SpacingSize),
Height(msgrect) + (2 * SpacingSize));
if (Height(mbrect) < MinimalHeight)
mbrect.bottom = MinimalHeight;
// now initialize the DLGTEMPLATE structure
m_dlgTempl.x = 0;
m_dlgTempl.y = 0;
m_dlgTempl.cdit = 0;
m_dlgTempl.style = WS_CAPTION | WS_VISIBLE | WS_SYSMENU |
WS_POPUP | DS_MODALFRAME | DS_CENTER;
m_dlgTempl.dwExtendedStyle = 0;
if (nStyle & MB_SYSTEMMODAL)
{
m_dlgTempl.style |= DS_SYSMODAL;
}
for (int j = 0; j < MaxItems; j++)
{
m_pDlgItemArray[j] = NULL;
}
int x, y;
RECT iconrect;
SetRect(&iconrect, 0, 0, 0, 0);
RECT rect;
if (nStyle & MB_ICONMASK)
{
int cxIcon;
int cyIcon;
LPSTR lpIcon = NULL;
switch (nStyle & MB_ICONMASK)
{
case MB_ICONEXCLAMATION:
lpIcon = (LPSTR)IDI_EXCLAMATION;
break;
case MB_ICONHAND:
lpIcon = (LPSTR)IDI_HAND;
break;
case MB_ICONQUESTION:
lpIcon = (LPSTR)IDI_QUESTION;
break;
case MB_ICONASTERISK:
lpIcon = (LPSTR)IDI_ASTERISK;
break;
}
if (lpIcon)
{
m_hIcon = ::LoadIcon(NULL, lpIcon);
cxIcon = GetSystemMetrics(SM_CXICON);
cyIcon = GetSystemMetrics(SM_CYICON);
int icon_x = SpacingSize;
int icon_y = SpacingSize;
msgrect.left += cxIcon + icon_x;
msgrect.right += cxIcon + icon_x;
mbrect.right = msgrect.right + SpacingSize;
SetRect(&iconrect, icon_x, icon_y, icon_x + cxIcon + 2, icon_y + cyIcon + 2);
AddItem(CDialogItem::STATICTEXT, 1000, &iconrect, _T(""));
}
}
AddItem(CDialogItem::STATICTEXT, m_nMaxID++, &msgrect, MessageText());
int cItems = 0;
switch (nStyle & MB_TYPEMASK)
{
case MB_OK :
cItems = 1;
break;
case MB_OKCANCEL :
cItems = 2;
break;
case MB_YESNO :
cItems = 2;
break;
case MB_YESNOCANCEL :
cItems = 3;
break;
case MB_ABORTRETRYIGNORE :
cItems = 3;
break;
case MB_RETRYCANCEL :
cItems = 2;
break;
case MB_CONTINUEABORT :
cItems = 2;
break;
}
if (nStyle & MB_HELP)
{
cItems++;
}
if (nStyle & MB_YESTOALL)
{
if ((nStyle & MB_YESNO) || (nStyle & MB_YESNOCANCEL))
{
cItems++;
}
else
{
ASSERT(FALSE); // must have either MB_YESNO or MB_YESNOCANCEL
}
}
if (nStyle & MB_NOTOALL)
{
if ((nStyle & MB_YESNO) || (nStyle & MB_YESNOCANCEL))
{
cItems++;
}
else
{
ASSERT(FALSE); // must have either MB_YESNO or MB_YESNOCANCEL
}
}
if (nStyle & MB_REPORT)
{
cItems++;
}
if (nStyle & MB_DONOTASKAGAIN)
{
Set(DoNotAskAgain);
}
else if (nStyle & MB_DONOTTELLAGAIN)
{
Set(DoNotTellAgain);
};
ASSERT(cItems > 0);
RECT buttonrow;
y = (msgrect.bottom > iconrect.bottom) ? msgrect.bottom : iconrect.bottom;
y += SpacingSize;
int w = ButtonWidth * cItems + (ButtonSpacing * (cItems - 1));
SetRect(&buttonrow,0, y, w,
y + ButtonHeight);
switch (nStyle & MB_DEFMASK)
{
case MB_DEFBUTTON1 :
m_nDefButton = 1;
break;
case MB_DEFBUTTON2 :
m_nDefButton = 2;
break;
case MB_DEFBUTTON3 :
m_nDefButton = 3;
break;
case MB_DEFBUTTON4 :
m_nDefButton = 4;
break;
case MB_DEFBUTTON5 :
m_nDefButton = 5;
break;
case MB_DEFBUTTON6 :
m_nDefButton = 6;
break;
default:
m_nDefButton = 1;
}
if (m_nDefButton > cItems)
{
m_nDefButton = 1;
}
x = (Width(mbrect) - Width(buttonrow)) / 2;
mbrect.bottom = buttonrow.bottom + BottomMargin;
int bw = Width(buttonrow);
int bleft = 2 * SpacingSize;
int bright = bleft + bw;
if (mbrect.right <= (bright + (2 * SpacingSize)))
{
mbrect.right = bright + (2 * SpacingSize);
}
x = (Width(mbrect) - bw) / 2;
y = buttonrow.top;
switch (nStyle & MB_TYPEMASK)
{
case MB_OK:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDOK, &rect, szOK);
Set(OkButton);
break;
case MB_OKCANCEL:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDOK, &rect, szOK);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDCANCEL, &rect, szCancel);
Set(CancelButton);
break;
case MB_YESNO:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDYES, &rect, szYes);
if (nStyle & MB_YESTOALL)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDYESTOALL, &rect, szYesToAll);
}
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDNO, &rect, szNo);
if (nStyle & MB_NOTOALL)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDNOTOALL, &rect, szNoToAll);
}
break;
case MB_YESNOCANCEL:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDYES, &rect, szYes);
if (nStyle & MB_YESTOALL)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDYESTOALL, &rect, szYesToAll);
}
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDNO, &rect, szNo);
if (nStyle & MB_NOTOALL)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDNOTOALL, &rect, szNoToAll);
}
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDCANCEL, &rect, szCancel);
Set(CancelButton);
break;
case MB_ABORTRETRYIGNORE:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDABORT, &rect, szAbort);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDRETRY, &rect, szRetry);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDIGNORE, &rect, szIgnore);
break;
case MB_RETRYCANCEL:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDRETRY, &rect, szRetry);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDCANCEL, &rect, szCancel);
Set(CancelButton);
break;
case MB_CONTINUEABORT:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDCONTINUE, &rect, szContinue);
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDABORT, &rect, szAbort);
break;
default:
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IDOK, &rect, szOK);
break;
}
if (nStyle & MB_HELP)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IdExHelp, &rect, szHelp);
}
nMaxWidth = ::GetSystemMetrics(SM_CXSCREEN) / 3;
RECT checkboxrect;
SetRect(&checkboxrect,0, 0, nMaxWidth, DoNotAskAgainHeight);
if (nStyle & MB_DONOTASKAGAIN)
{
x = 2 * ButtonSpacing + 5;
y += ButtonHeight + (2 * ButtonSpacing);
::DrawText(hdc, szDoNotAskAgain, -1, &checkboxrect,
DT_LEFT | DT_NOPREFIX | DT_CALCRECT | DT_SINGLELINE);
int w = checkboxrect.right - checkboxrect.left;
w += w/3;
//rect.SetRect(x, y, x + MSGBOXEX_DONOTASKAGAIN_WIDTH, y + DoNotAskAgainHeight);
SetRect(&rect,x, y, x + w, y + DoNotAskAgainHeight);
AddItem(CDialogItem::CHECKBOX, IdDoNotAskAgian, &rect, szDoNotAskAgain);
buttonrow.bottom = y + DoNotAskAgainHeight;
mbrect.bottom = buttonrow.bottom + SpacingSize;
if (Width(mbrect) < (x + w))
mbrect.right = mbrect.left + x + w;
}
else if (nStyle & MB_DONOTTELLAGAIN)
{
x = 2 * ButtonSpacing + 5;
y += ButtonHeight + (2 * ButtonSpacing);
::DrawText(hdc, szDoNotTellAgain, -1, &checkboxrect,
DT_LEFT | DT_NOPREFIX | DT_CALCRECT | DT_SINGLELINE);
int w = checkboxrect.right - checkboxrect.left;
w += w/3;
//rect.SetRect(x, y, x + MSGBOXEX_DONOTASKAGAIN_WIDTH, y + DoNotAskAgainHeight);
SetRect(&rect,x, y, x + w, y + DoNotAskAgainHeight);
AddItem(CDialogItem::CHECKBOX, IdDoNotAskAgian, &rect, szDoNotTellAgain);
buttonrow.bottom = y + DoNotAskAgainHeight;
mbrect.bottom = buttonrow.bottom + SpacingSize;
if (Width(mbrect) < (x + w))
{
mbrect.right = mbrect.left + x + w;
}
}
if (nStyle & MB_REPORT)
{
x += ButtonWidth + ButtonSpacing;
SetRect(&rect,x, y, x + ButtonWidth, y + ButtonHeight);
AddItem(CDialogItem::BUTTON, IdExReport, &rect, szReport);
}
if (buttonrow.bottom >= mbrect.bottom)
{
mbrect.bottom = buttonrow.bottom + (2 * SpacingSize);
}
if (mbrect.right < (buttonrow.right + (2 * SpacingSize)))
{
mbrect.right = buttonrow.right + (2 * SpacingSize);
}
short hidbu = HIWORD(GetDialogBaseUnits());
short lodbu = LOWORD(GetDialogBaseUnits());
m_dlgTempl.x = 0;
m_dlgTempl.y = 0;
m_dlgTempl.cx = (short)((Width(mbrect) * 4) / lodbu);
m_dlgTempl.cy = (short)((Height(mbrect) * 8) / hidbu);
::SelectObject(hdc, hOldFont);
::DeleteDC(hdc);
}
///////////////////////////////////////////////////////////////////////////////
// CDialogTemplate dtor
CDialogTemplate::~CDialogTemplate()
{
if (m_hIcon)
{
DestroyIcon(m_hIcon);
}
if (m_hFont)
{
::DeleteObject(m_hFont);
}
for (int i = 0; i < MaxItems; i++)
{
if (m_pDlgItemArray[i])
{
delete m_pDlgItemArray[i];
m_pDlgItemArray[i] = NULL;
}
}
}
///////////////////////////////////////////////////////////////////////////////
// LoadButtonStrings
void CDialogTemplate::LoadButtonStrings()
{
_tcscpy(szOK, _T("OK"));
_tcscpy(szCancel, _T("Cancel"));
_tcscpy(szIgnore, _T("&Ignore"));
_tcscpy(szRetry, _T("&Retry"));
_tcscpy(szAbort, _T("&Abort"));
_tcscpy(szHelp, _T("&Help"));
_tcscpy(szYes, _T("&Yes"));
_tcscpy(szNo, _T("&No"));
_tcscpy(szContinue, _T("&Continue"));
_tcscpy(szDoNotAskAgain, _T("Don't ask me again"));
_tcscpy(szDoNotTellAgain, _T("Don't tell me again"));
_tcscpy(szYesToAll, _T("Yes to &All"));
_tcscpy(szNoToAll, _T("No to A&ll"));
_tcscpy(szReport, _T("Re&port"));
}
///////////////////////////////////////////////////////////////////////////////
// LoadButtonStringsFromResources
void CDialogTemplate::LoadButtonStringsFromResources()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
if (::LoadString(hInstance, IDS_OK, szOK, MaxButtonStringSize) == 0)
{
_tcscpy(szOK, _T("OK"));
}
szOK[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_CANCEL, szCancel, MaxButtonStringSize) == 0)
{
_tcscpy(szCancel, _T("Cancel"));
}
szCancel[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_IGNORE, szIgnore, MaxButtonStringSize) == 0)
{
_tcscpy(szIgnore, _T("&Ignore"));
}
szIgnore[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_RETRY, szRetry, MaxButtonStringSize) == 0)
{
_tcscpy(szRetry, _T("&Retry"));
}
szRetry[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_ABORT, szAbort, MaxButtonStringSize) == 0)
{
_tcscpy(szAbort, _T("&Abort"));
}
szAbort[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_HELP, szHelp, MaxButtonStringSize) == 0)
{
_tcscpy(szHelp, _T("&Help"));
}
szHelp[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_YES, szYes, MaxButtonStringSize) == 0)
{
_tcscpy(szYes, _T("&Yes"));
}
szYes[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_NO, szNo, MaxButtonStringSize) == 0)
{
_tcscpy(szNo, _T("&No"));
}
szNo[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_CONTINUE, szContinue, MaxButtonStringSize) == 0)
{
_tcscpy(szContinue, _T("&Continue"));
}
szContinue[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_DONOTASKAGAIN, szDoNotAskAgain, MaxButtonStringSize) == 0)
{
_tcscpy(szDoNotAskAgain, _T("Don't ask me again"));
}
szDoNotAskAgain[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_DONOTTELLAGAIN, szDoNotTellAgain, MaxButtonStringSize) == 0)
{
_tcscpy(szDoNotTellAgain, _T("Don't tell me again"));
}
szDoNotTellAgain[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_YESTOALL, szYesToAll, MaxButtonStringSize) == 0)
{
_tcscpy(szYesToAll, _T("Yes to &All"));
}
szYesToAll[MaxButtonStringSize-1] = _T('\0');
if (::LoadString(hInstance, IDS_NOTOALL, szNoToAll, MaxButtonStringSize) == 0)
{
_tcscpy(szNoToAll, _T("No to A&ll"));
}
szNoToAll[MaxButtonStringSize-1] = _T('\0');
}
///////////////////////////////////////////////////////////////////////////////
// MsgBoxDlgProc
BOOL CALLBACK CDialogTemplate::MsgBoxDlgProc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
CDialogTemplate* Me = reinterpret_cast<cdialogtemplate*>(::GetWindowLong(hwnd, GWL_USERDATA));
HWND hwndChild;
switch (message)
{
case WM_INITDIALOG:
{
::SetWindowLong(hwnd, GWL_USERDATA, lParam); // safe it for the others
Me = reinterpret_cast<cdialogtemplate*>(lParam);
HDC hdc = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
ASSERT(hdc);
::SelectObject(hdc, Me->m_hFont);
::DeleteDC(hdc);
UINT nID;
for (nID = FirstControlId; nID < Me->m_nMaxID; nID++)
{
hwndChild = ::GetDlgItem(hwnd, nID);
if (::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
}
else
{
break;
}
}
for (nID = 1; nID < 18; nID++)
{
hwndChild = ::GetDlgItem(hwnd, nID);
if (hwndChild && ::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
}
}
hwndChild = ::GetDlgItem(hwnd, IdExHelp);
if (hwndChild && ::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
}
hwndChild = ::GetDlgItem(hwnd, IdDoNotAskAgian);
if (hwndChild && ::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
CheckDlgButton(hwnd, IdDoNotAskAgian, 0);
}
hwndChild = ::GetDlgItem(hwnd, IdExReport);
if (hwndChild && ::IsWindow(hwndChild))
{
::SendMessage(hwndChild, WM_SETFONT, (WPARAM)Me->m_hFont, 0);
}
hwndChild = ::GetDlgItem(hwnd, Me->m_nDefId);
if (hwndChild && ::IsWindow(hwndChild))
{
::SetFocus(hwndChild);
}
// disable close button just like real MessageBox
if (!Me->Option(CancelOrOkButton))
{
EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_CLOSE, MF_GRAYED);
};
if (Me->m_hIcon)
{
HWND hwndIcon;
hwndIcon = ::GetDlgItem(hwnd, 1000);
::SetWindowLong(hwndIcon, GWL_WNDPROC, reinterpret_cast<long>(IconProc));
::SetWindowLong(hwndIcon, GWL_USERDATA, reinterpret_cast<long>(Me->m_hIcon));
}
return FALSE;
}
case WM_COMMAND:
{
switch(wParam)
{
case IDCLOSE:
return TRUE;
case IDCANCEL:
if (Me->Option(CancelButton))
{
::EndDialog(hwnd, IDCANCEL);
}
else if (Me->Option(OkButton))
{
::EndDialog(hwnd, IDOK);
}
return TRUE;
case IdExHelp:
{
_TCHAR szBuf[_MAX_PATH*2];
szBuf[0] = 0;
GetModuleFileName(NULL, szBuf, (sizeof(szBuf)/sizeof(szBuf[0])) - 1); //AfxGetInstanceHandle()
if (strlen(szBuf) > 0)
{
_TCHAR *cp = _tcsrchr(szBuf, _T('.'));
if (cp)
{
_tcscpy(cp, _T(".hlp"));
::WinHelp(hwnd, szBuf,
(Me->m_nHelpId == 0) ? HELP_PARTIALKEY : HELP_CONTEXT,
Me->m_nHelpId);
}
}
return FALSE;
}
case IdExReport:
{
//QOReportError(Me->MessageText());
QODumpStack(Me->MessageText());
return FALSE;
}
case IdDoNotAskAgian: //IdDoNotAskAgian & DoNotTellAgain share the same id!!
return FALSE;
default:
//if (wParam != IdExHelp && wParam != IdDoNotAskAgian)
{
hwndChild = ::GetDlgItem(hwnd, IdDoNotAskAgian);
BOOL bFlag = FALSE;
if (hwndChild && ::IsWindow(hwndChild))
{
bFlag = ::SendMessage(hwndChild, BM_GETCHECK, 0, 0);
}
if (Me->Option(DoNotAskAgain))
{
wParam |= bFlag ? MB_DONOTASKAGAIN : 0;
}
else if (Me->Option(DoNotTellAgain))
{
wParam |= bFlag ? MB_DONOTTELLAGAIN : 0;
}
::EndDialog(hwnd, wParam);
}
return FALSE;
}
}
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
// CDialogTemplate::AddItem
void CDialogTemplate::AddItem(CDialogItem::Econtroltype cType, UINT nID, RECT* prect, LPCTSTR pszCaption)
{
ASSERT(m_pDlgItemArray[m_dlgTempl.cdit] == NULL);
CDialogItem::Econtroltype ct = cType;
if (ct == CDialogItem::CHECKBOX)
{
ct = CDialogItem::BUTTON;
}
m_pDlgItemArray[m_dlgTempl.cdit] = new CDialogItem(ct);
ASSERT(m_pDlgItemArray[m_dlgTempl.cdit]);
m_pDlgItemArray[m_dlgTempl.cdit]->AddItem(*this, cType, nID, prect, pszCaption);
m_dlgTempl.cdit++;
ASSERT(m_dlgTempl.cdit < MaxItems);
}
///////////////////////////////////////////////////////////////////////////////
// CDialogTemplate::Display
int CDialogTemplate::Display(LPCTSTR lpszCaption)
{
// The first step is to allocate memory to define the dialog. The information to be
// stored in the allocated buffer is the following:
//
// 1. DLGTEMPLATE structure
// typedef struct
// {
// DWORD style;
// DWORD dwExtendedStyle;
// WORD cdit;
// short x;
// short y;
// short cx;
// short cy;
// } DLGTEMPLATE;
// 2. 0x0000 (Word) indicating the dialog has no menu
// 3. 0x0000 (Word) Let windows assign default class to the dialog
// 4. (Caption) Null terminated unicode string
// 5. 0x000B (size of the font to be used)
// 6. "MS Sans Serif" (name of the typeface to be used)
// 7. DLGITEMTEMPLATE structure for the button (HAS TO BE DWORD ALIGNED)
// typedef struct
// {
// DWORD style;
// DWORD dwExtendedStyle;
// short x;
// short y;
// short cx;
// short cy;
// WORD id;
// } DLGITEMTEMPLATE;
// 8. 0x0080 to indicate the control is a button
// 9. (Title). Unicode null terminated string with the caption
// 10. 0x0000 0 extra bytes of data for this control
// 11. DLGITEMTEMPLATE structure for the Static Text (HAS TO BE DWORD ALIGNED)
// 12. 0x0081 to indicate the control is static text
// 13. (Title). Unicode null terminated string with the text
// 14 0x0000. 0 extra bytes of data for this control
int rc = IDCANCEL;
_TCHAR szTitle[1024];
_tcsncpy(szTitle, lpszCaption, (sizeof(szTitle)/sizeof(szTitle[0]))-1);
szTitle[(sizeof(szTitle)/sizeof(szTitle[0]))-1] = _T('\0');
int nTitleLen = _tcslen(szTitle);
int i;
try // catch memory exceptions and don't worry about allocation failures
{
int nBufferSize = sizeof(DLGTEMPLATE) +
(2 * sizeof(WORD)) + // menu and class
((nTitleLen + 1) * sizeof(WCHAR));
// NOTE - font is set in MsgBoxDlgProc
nBufferSize = (nBufferSize + 3) & ~3; // adjust size to make
// first control DWORD aligned
// loop to calculate size of buffer we need -
// add size of each control:
// sizeof(DLGITEMTEMPLATE) +
// sizeof(WORD) + // atom value flag 0xFFFF
// sizeof(WORD) + // ordinal value of control's class
// sizeof(WORD) + // no. of bytes in creation data array
// sizeof title in WCHARs
for (i = 0; i < m_dlgTempl.cdit; i++)
{
int nItemLength = sizeof(DLGITEMTEMPLATE) + 3 * sizeof(WORD);
int nChars = _tcslen(m_pDlgItemArray[i]->m_szCaption) + 1;
nItemLength += nChars * sizeof(WCHAR);
if (i != m_dlgTempl.cdit - 1) // the last control does not need extra bytes
{
nItemLength = (nItemLength + 3) & ~3; // take into account gap
} // so next control is DWORD aligned
nBufferSize += nItemLength;
}
HLOCAL hLocal = LocalAlloc(LHND, nBufferSize);
if (hLocal == NULL)
{
throw TException("XMessageBox: Out of memory");
}
BYTE* pBuffer = (BYTE*)LocalLock(hLocal);
if (pBuffer == NULL)
{
LocalFree(hLocal);
throw TException("XMessageBox: Lock failed");
}
BYTE* pdest = pBuffer;
// transfer DLGTEMPLATE structure to the buffer
memcpy(pdest, &m_dlgTempl, sizeof(DLGTEMPLATE));
pdest += sizeof(DLGTEMPLATE);
*(WORD*)pdest = 0; // no menu
*(WORD*)(pdest + 1) = 0; // use default window class
pdest += 2 * sizeof(WORD);
// transfer title
WCHAR* pchCaption;
int nActualChars;
pchCaption = new WCHAR[nTitleLen + 1];
nActualChars = MultiByteToWideChar(CP_ACP, 0, szTitle, -1, pchCaption, nTitleLen + 1);
ASSERT(nActualChars > 0);
memcpy(pdest, pchCaption, nActualChars * sizeof(WCHAR));
pdest += nActualChars * sizeof(WCHAR);
delete pchCaption;
// will now transfer the information for each one of the item templates
for (i = 0; i < m_dlgTempl.cdit; i++)
{
pdest = (BYTE*)(((DWORD)pdest + 3) & ~3); // make the pointer DWORD aligned
memcpy(pdest, (void *)&m_pDlgItemArray[i]->m_dlgItemTemplate, sizeof(DLGITEMTEMPLATE));
pdest += sizeof(DLGITEMTEMPLATE);
*(WORD*)pdest = 0xFFFF; // indicating atom value
pdest += sizeof(WORD);
*(WORD*)pdest = (WORD)m_pDlgItemArray[i]->m_controltype; // atom value for the control
pdest += sizeof(WORD);
// transfer the caption even when it is an empty string
WCHAR* pchCaption;
int nChars = _tcslen(m_pDlgItemArray[i]->m_szCaption) + 1;
pchCaption = new WCHAR[nChars];
int nActualChars = MultiByteToWideChar(CP_ACP, 0,
m_pDlgItemArray[i]->m_szCaption, -1, pchCaption, nChars);
ASSERT(nActualChars > 0);
memcpy(pdest, pchCaption, nActualChars * sizeof(WCHAR));
pdest += nActualChars * sizeof(WCHAR);
delete pchCaption;
*(WORD*)pdest = 0; // How many bytes in data for control
pdest += sizeof(WORD);
}
ASSERT(pdest - pBuffer == nBufferSize); // just make sure we did not overrun the heap
HINSTANCE hInstance = GetModuleHandle(NULL);
rc = ::DialogBoxIndirectParam(hInstance, reinterpret_cast<lpdlgtemplate>(pBuffer),
m_hWnd, MsgBoxDlgProc, reinterpret_cast<lparam>(this));
LocalUnlock(hLocal);
LocalFree(hLocal);
}
catch (std::bad_alloc a) //I have not succeeded in testing this catch
{
::MessageBox(m_hWnd, _T("Memory allocation for dialog template failed."), a.what(),
MB_ICONEXCLAMATION | MB_OK);
rc = IDCANCEL;
}
return rc;
}
///////////////////////////////////////////////////////////////////////////////
// CDialogItem class
///////////////////////////////////////////////////////////////////////////////
// CDialogItem ctor
CDialogItem::CDialogItem(CDialogItem::Econtroltype ctrlType)
{
m_controltype = ctrlType;
}
///////////////////////////////////////////////////////////////////////////////
// CDialogItem::AddItem
void CDialogItem::AddItem(CDialogTemplate& dialog, Econtroltype ctrltype, UINT nID, RECT* prect, LPCTSTR lpszCaption)
{
short hidbu = HIWORD(GetDialogBaseUnits());
short lodbu = LOWORD(GetDialogBaseUnits());
// first fill in the type, location and size of the control
m_controltype = ctrltype;
if (m_controltype == CHECKBOX)
{
m_controltype = BUTTON;
}
if (prect != NULL)
{
m_dlgItemTemplate.x = (short)((prect->left * 4) / lodbu);
m_dlgItemTemplate.y = (short)((prect->top * 8) / hidbu);
m_dlgItemTemplate.cx = (short)((Width(*prect) * 4) / lodbu);
m_dlgItemTemplate.cy = (short)((Height(*prect) * 8) / hidbu);
}
else
{
m_dlgItemTemplate.x = 0;
m_dlgItemTemplate.y = 0;
m_dlgItemTemplate.cx = 10; // some useless default
m_dlgItemTemplate.cy = 10;
}
m_dlgItemTemplate.dwExtendedStyle = 0;
m_dlgItemTemplate.id = (WORD)nID;
switch (ctrltype)
{
case ICON:
m_dlgItemTemplate.style = WS_CHILD | SS_ICON | WS_VISIBLE;
break;
case BUTTON:
dialog.ButtonCount()++;
m_dlgItemTemplate.style = WS_VISIBLE | WS_CHILD | WS_TABSTOP;
if (dialog.ButtonCount() == dialog.DefaultButton())
{
m_dlgItemTemplate.style |= BS_DEFPUSHBUTTON;
dialog.DefaultButtonId(nID);
}
else
{
m_dlgItemTemplate.style |= BS_PUSHBUTTON;
}
break;
case CHECKBOX:
m_dlgItemTemplate.style = WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_AUTOCHECKBOX;
break;
case EDITCONTROL:
m_dlgItemTemplate.style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE | ES_LEFT;
break;
case STATICTEXT:
m_dlgItemTemplate.style = WS_CHILD | WS_VISIBLE | SS_LEFT;
break;
default:
ASSERT(FALSE); // should never get here
}
_tcsncpy(m_szCaption, (lpszCaption != NULL) ? lpszCaption : _T(""), (sizeof(m_szCaption)/sizeof(m_szCaption[0]))-1);
m_szCaption[(sizeof(m_szCaption)/sizeof(m_szCaption[0]))-1] = _T('\0');
}
<>
|
|
|
|
|