|
|
Comments and Discussions
|
|
 |

|
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
|
|
|
|

|
I've confirmed this is a problem, and I'm looking into it now.
|
|
|
|

|
Please replace code at end of CXDialogTemplate::Display() with this code:
HWND hDlg = ::CreateDialogIndirectParam(hInstance, (LPCDLGTEMPLATE) pBuffer,
m_hWndOwner, MsgBoxDlgProc, (LPARAM) this);
_ASSERTE(hDlg);
if (hDlg)
{
HWND hwnd = m_hWndOwner;
while (hwnd && IsWindow(hwnd))
{
::EnableWindow(hwnd, FALSE);
hwnd = ::GetParent(hwnd);
}
MSG msg;
memset(&msg, 0, sizeof(msg));
while (!IsEnded())
{
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
break;
}
if (msg.message == WM_KEYDOWN)
{
if (OnKeyDown(hDlg, msg.wParam, msg.lParam))
continue;
}
if (!::IsDialogMessage(hDlg, &msg))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
else if (!IsEnded())
{
::WaitMessage(); }
}
TRACE(_T("===== message loop ended\n"));
if (msg.message == WM_QUIT)
{
TRACE(_T("_____ WM_QUIT seen\n"));
PostQuitMessage((int)msg.wParam);
}
hwnd = m_hWndOwner;
while (hwnd && IsWindow(hwnd))
{
::EnableWindow(hwnd, TRUE);
hwnd = ::GetParent(hwnd);
}
::DestroyWindow(hDlg);
}
|
|
|
|
|

|
Same problem, but solution don´t work for me.
I call XMessageBox(NULL, ....., so You do hwnd = ::GetActiveWindow();, this returns my AppMainWnd, then hwnd = ::GetLastActivePopup(hwnd) returns same window. ( I have modeless dialog on it )
So when yo make
HWND hwnd = m_hWndOwner;
while (hwnd && IsWindow(hwnd))
{
::EnableWindow(hwnd, FALSE);
hwnd = ::GetParent(hwnd);
}
My modeless dialogs remains receiving messages, and procesing them...
PD: Great class. I used version 1.4 for some years and works fine.
|
|
|
|

|
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!
|
|
|
|

|
This has been fixed in the latest version which is available here.
|
|
|
|

|
Is this new version of XMessageBox (v1.11 or onwards) still Open source and have the same licence to use?
I didn't find any link to download on this suggested link.
Please suggest.
|
|
|
|

|
Member 3599795 wrote: Is this new version of XMessageBox (v1.11 or onwards) still Open source and have the same licence to use?
No. The link I gave has a Paypal Add To Cart button at the bottom of the page. The latest version is not open source and is no longer free.
You can still download v1.10 and use it for free.
|
|
|
|

|
thanx a lot for the great code, but you should clearly write about the licensing conditions of the releases after 1.10. I missed V 1.11 commercial release
Press F1 for help or google it.
Greetings from Germany
|
|
|
|

|
You can try this code:
//If main window is minimized
CFrameWnd *pFrame = (CFrameWnd *)AfxGetApp()->GetMainWnd();
::SetForegroundWindow(pFrame->m_hWnd);
if(pFrame->IsIconic())
pFrame->ShowWindow(SW_RESTORE);
//Then call the XMessageBox
int res = ::XMessageBox(NULL , _T("Some question"), AfxGetAppName(),
MB_OKCANCEL | MB_DONOTASKAGAIN | MB_ICONINFORMATION | MB_NORESOURCE);
|
|
|
|

|
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
|
|
|
|
|

|
Support for long captions plus other new features has been added to the latest version of XMessageBox which is available here.
|
|
|
|
|

|
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!
|
|
|
|

|
Thank you for taking the time to write all this! I appreciate your kind offer. I would like very much to have your changes. Please send complete source, not just diffs - I have my own program for doing diffs visually.
Please zip project (do not include exe, gmail will not allow) and email to me. You can find my email address in About box of demo program. If you could also send a few notes of what you changed that would be great.
|
|
|
|

|
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.
|
|
|
|

|
Can you compile the VC6 demo project?
|
|
|
|

|
Hi and thanks for quick replay.
I've tried to compile VC6 demo and can't do it.
Build window displays this:
Compiling resources...
Compiling...
StdAfx.cpp
NOTE: WINVER has been defined as 0x0500 or greater which enables
Windows NT 5.0 and Windows 98 features. When these headers were released,
Windows NT 5.0 beta 1 and Windows 98 beta 2.1 were the current versions.
For this release when WINVER is defined as 0x0500 or greater, you can only
build beta or test applications. To build a retail application,
set WINVER to 0x0400 or visit http://www.microsoft.com/msdn/sdk
to see if retail Windows NT 5.0 or Windows 98 headers are available.
See the SDK release notes for more information.
Compiling...
About.cpp
Gallery.cpp
ROEdit.cpp
XHyperLink.cpp
XMessageBox.cpp
compiling for MFC
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(685) : error C2039: 'GetWindowLongPtr' : is not a member of '`global namespace''
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(685) : error C2065: 'GetWindowLongPtr' : undeclared identifier
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(685) : error C2065: 'GWLP_USERDATA' : undeclared identifier
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(1695) : error C2039: 'SetWindowLongPtr' : is not a member of '`global namespace''
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(1695) : error C2065: 'SetWindowLongPtr' : undeclared identifier
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(1763) : error C2065: 'GWLP_WNDPROC' : undeclared identifier
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(1763) : error C2065: 'LONG_PTR' : undeclared identifier
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(1763) : error C2146: syntax error : missing ')' before identifier 'IconProc'
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(1763) : error C2059: syntax error : ')'
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(1764) : error C2146: syntax error : missing ')' before identifier 'Me'
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(1764) : error C2059: syntax error : ')'
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(2392) : error C2065: 'DWORD_PTR' : undeclared identifier
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(2392) : error C2146: syntax error : missing ')' before identifier 'pdest'
D:\My Project\Primjeri\XMessageBox_demo\src\XMessageBox.cpp(2392) : error C2059: syntax error : ')'
D:\My Project\Primjeri\XMessageBox_demo\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 in
t,unsigned int,long)'
None of the functions with this name in scope match the target type
XMsgBoxTest.cpp
XMsgBoxTestDlg.cpp
Generating Code...
Error executing cl.exe.
XMsgBoxTest.exe - 15 error(s), 0 warning(s)
|
|
|
|
 |
|
|
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,370 |
| Bookmarked | 391 times |
|
|