|
|
Comments and Discussions
|
|
 |
|

|
i do not use c++ and that is clearly evident from my inability to compile this as a dll for use in a vb.net project with framework 4.0
any pointers would be really welcome
|
|
|
|

|
I noticed that in Vista / Win7 high DPI mode the default icons looked pixelated.
"Icon Display for High DPI" post suggested changing the icon draw code – which fixed pixilation by making icon smaller.
Instead I suggest changing
m_hIcon = ::LoadIcon(NULL, lpIcon);
in constructor in XMessageBox.cpp to
LoadIconMetric( NULL, lpIcon, LIM_LARGE, &m_hIcon);
since LoadIconMetric(), and LoadIconWithScaleDown() seem superior to LoadImage() which I first tried (it did not seem to work for LR_SHARED icons for desired DPI changed size), all of which seem superior to LoadIcon() when used in Vista or higher.
Jens Winslow
|
|
|
|

|
Hello. I'm using XMessageBox v1.10.
If I override CWinApp::DoMessageBox like this:
int CMyApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT nIDPrompt)
{
return XMessageBox(m_pMainWnd->GetSafeHwnd(),lpszPrompt,_T("Hello"),nType);
}
and CListView::OnEndlabeledit like this:
void CMyListView::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
AfxMessageBox(_T("Again"));
*pResult = 0;
}
Then after editing a list view item text:
1. If I press Enter, then the message-box acts correctly.
2. If I click outside the item edited, then the message-box doesn't react to mouse-clicks on its buttons and the input focus is on the list view, if I right-click on the message-box, then I see the list view context-menu. It only listens to the Enter and Escape button pushes.
How can I make the message-box listen to mouse-clicks and have focus on it in the second case?
|
|
|
|

|
The created buttons aren't drawn theme-aware. When I compared theme drawn buttons (same "button" class) in other dialogs, they have the same styles as what XMessageBox ends up using (verified with Spy++). BS_TEXT|BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE|WS_TABSTOP, etc. I don't think themeing cares about those anyway, but it was worth a shot.
Is this a side effect of CreateDialogIndirectParam() vs a CreateDialogXXX()? Google doesn't turn up anything...
Hopefully I'm not missing anything obvious.
|
|
|
|

|
I have used it. There is no better reason.
|
|
|
|

|
XMessageBox does not build under VC++6
// 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, (HICON)(::GetWindowLongPtr(hwnd, GWLP_USERDATA)));
EndPaint(hwnd, &ps);
}
return FALSE;
}
error message:
XMessageBox\src\XMessageBox.cpp(685) : error C2039: 'GetWindowLongPtr' : is not a member of '`global namespace''
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(685) : error C2065: 'GetWindowLongPtr' : undeclared identifier
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(685) : error C2065: 'GWLP_USERDATA' : undeclared identifier
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(1695) : error C2039: 'SetWindowLongPtr' : is not a member of '`global namespace''
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(1695) : error C2065: 'SetWindowLongPtr' : undeclared identifier
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(1763) : error C2065: 'GWLP_WNDPROC' : undeclared identifier
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(1763) : error C2065: 'LONG_PTR' : undeclared identifier
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(1763) : error C2146: syntax error : missing ')' before identifier 'IconProc'
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(1763) : error C2059: syntax error : ')'
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(1764) : error C2146: syntax error : missing ')' before identifier 'Me'
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(1764) : error C2059: syntax error : ')'
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(2392) : error C2065: 'DWORD_PTR' : undeclared identifier
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(2392) : error C2146: syntax error : missing ')' before identifier 'pdest'
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(2392) : error C2059: syntax error : ')'
C:\TheCodeProject\XMessageBox\src\XMessageBox.cpp(2431) : error C2664: 'CreateDialogIndirectParamW' : cannot convert parameter 4 from 'long (struct HWND__ *,unsigned int,unsigned int,long)' to 'int (__stdcall *)(struct HWND__ *,unsigned int,unsigned
int,long)'
None of the functions with this name in scope match the target type
|
|
|
|

|
One of the most painstakingly perfect articles I've ever seen. 5 really isn't enough
|
|
|
|
|

|
I have used this code, a Unicode version of it, and it works really nicely. But I have had to add code for watch out for two problem situations (not bugs in this code mind you):
- The code uses DrawText with DT_CALCRECT to determine the width of text. For some reason, this function -sometimes- says that it was successful, but it returns a rect.right value that is insanely large . The calculations use that width to eventually calculate a negative dialog box width (because the int is so large it gets reinterpreted as negative number somewhere) which means no dialog box the user can interact with, yet the code waits for user input. This seems to happen commonly on Russian version of Windows XP for example. I had a hard time figuring this out because it would not misbehave on any of our machines, but only on Russian client machines. So I have replaced the two DrawText calls with a method which adds some sanity checks and ultimately, if need be, even use the TEXTMETRIC.tmAveCharWidth to come up with a reasonable width . Interestingly, DrawText always draws correctly, but sometimes it cant calculate the rectangle width correctly to save its life. I also put a safety check on the bottom of the method which sets the dialog box width.
- Also be careful what owner window HWND handle you pass in, getting something incorrect or using 0 can result in your dialog box not being associated with your application or sometimes (not always!) disappearing behind your application without the user being able to bring it to the foreground. The only way to bring it to the foreground is to minimizing everything and use alt-tab.
But great code and useful, thank you.
modified on Wednesday, May 26, 2010 4:31 PM
|
|
|
|

