 |
|
 |
Dear Author,
Congratulations - Within no time, I integrated your MessageBox into my code. I did a bit of placement changes (thanks all of these were provided by you as configurable variables).
I also skinned the messagebox (as all the UI in my app is skinned).
I just have one problem - After skinning the icon on the message-box is NOT drawn correctly - I mean it is surrounded with a Black border rather than the Messagebox background color. I definitely know that this is a problem of not managing the alpha channel well - I seem to have read about this on CP but somehow unable to find that article right now.
Other than that everything works fine - I have opted for the Class version of your messagebox, since I wanted to skin it.
You get five points from me.
Best regards,
Yogesh Dhakad
|
|
|
|
 |
|
 |
Glad see your this idea ,but now i have one question :
i want to make one "MessageBox" by my self to replace System "MessageBox",of course use you code, i can do it ,but if another application to call the system "MessageBox", it is not my "MessageBox" and it is all the same System "MessageBox", and not my "MessageBox"
I think if you have enough time ,you can help me ,thanks
|
|
|
|
 |
|
 |
Hello,
Thanks for the tip. But I was puzzled that your code did NOT actually go to its logical end: to NOT show a dialog box. After running the demo and finding it was NOT doing what was intended, for an hour I scratched my head deciphering your code. It's like a guy who shows you how to buy 4 tires, and JUST that. Then you've got 4 tires but you DON'T have a car on the road, if the guy does NOT tell you how to install those 4 tires. Very strange thinking of yours... Here's the obvious way to rewrite MsgBoxHook::NabMessageBox():
int rc = 0;
bool bChecked = false;
if (mapChecked.find(lpszText) == mapChecked.end()) {
mapChecked[lpszText].strDoNotString = ((nType&0xF) ?
g_strDoNotShowAgain : g_strDoNotAskAgain);
mapChecked[lpszText].bChecked = false;
} else bChecked = mapChecked[lpszText].bChecked;
if (!bChecked) rc=AfxMessageBox(lpszText,nType,nIDHelp);
return (bChecked ? -1 : 1) * rc;
arenaud01
|
|
|
|
 |
|
|
 |
|
 |