|
Hi
This is a great class but I have noticed that when the message box is displayed, the user can continue to click stuff in the main application window e.g. toolbar and it still responds. This is something that AfxMessageBox prevents by default.
Is there any way to get XMessageBox to work in the same way? I have tried adding MB_APPLMODAL to the style but MB_APPLMODAL has an ID of zero so it has no effect.
Thanks
Tony
|
|
|
|

|
If Windows is running with high DPI settings, the size of the icon loaded can be different from the value returned by GetSystemMetrics(SM_CXICON)
For instance: GetSystemMetrics(SM_CXICON) returns 40 at 120 DPI on Vista, but if a 40x40 icon is not available, a 32x32 icon is returned by ::LoadIcon(NULL, lpIcon);
When the 32x32 icon is drawn in a 40x40 box by the IconProc, the icon is stretched and looks out of focus.
So I replaced the icon drawing function in IconProc with this
HICON hIcon = (HICON)(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
int cxIcon = 0;
int cyIcon = 0;
if (hIcon) { // success
ICONINFO ii;
// Get icon dimension
ZeroMemory(&ii, sizeof(ICONINFO));
if (::GetIconInfo(hIcon, &ii)) {
cxIcon = (BYTE)(ii.xHotspot * 2);
cyIcon = (BYTE)(ii.yHotspot * 2);
}
}
// High DPI
if (cxIcon > 0) // it was possible to find out the real icon size
::DrawIconEx(hdc, 0, 0, hIcon, cxIcon, cyIcon, 0, NULL, DI_NORMAL);
else
::DrawIcon(hdc, 0, 0, hIcon);
XMessageBox is GREAT! thanks
|
|
|
|

|
To be consistant with MessageBox(), it seems to me that the return call at the end of CXDialogTemplate::Display() should be :
return GetReturnValue();
rather than:
return rc;
which always returns IDCANCEL
Otherwise a fantastic class that I use often!
John Curtis.
Software guy.
Fatlab Software.
|
|
|
|

|
This is a fantastic tool. I use it all the time. Thanks.
I have introduced the GNU Gettext translation program and that works fine too. I have made another addition that I use regularly. I often want the message box to come up slightly to the left of middle of the screen (so you can see whatever is behind it). I can't be bothered working out where on the screen it should be, I just simply want the message box say 300 pixels to the left of center. Hence if x or y is negative - this code just moves the messagebox left and up by the x and y value. If x or y are positive, it moves to an exact location as before.
// XMessagebox.cpp
//{
//.....
//}
// REPLACED BY
if (Me->m_X > 0 || Me->m_Y > 0)
{
// caller has specified screen coordinates
CXRect dlgRect;
::GetWindowRect(hwnd, &dlgRect);
::MoveWindow(hwnd, Me->m_X, Me->m_Y, dlgRect.Width(), dlgRect.Height(), TRUE);
}
else if (Me->m_X < 0 || Me->m_Y < 0)
{ // Mod by JLB 28 Oct 09 for Offset coordinates
// caller has specified negative offset screen coordinates
// code to center dialog (necessary if not called by MFC app)
CXRect mainRect, dlgRect;
::GetWindowRect(::GetParent(hwnd), &mainRect);
::GetWindowRect(hwnd, &dlgRect);
// Me->m_X and Me->m_Y already negative so add to center coordinates
int x = (mainRect.right + mainRect.left)/2 - dlgRect.Width()/2 + Me->m_X;
if(x < 0) // Check will be on screen
x = 0;
int y = (mainRect.bottom + mainRect.top) /2 - dlgRect.Height()/2 + Me->m_Y;
if (y < 0) // Check will be on screen
y = 0;
::MoveWindow(hwnd, x, y, dlgRect.Width(), dlgRect.Height(), TRUE);
}
|
|
|
|

|
Author:
Here is the steps to reproduce the problem.
1) Create a button on the main Dialogbox of Demo project.
2) write a simple code to create a "Hello world" console executable. remember "Hello.exe" path. we will use in step 3.
<code> #include <stdio.h>
#include <windows.h>
int main(int argc, char *argv[])
{
int i;
for (i=0;i<10 ;i++ )
{
Sleep(1000);
printf("Hello, world\n");
}
return 0;
}</code>
3) paste this full text in the event of button click for button created in step 1:
<code>void CXMsgBoxTestDlg::OnBnClickedButton12()
{
DWORD ExitCode = 1;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pinfo;
int Response = 999;
CString strTempTitle = CString("Hello.exe");
HWND ConsoleWnd = NULL;
AllocConsole();
SetConsoleTitle( strTempTitle );
while (ConsoleWnd == NULL) {
Sleep(0);
ConsoleWnd = ::FindWindow( NULL, strTempTitle );
}
CString strCommandLine = CString("\\XMessageBox_demo\\src\\Hello.exe");
BOOL cpret = CreateProcess(
NULL,
strCommandLine.GetBuffer(strCommandLine.GetLength()+1),
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
& si,
& pinfo );
strCommandLine.ReleaseBuffer();
WaitForSingleObject( pinfo.hProcess, INFINITE );
GetExitCodeProcess( pinfo.hProcess, & ExitCode );
CloseHandle( pinfo.hProcess );
CloseHandle( pinfo.hThread );
(void)SetForegroundWindow();
XMSGBOXPARAMS xmb;
(void)_tcsncpy( xmb.szCustomButtons,
CString("View output\nClose output"),
(sizeof(xmb.szCustomButtons)/sizeof((xmb.szCustomButtons)[0])) );
if (ExitCode == 0) {
Response = XMessageBox( ConsoleWnd,
CString("completed successfully"),
CString("Hello Demo"),
MB_YESNO | MB_ICONINFORMATION | MB_SETFOREGROUND,
&xmb );
}
CString sMessage = TEXT("");
sMessage.Format(TEXT("%d"),Response);
AfxMessageBox(sMessage, MB_OK|MB_ICONINFORMATION);
// TODO: Add your control notification handler code here
}</code>
4) modify strCommandLine string to have proper path for Hello.exe.
5) Rebuild and execute.
6) A console window will apprear and will run Hello.exe. Minimize this console window. wait for 10 sec to finish this Hello.exe. Now you will not be able to see custom message (XMessageBox). this will also block this console application to terminate. When console window is in non-minimized state, we can see the custom message box.
Can any one help me on this? Thanks in Advance!
|
|
|
|

|
Is there a way to make XMessageBox() adapt the message box size so that a long title (the third parameter usually passed to MessageBox() API) can fit in it? Thanks in advance for replies
|
|
|
|
|

|
Great job! I've done something like your project and I even wanted to post it here. But XMEssageBox is much better and flexible.
I have dealed with some things that are not implemented or not properly implemented here. I have Windows 2000 MessageBox sources, it is much easier to implement some features using original source code. I can resolve some issues and send diffs if you accept.
1) Flags MB_RTLREADING, MB_RIGHT. There is no support here. They work sometime together sometime not. Arabic and Hebrew systems need this. It is not very hard to implement - just change some static control and dialog styles.
You should also note:
MSDN: Adding two right-to-left marks (RLMs), represented by Unicode formatting character U+200F, in the beginning of a MessageBox display string is interpreted by the Win32 MessageBox rendering engine so as to cause the reading order of the MessageBox to be rendered as right-to-left (RTL).
2) Why do you have the following code?
if (hwnd == NULL)
{
hwnd = ::GetActiveWindow() ;
if (hwnd != NULL)
{
hwnd = ::GetLastActivePopup(hwnd) ;
}
};
As far as I know original MessageBox don't do anything like that. I think this is not the thing the caller wanted from XMessageBox().
You also don't have an option in your sample project to set windows handle to NULL.
3) MB_TASKMODAL is not supported. This flag + NULL hwndParent disables all windows belonging to current thread and enables them before MessageBox close. I can give you a piece of original code that will do the job in original manner.
You also don't have an option in your sample project to choose modality (MB_APPLMODAL, MB_SYSTEMMODAL, MB_TASKMODAL). It could be better if you had buttons like "+1 window", "+1 thread" that will create other instances of testing window in the same thread/another thread. It will help testing MB_TASKMODAL.
4) It could be better if XMessageBox could support a number of languages at one time choosing them by LanguageId. You could store languages in runtime memory, hardcoded or by providing LanguageId to FindResourceEx (only one way).
As for me it is better not using resources for standart buttons text in other languages, because it will create external dependencies for XMessageBox. And there will be some problems using static library project (it can't have any resources inside).
You should also provide a way to translate a string "Error" that is shown in caption when szCaption is NULL.
I also could translate XMessageBox strings to Russian if you want.
5) It could be better if you also copy to clipboard text of optional checkbox. (by Ctrl+C)
6) Why do you have the following code?
case IdExHelp:
{
TCHAR szBuf[_MAX_PATH*2] = { 0 };
::GetModuleFileName(NULL, szBuf, countof(szBuf) - 1);
if (_tcslen(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;
}
MSDN states another behaviour:
MB_HELP - Adds a Help button to the message box. When the user clicks the Help button or presses F1, the system sends a WM_HELP message to the owner.
So there should be a code like this:
const DWORD dwMousePos = GetMessagePos();
HELPINFO hlp;
memset(&hlp, 0, sizeof(hlp));
hlp.cbSize = sizeof(hlp);
hlp.iContextType = HELPINFO_WINDOW;
hlp.iCtrlId = dwControlId;
hlp.hItemHandle = hwndControl;
hlp.dwContextId = pMsgData->dwContextHelpId;
hlp.MousePos.x = GET_X_LPARAM(dwMousePos);
hlp.MousePos.y = GET_Y_LPARAM(dwMousePos);
if(pMsgData->lpfnMsgBoxCallback != NULL)
{
pMsgData->lpfnMsgBoxCallback(&hlp);
}
else if(IsWindow(pMsgData->hwndParent))
{
SendMessageW(pMsgData->hwndParent, WM_HELP, 0, (LPARAM)&hlp);
}
7) Structure XMSGBOXPARAMS is placed on stack and it is near 12 Kb in Unicode.
I think it could be better to store XMSGBOXPARAMS in dynamic memory. Don't help stack to overflow!
Sometime XMessagebox will not be at the end of stack, but program will continue growing stack deeper than XMessageBox. (Examples: When hwndParent is NULL and thread has it's own windows, when Help button is pressed and parent handles WM_HELPINFO showing something...). Even a number of executing at the same time XMessageBoxes can exist in the same thread stack.
Experiments showed that it is possible to run near 30 XMessageBoxes inside each other and the stack will overflow. It is not a standart usage, but real program could use stack too...
You can allocate some memory earlier to be sure it will be enough memory during XMessageBox call. But keep in mind multiple MessageBoxes at the same thread at the same time.
8) There is an interesting way to set dialog font in template. Just use DS_SETFONT style, add font size 0x7FFF and don't set any font name at all! It will create dialog and apply messagebox font.
9) Following code looks strange:
_ASSERTE(xmb.nTimeoutSeconds < 1000);
if (xmb.nTimeoutSeconds >= 1000)
xmb.nTimeoutSeconds = 10;
I need timeouts like a few hours, even days. I'm writing application that works 24/7. Sometimes it shows an error message and writes log. It is a good idea to wait for operator for a few hours, but not longer.
10) You have a functionality to stop timer after user clicked on something. It is necessary to have an option to disable this feature.
Thanks for reading all this...
I hope it will help make XMessageBox better!
|
|
|
|