Hello,
did not hear of this function before but the behaviour is not exactly what we expect as written in the Remarks section:
Note Do not confuse "Do not show this dialog box" with "Remember this answer". SHMessageBoxCheck does not provide "Remember this answer" functionality. If the user opts to suppress the message box again, the function does not preserve which button they clicked. Instead, subsequent invocations of SHMessageBoxCheck simply return the value specified by iDefault. Consider the following example.
int iResult = SHMessageBoxCheck(hwnd, TEXT("Do you want to exit without saving?"),
TEXT("Warning"), MB_YESNO, IDNO,
TEXT("{d9108ba3-9a61-4398-bfbc-b02102c77e8a}");
If the user selects "In the future, do not show me this dialog box" and clicks the "Yes" button, SHMessageBoxCheck returns IDYES. However, the next time this code is executed, SHMessageBoxCheck does not return IDYES, even though the user selected "Yes" originally. Instead, it returns IDNO, because that is the value specified by iDefault.
Regards,
nabocorp
|
|
|
|
 |
|
 |
Hello,
do you know if there's a way to check if someone is trying to hook on my dialog and, eventually, reject its attempt?
Thanx,
Fabio
|
|
|
|
 |
|
 |
Why would you go to all that trouble.
Easy steps!
1 Create a project dlg or whatever.
2 Put a button on it.
3 Double click the button.
4 Add a child dlg.
5 Put a check box on it the child dlg
Add a static ctrl to child
Add a CSring var named m_stitle to child
In the init of the child dlg add
SetWindowText(m_stitle);
Set a var to the static ctrl called m_sQuestion.
Add a boolean var for the check box set it to FALSE
In the parent dlg in the button handler add the following.
CString m_strTitle
CString m_strQuestion;
m_strTitle = "Close File Verification";
m_strQuestion = "Do you really want to close this window?";
m_iResourceID = 1001;
void CCkmsgboxDlg::OnButton1()
{
CDlgTest dlg;
dlg.m_stitle.Format("%s",m_strTitle);
dlg.m_strQuestion.Format("%s",m_strQuestion);
if(dlg.DoModal() == IDOK){
if(dlg.m_bcked){
CString tmp;
tmp.Format("%d",m_iResourceID);
AfxMessageBox("Checked");
AfxGetApp()->WriteProfileInt("Section",tmp,TRUE);
}else{
AfxMessageBox("Not Checked");
}
}
}
Ole'
It took me five minutes to do something that you have taken a huge amount of code to do.
My way is more reliable and can be called with different vars just as yours.
What do you need a class for when a structure is overkill? Why reinvent verbose code with even more verbose code?
Sorry but I can't believe it has come to this.... big code == sloppy code. Mine is much too large as is,but,I onlt took five minutes.
"Naked we come and bruised we go."
- James Douglas Morrison
Best Wishes,
ez_way
|
|
|
|
 |
|
 |
For one message box, this is simple. But for ten? twenty?
To emulate the Windows provided message box class completely, is a daunting task. Lyouting, different levels of modality, up to some special settings that work also on low memory conditions (to pop an "out of memory" message).
I never really know a killer from a savior boost your code || Fold With Us! || sighist | doxygen
|
|
|
|
 |
|
 |
Did not see this message until now but obviously you missed the point. The goal is not to add a checkbox to one message box but to any you want without having to create a new dialog just to display it.
|
|
|
|
 |
|
 |
When determining the check box height in nbMessageBox, the code used is as follows:
// more metrics
int nCheckboxHeight = min(13, size.cy);
13 is the height of the checkbox bitmap. If the text height is less than or greater than 13, the control will be sized too small.
I think you want max instead of min.
"You will be killed by a poisoned fortune cookie." - Old fortune cookie proverb
|
|
|
|
 |
|
 |
This code isn't working for me on Win98. In particular, it's the following code segment that fails:
Inside MoveButtons in MsgBoxHook.cpp...
// get the window placement (position and size)
WINDOWPLACEMENT placement;
::GetWindowPlacement(hwnd, &placement);
CRect rc = placement.rcNormalPosition;
::SetWindowPos(hwnd, NULL, rc.left+offset/2, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER);
The rcNormalPosition variable contains negative values for me when called on Win98. This causes the buttons to move off the message box when the SetWindowPos function is called. (making it impossible to close the message box) The demo appears to work because the condition isn't being met that will trigger execution of the above code:
Inside OnSubclassedInit in nbMessageBox.cpp...
// make sure the box is wide enough for the checkbox
...
if (rc.Width() < size.cx)
If you make the check box text long, and the message box text short, it will trigger the above, causing the problems on Win98.
Here's the fix that worked for me:
In the MoveButtons function, replace
// get the window placement (position and size)
WINDOWPLACEMENT placement;
::GetWindowPlacement(hwnd, &placement);
CRect rc = placement.rcNormalPosition;
with
// get the window placement (position and size)
HWND hParentWnd = ::GetParent(hwnd);
CWnd* pParent = CWnd::FromHandle(hParentWnd);
ASSERT_VALID(pParent);
CRect rc;
::GetWindowRect(hwnd, rc);
pParent->ScreenToClient(rc);
Keep the SetWindowPos line as is.
"You will be killed by a poisoned fortune cookie." - Old fortune cookie proverb
|
|
|
|
 |
|
 |
There is one problem I've noticed with the code pertaining to calculating the check box size. (in the subclass)
The GetTextExtent function doesn't take into account underscores used for access keys.
i.e. &Don't show again - it includes the width of the ampersand in the text width calculation.
If you comment this code out:
//CSize size = pDC->GetTextExtent(strLabel);
and replace it with:
CRect rcLabel(0,0,0,0);
pDC->DrawText(strLabel, rcLabel, DT_SINGLELINE | DT_NOCLIP | DT_CALCRECT);
CSize size = rcLabel.Size();
It should work fine.
"You will be killed by a poisoned fortune cookie." - Old fortune cookie proverb
|
|
|
|
 |
|
 |
The approach is IMHO not good enough, as management of the "unique ID" is left to the caller, and so is resetting the memorized auto-response.
I use a different approach in my applications. I provide my own dialog (CMyMessageBox, if you will). That beast has a printf-like constructor with a resource string ID for the box title and one for the format string (plus a couple of other parameters, such as icon and button preferences).
The class computes a unique key based on the two resource string IDs. That is used to identify the history, and all management is done by CMyMessageBox:
...
CMyMessageBox oMsg(IDS_MGS_TITLE, IDS_MSG_FMT, MB_YESNO | MB_ICONSTOP, (LPCTSTR)sFilename);
if (oMsg.DoModal() == IDYES) {
...
} else {
...
}
The class also has (static) methods to clear the history, and one to clear the history of a given box (by title and format string resource IDs).
I find this is more powerful in terms of "unique ids", and more straight-forward (no hooks, subclassing, etc).
A matter of taste, though.
Bernd
|
|
|
|
 |
|
 |
What you suggest is a good management for the unique ID stuff and it could be used in conjunction with the rest of my code.
Although to display the message box I think that hook/subclassing is needed because otherwise it will probably hard to display the icon which matches the OS you are running (the icons have been updated with XP for instance) and also support XP themes. How do you handle this?
|
|
|
|
 |
|
 |
Also, your unique ID generation technique will fail in the cases where the message title and message id are used in multiple locations in the program.
I can think where there have been 'over write read only file' type title and message used in multiple locations in my programs, but you would want unique ID for each case.
C++/MFC/InstallShield since 1993
|
|
|
|
 |
|
 |
I see your concern. All I can say is that it works for me: I just know that the combination of format string and box title string resource ID is "unique enough" in my application, and I also think it should be in all applications.
In case the same message can occur in two (or more) locations, then you should provide distinct titles. Otherwise, how do you tell what's going on if this technical support inquirey lands on your desk ("customer always gets this message - what's going on")?
But, I agree this is a matter of programming discipline and my strategy is not fool-proof.
Bernd
|
|
|
|
 |
|
 |
MyMessageBox loads the icons as needed, and doesn't support themes. MB_ICONQUESTION simply calls ::LoadIcon(NULL, IDI_QUESTION).
Sufficient for my current requirements, but I begin to see the beauty of the hook. I'll study your code occasionally.
Bernd
|
|
|
|
 |
|
 |
I did exactly the same thing to detect a message box but my creteria is slighly different. My message bos has exactly 1 static icon, 1 static text, 1 to 4 buttons, no other controls, and has popup style.
Did you forget the help button?
Benjamin Tong
|
|
|
|
 |
|
 |
True! The funniest thing is that my original code included 4 buttons. When doing the review before submitting the article I was wondering why I did put 4 and not 3. Did not find the answer so I changed to code to detect 3 buttons max Probably because I never use help buttons in message boxes...
However as the MFC subclassing is the prefered method I won't update the article... Those who still want to use the hook may easily find the two lines where the modification is needed.
|
|
|
|
 |
|
 |
Why not just derive a class from the Windows Message Box to provide the same interface of messages like in the standard CDialog?
Regards,
Vitaly
Ultimate all-in-one XP-Style UI multiplatform solution: Tooltips, XP Menus, Hyperlinks, Drawing Graphics and formatted documents, plus powerful binary resource reuse. All Free 100%, visit www.tooltips.net now. The most powerful integrate UI library for developers in VC++, C#, Java, VB, Delphi, Borland C++, Borland C++ Builder, as well as any COM-compatible platform; Unified approach, cross-language OS, full .NET integration.
|
|
|
|
 |
|
 |
Which class exactly to you want to derive from?
|
|
|
|
 |
|
 |
Hook the message box window, and then write your own CDialog which will be handling all the standard messages, i.e. the one which will have:
HWND m_hWnd; virtual BOOL OnInitDialog(); virtual void OnPaint(HDC hDC);
....
etc.
And about the same for all the controls contained in the dialog box.
Thou it might be something close to what you have already created. I think i want even to write it just for myself. Wait for an article from me soon.
Peace!
Ultimate all-in-one XP-Style UI multiplatform solution: Tooltips, XP Menus, Hyperlinks, Drawing Graphics and formatted documents, plus powerful binary resource reuse. All Free 100%, visit www.tooltips.net now. The most powerful integrate UI library for developers in VC++, C#, Java, VB, Delphi, Borland C++, Borland C++ Builder, as well as any COM-compatible platform; Unified approach, cross-language OS, full .NET integration.
|
|
|
|
 |
|
 |
I run the demo in WinME and if I press the "Hoocked" button I cannot see the second messagge and the application freezes.
Why?
Peppe
|
|
|
|
 |
|
 |
I do not have a ME machine to test. Download the updated article and try using the Subclassed button to see if it works better.
|
|
|
|
 |
|
 |
Yes, OK!
If I press subclass botton it works.
Bye
|
|
|
|
 |