|
Oh, great program..
Can use this program in EVC++ 4.0(MS Embedded Visual C++ 4.0)?
Mobile O/S : Windows CE 5.0..
God bless you..
|
|
|
|

|
great messagebox. I will be using it. I also bookmarked this.
|
|
|
|

|
First of all I think this is a great stuff, and thanks for sharing it.
I run into a problem right on the start when I add files to my existing project and try to compile it.
Error notes:
-XMessageBox.cpp(687) : error C2039: 'GetWindowLongPtr' : is not a member of '`global namespace''
-XMessageBox.cpp(687) : error C2065: 'GetWindowLongPtr' : undeclared identifier
-XMessageBox.cpp(687) : error C2065: 'GWLP_USERDATA' : undeclared identifier
-XMessageBox.cpp(1765) : error C2065: 'GWLP_WNDPROC' : undeclared identifier
-XMessageBox.cpp(1765) : error C2065: 'LONG_PTR' : undeclared identifier
-XMessageBox.cpp(2394) : error C2065: 'DWORD_PTR' : undeclared identifier
-XMessageBox.cpp(2433) : error C2664: 'CreateDialogIndirectParamA' : cannot convert parameter 4 from 'long (struct HWND__ *,unsigned int,unsigned int,long)' to 'int (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)
...
If you could help about this I'd be tankful. I'm using VC6.
|
|
|
|

|
Hello, is it possible to insert a clickable URL or link in the displayed text (like a html tag maybe ?)
Thank you for your good job!
|
|
|
|

|
Hello Hans,
First of all, this is just great. I use custom message boxes in my software and like you I got tired of writing the automatic resizing code for every dialog. I was planning to write a control like you have, so you save me a lot of work
Anyway, in the message boxes I use in my application, I can define an additional 'more' text. This means that the text is initially not visible. However, when the user clicks the More >> button, the message box (height) is expanded and the additional text is displayed to provide the user more information.
For example, and error dialog can see:
The server is not available at the moment.
The more text is:
In most cases, this problem is solved by checking your internet connection. If you don't know how to solve this problem, please contact your ISP (Internet Service Provider).
What do you think of this idea? If you want, I can implement it (it's quite simply actually), but maybe it's an idea to add this as default behavior to the message box.
Best regards,
|
|
|
|

|
Thank you for sharing, Hans.
|
|
|
|

|
Is there any way to control the max size of message box.
I am facing the problem of automatic word wrapping in windows Vista.
In Windows Vista the max size of message box have been changed and it is smaller than the max size on Windows XP.
AfxMessageBox has been used widely in my application and in may places '\n' has been used to reduce the size of the message box.
On Vista my message strings are automatically wrapped before '\n'(line break) due to this message formatting get disturbed.
Is there a way by which I can make the max size of message box on vista equal to the max size of message box in XP. So that the message formatting on Vista become sane as the formatting on XP.
|
|
|
|

|
Hi,
First of all, great function, thanks a lot for it.
I was looking at your new version and I think that a line of code is invalid.
Because I handle my own saving/loading, if I un-comment line 154
#define XMESSAGEBOX_DO_NOT_SAVE_CHECKBOX
I get an error in line 2747
encode(szKey);
this is because the previous
#endif
Seem to have been added too soon.
If you move it down past the last 2 new functions, (XMessageBoxGetCheckBox(...)), then it works fine.
Thanks
Sims
|
|
|
|

|
Nice work. It shows a lot of effort to produce a very versatile tool.
Did anyone already create a C# wrapper for it to help lazy coders like me?
|
|
|
|

|
Hi Hans,
you've got my 5 for your great work.
I have just one question:
Is there a way to make the message boxes more looks like the one in Vista?
(White background for the message, gray background for the buttons and
limitting the width)
Many thanks for your samples here on codeproject.
Bye
Joerg
|
|
|
|

|
Very nice article. I thought I've read all of your articles, cannot believe I missed this one
"The clue train passed his station without stopping." - John Simmons / outlaw programmer
"Real programmers just throw a bunch of 1s and 0s at the computer to see what sticks" - Pete O'Hanlon
"Not only do you continue to babble nonsense, you can't even correctly remember the nonsense you babbled just minutes ago." - Rob Graham
|
|
|
|

|
Is there a way to detect when a "don't ask" checkbox is checked or unchecked after a button is pressed? Also, is there a way to know if the message box will NOT be displayed because of a previous setting of "don't ask" checkboxes?
If not, this would be a great addition to this most useful class.
|
|
|
|

|
Is it possible to do it with current code,
(Original Message Box text is unelectable )
I think it will be very useful
|
|
|
|

|
Can't figured it out, please help
|
|
|
|

|
I'd like to handle the help myself but I need control of the Help button. If this was a CDialog I could override OnHelpInfo(). How and where do you get control of the Help Button?
Thanks, Neil
Neil Bartow
|
|
|
|

|
My appl runs on Mac and Windows. Until now, the standard Yes/No dialogs have been sufficient. But now I need custom buttons. Does anyone know of a dialog source code package that supports both Mac and Windows?
|
|
|
|

|
First let me say that this is a really useful messagebox replacement, thanks for sharing. There is one minor problem with it though, if you set windows to use large fonts the buttons on the message box do not increase in size (unlike the windows messagebox), so the text looks really squashed. br /> The problem is that you use constants for all the sizes in the message box, and these are in pixels, so the sizes never change even though the font is larger. To fix this I have modified the code to change these constants to dialog units (which in this case meant halving the values), and added corresponding member variables which I initialze in the constructor by converting the constants to pixel values. I then replaced all uses of the constants with the corresponding member variables and now everything works fine. I added some helper functions to make the conversions between dialog units and pixels easier, here is a sample of the changes: class CXDialogTemplate { enum { //ButtonWidth = 78, ButtonWidth = 39, // d.l.u's //ButtonTimeoutWidth = 100, ButtonTimeoutWidth = 50, // d.l.u's //ButtonHeight = 24, ButtonHeight = 12, // d.l.u's ... }; ... long m_baseunitY; // vertical dialog base units long m_baseunitX; // horizontal dialog base units int m_button_width; // ButtonWidth converted to pixels int m_button_height; // ButtonHeight converted to pixels ... long PixelToDlgunitX( long pixelX ) { return MulDiv(pixelX, 4, m_baseunitX); } long PixelToDlgunitY( long pixelY ) { return MulDiv(pixelY, 8, m_baseunitY); } long DlgunitToPixelX( long dlgunitX ) { return MulDiv(dlgunitX, m_baseunitX, 4); } long DlgunitToPixelY( long dlgunitY ) { return MulDiv(dlgunitY, m_baseunitY, 8); } ... }; CXDialogTemplate::CXDialogTemplate(HWND hWnd, ... ) { ... // get dialog base units for use in converting pixels to dialog units m_baseunitY = HIWORD(GetDialogBaseUnits()); m_baseunitX = LOWORD(GetDialogBaseUnits()); // convert all fixed dimensions from dialog units to pixels m_button_width = DlgunitToPixelX( m_nTimeoutSeconds ? ButtonTimeoutWidth : ButtonWidth ); m_button_height = DlgunitToPixelY( ButtonHeight ); ... // use the member variables throughout code } Incidentally, for completeness I also added functions for converting from pixels to dialog units (PixelToDlgunitX and PixelToDlgunitY) and replaced your code with calls to these functions where you populate the relevant DLGTEMPLATE members. Thanks for a very useful project, and I hope this helps to make it even better! Brian
|
|
|
|

|
The length of the message for a message box is capped by the size of m_szCaption at 1024 regardless of your MessageSize parameter. I hesitate to just crank this up because it is used for every control on the box; eg, button labels, etc. Perhaps this should be dynamically allocated when CAxDialogItem is constructed...
|
|
|
|

|
Hello,
I would like to point out to another MessageBox enhancer which is a wrapper over standard MessageBox - http://alax.info/blog/127
That MessageBox would hook newly created Windows dialog and modify it as necessary (does not create dialog from scratch).
Source code is available on the blog.
|
|
|
|

|
Whats the best way to proceed if the application is minimized?
I've implemented XmessageBox to display a message before my app is closed. The XMessagebox works great under most circumstances, but if my application is minimized when it tries to display the XMessagebox then I get hung up at: XMessageBox::Display()
rc = ::DialogBoxIndirectParam(hInstance, (LPCDLGTEMPLATE) pBuffer,
m_hWnd, MsgBoxDlgProc, (LPARAM) this);
I'm thinking of skipping the messagebox alltogether if the app is minimized, is this the best way to proceed?
|
|
|
|

|
I'm using the XMessageBox as timeout Box.
It works as expected when you press a button before timeout,
but if you just select another button,e.g by using the tabulator key,
then on timeout XMessageBox chooses still the default button and not
the focus button as one would expect.
This means that your XMessageBox can't be used with a keyboard alone.
Your class can only be used in a meaningful way with a mouse.
What would I have to do to activate the focus button instead of the
default button at timeout?
Best Regards Martin
|
|
|
|

|
Nice work!
But is it also possible to use the buttons-captions depend on the systems locale-settings?
Rgds,
Michael
|
|
|
|

|
Thanks for this MessageBox. I am using in two of my applications.
I want to know:
- How Can I change font for Message (if possible) ?
- How Can I change font for Caption (if possible) ?
Ana
|
|
|
|

|
I noticed, that if the parent window located partially outside of the screeen, message box will displayed incorrectly (in off-screen space, fully or partially).
There is improved centering code snippet, that can solve this problem:
BOOL CALLBACK CXDialogTemplate::MsgBoxDlgProc(...)
{
...
CXRect mainRect, dlgRect;
::GetWindowRect(::GetParent(hwnd), &mainRect);
::GetWindowRect(hwnd, &dlgRect);
int x = (mainRect.right + mainRect.left)/ 2 - dlgRect.Width() / 2;
int y = (mainRect.bottom + mainRect.top) / 2 - dlgRect.Height() / 2;
CXRect desktopRect;
::SystemParametersInfo( SPI_GETWORKAREA, NULL, &desktopRect, 0 );
if ( y + dlgRect.Height() > desktopRect.bottom )
{
y = desktopRect.bottom - dlgRect.Height();
}
if ( x + dlgRect.Width() > desktopRect.right )
{
x = desktopRect.right - dlgRect.Width();
}
if ( y < desktopRect.top )
{
y = desktopRect.top;
}
if ( x < desktopRect.left )
{
x = desktopRect.left;
}
::MoveWindow(hwnd, x, y, dlgRect.Width(), dlgRect.Height(), TRUE);
...
}
|
|
|
|

|
Thanks for this highly useful tool!
Here's a patch, in unidiff format, that will allow it compile and run natively under 64-bit Windows (IA64, x64).
Some of the changes are simply for eliminating warnings, but there are a few crucial fixes for 64-bit pointer truncation, which can cause runtime crashes.
Usage:
- Copy the following code into a text file (e.g. patchfile.txt)
- Obtain patch for win32 (http://gnuwin32.sourceforge.net/packages/patch.htm)
- Run the following command in the same directory as XMessageBox.cpp:
patch XMessageBox.cpp patchfile.txt
Patch for XMessageBox.cpp (version 1.5):
--- XMessageBox.cpp
+++ XMessageBox.cpp
@@ -346,7 +346,7 @@
EDefault = 0x00
};
- static BOOL CALLBACK MsgBoxDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM me);
+ static INT_PTR CALLBACK MsgBoxDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM me);
void Unset(EOptions id) { m_Options &= ~id;};
void Set(EOptions id) { m_Options |= id;};
@@ -586,7 +586,7 @@
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
- ::DrawIcon(hdc, 0, 0, (HICON)(::GetWindowLong(hwnd, GWL_USERDATA)));
+ ::DrawIcon(hdc, 0, 0, (HICON)(::GetWindowLongPtr(hwnd, GWLP_USERDATA)));
EndPaint(hwnd, &ps);
}
@@ -1451,19 +1451,19 @@
-BOOL CALLBACK CXDialogTemplate::MsgBoxDlgProc(HWND hwnd,
+INT_PTR CALLBACK CXDialogTemplate::MsgBoxDlgProc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
- CXDialogTemplate* Me = (CXDialogTemplate*) ::GetWindowLong(hwnd, GWL_USERDATA);
+ CXDialogTemplate* Me = (CXDialogTemplate*) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
HWND hwndChild;
switch (message)
{
case WM_INITDIALOG:
{
- ::SetWindowLong(hwnd, GWL_USERDATA, lParam); + ::SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); Me = (CXDialogTemplate*) lParam;
_ASSERTE(Me);
@@ -1496,9 +1496,9 @@
::GetClassName(hwndChild, szClassName, countof(szClassName)-2);
if (_tcsicmp(szClassName, _T("Button")) == 0)
{
- LONG nStyle = ::GetWindowLong(hwndChild, GWL_STYLE);
+ LONG_PTR nStyle = ::GetWindowLongPtr(hwndChild, GWL_STYLE);
nStyle |= WS_DISABLED;
- ::SetWindowLong(hwndChild, GWL_STYLE, nStyle);
+ ::SetWindowLongPtr(hwndChild, GWL_STYLE, nStyle);
}
::EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_CLOSE, MF_GRAYED);
}
@@ -1533,8 +1533,8 @@
HWND hwndIcon;
hwndIcon = ::GetDlgItem(hwnd, 1000);
- ::SetWindowLong(hwndIcon, GWL_WNDPROC, (LONG) IconProc);
- ::SetWindowLong(hwndIcon, GWL_USERDATA, (LONG) Me->m_hIcon);
+ ::SetWindowLongPtr(hwndIcon, GWLP_WNDPROC, (LONG_PTR)IconProc);
+ ::SetWindowLongPtr(hwndIcon, GWLP_USERDATA, (LONG_PTR)Me->m_hIcon);
}
if (Me->m_nStyle & MB_TOPMOST)
@@ -1635,7 +1635,7 @@
BOOL bFlag = FALSE;
if (hwndChild && ::IsWindow(hwndChild))
- bFlag = ::SendMessage(hwndChild, BM_GETCHECK, 0, 0);
+ bFlag = (BOOL)::SendMessage(hwndChild, BM_GETCHECK, 0, 0);
if (Me->Option(DoNotAskAgain))
wParam |= bFlag ? MB_DONOTASKAGAIN : 0;
@@ -1808,9 +1808,9 @@
::GetClassName(hwndChild, szClassName, countof(szClassName)-2);
if (_tcsicmp(szClassName, _T("Button")) == 0)
{
- LONG nStyle = ::GetWindowLong(hwndChild, GWL_STYLE);
+ LONG_PTR nStyle = ::GetWindowLongPtr(hwndChild, GWL_STYLE);
nStyle &= ~WS_DISABLED;
- ::SetWindowLong(hwndChild, GWL_STYLE, nStyle);
+ ::SetWindowLongPtr(hwndChild, GWL_STYLE, nStyle);
}
}
} @@ -1897,7 +1897,7 @@
TCHAR szTitle[1024];
_tcsncpy(szTitle, m_lpszCaption, countof(szTitle)-1);
szTitle[countof(szTitle)-1] = _T('\0');
- int nTitleLen = _tcslen(szTitle);
+ int nTitleLen = (int)_tcslen(szTitle);
int i = 0;
@@ -1984,7 +1984,7 @@
for (i = 0; i < m_dlgTempl.cdit; i++)
{
- pdest = (BYTE*)(((DWORD)pdest + 3) & ~3); + pdest = (BYTE*)(((DWORD_PTR)pdest + 3) & ~3); memcpy(pdest, (void *)&m_pDlgItemArray[i]->m_dlgItemTemplate,
sizeof(DLGITEMTEMPLATE));
pdest += sizeof(DLGITEMTEMPLATE);
@@ -1995,7 +1995,7 @@
- int nChars = _tcslen(m_pDlgItemArray[i]->m_pszCaption) + 1; + int nChars = (int)_tcslen(m_pDlgItemArray[i]->m_pszCaption) + 1;
WCHAR * pchCaption = new WCHAR[nChars+100];
@@ -2020,7 +2020,7 @@
_ASSERTE(pdest - pBuffer <= nBufferSize); HINSTANCE hInstance = GetModuleHandle(NULL);
- rc = ::DialogBoxIndirectParam(hInstance, (LPCDLGTEMPLATE) pBuffer,
+ rc = (int)::DialogBoxIndirectParam(hInstance, (LPCDLGTEMPLATE) pBuffer,
m_hWnd, MsgBoxDlgProc, (LPARAM) this);
LocalUnlock(hLocal);
@@ -2123,7 +2123,7 @@
- int stringLength = lpszCaption ? _tcslen(lpszCaption) : 0; + int stringLength = (int)(lpszCaption ? _tcslen(lpszCaption) : 0); m_pszCaption = new TCHAR [stringLength + 1]; _tcscpy(m_pszCaption, lpszCaption ? lpszCaption : _T("")); }
-- modified at 16:41 Saturday 9th December, 2006
|
|
|
|

|
Great project by the way, I was looking for something I could drop into a WTL project and this has worked perfectly.
My question is what is XMSGBOXPARAMS::RightJustifyButtons meant to do. I assumed that by using this I could place the question mark, created by using MB_YESNO on the right hand side of the question I put in as the message text of the text box, but as far as I can see nothing has changed.
|
|
|
|

|
Great project by the way, I was looking for something I could drop into a WTL project and this has worked perfectly.
My question is what is XMSGBOXPARAMS::RightJustifyButtons meant to do. I assumed that by using this I could place the question mark, created by using MB_YESNO on the right hand side of the question I put in as the message text of the text box, but as far as I can see nothing has changed.
|
|
|
|
|

|
I wish to insert a custom icon, but am having trouble getting it to work for me.
I have searched through the demo project, but have not been able to find sample code showing how to implement a custom icon.
Could someone kindly provide a sample?
I am guessing it would look something like this, but I must be doing something wrong here:
strcpy(xmb.szCustomButtons ,"&Yes\n&No thank you");
xmb.nIdIcon=0;
strcpy(xmb.szIcon,"MYICON");
if (IDCUSTOM1 == XMessageBox(
NULL, //NULL means no owner window
"Proceed?",
"My caption", //window caption
MB_DEFBUTTON2 //second button is default button
//| MB_ICONASTERISK //must I comment this if I am calling for a custom icon?
| MB_TASKMODAL,
&xmb //call optional parameters
))
|
|
|
|

|
After trying to migrate from 1.4 to 1.5, I got two build errors of this nature when building for non-MFC:
C:\timeto\XMessageBox.cpp(1948) : error C2065: 'ASSERT' : undeclared identifier
... one for 'TRACE' and one for 'ASSERT'.
I was able to fix the one for 'TRACE' by reincluding the line
#include "XTrace.h"
which was removed in 1.5 (relative to 1.4)
But I don't have a fix for the 'ASSERT' problem.
Please advise. Thank you in advance, David.
|
|
|
|

|
When we add the DONOTASKAGAIN parameter to a dialog, there seems to be an apparent dysfunction:
Consider this example:
strcpy(xmb.szCustomButtons ,"&Yes\n&No");
xmb.nLine=4;
if (IDCUSTOM2 == XMessageBox( //if they answer No
NULL, //NULL = no owner window
"Would you like to do it?",
(LPSTR) "Report",
MB_ICONQUESTION //display question mark icon
| MB_DEFBUTTON1 //first button is default button
| MB_DONOTASKAGAIN //checkbox for not asking again
| MB_TASKMODAL,
&xmb //call optional parameters
) )
{
msg ("No problem. Click OK to continue.");
return NO;
}
else //they answer Yes
.
.
In the above example, if the user clicks Yes or No, they get the correct outcome. However if they click the Do Not Ask checkbox and then click No, they what-seems-wrongly-to-me get the DEFBUTTON1 outcome. Am I misunderstanding the intention and/or the coding here?
So does clicking the checkbox intended to:
- always repeat what they chose in the future?, or
- always repeat the DEFBUTTON1 response in the future?, or
- always choose the DEFBUTTON1 response starting immediately no matter which button they click?, or
- always skip execution of the XMESSAGBOX function entirely in the future?
Thank you in advance for this clarity.
|
|
|
|

|
I have this working in Borland C++ V5 if anyone is interested. You need to make the following four changes. The author may wish to make the changes in the source. Excellent little function by the way. //1 - assert changes - include assert.h #include <assert.h> #define ASSERT assert //2 - order change #include <tchar.h> //Include tchar.h must PRECEDE crtdbg.h for Borland C++ #include <crtdbg.h> //3 - Trace changes #undef TRACE //#define TRACE ((void)0) #define TRACE (void) //4 - must cast (DLGPROC) in second line to make it work rc = ::DialogBoxIndirectParam(hInstance, (LPCDLGTEMPLATE) pBuffer, m_hWnd, (DLGPROC) MsgBoxDlgProc, (LPARAM) this);
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
A reverse-engineered non-MFC MessageBox() that includes custom checkboxes.
| Type | Article |
| Licence | CPOL |
| First Posted | 12 Jul 2001 |
| Views | 470,405 |
| Bookmarked | 391 times |
|
|