Allow to put URLs into "<>" and allow spaces and other chars there (as the RichEdit...
[TortoiseGit.git] / src / Utils / MiscUI / MessageBox.cpp
blobb642ddf13ea15efb909bce07374f8831e04d7611
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2013 - TortoiseGit
4 // Copyright (C) 2003-2008,2010 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 //#include "resource.h" //if you defined some IDS_MSGBOX_xxxx this include is needed!
22 #include "messagebox.h"
23 #include "ClipboardHelper.h"
24 #include "SmartHandle.h"
26 CMessageBox::CMessageBox(void)
27 : m_hIcon(NULL)
28 , m_uButton1Ret(1)
29 , m_uButton2Ret(2)
30 , m_uButton3Ret(3)
31 , m_uCancelRet(0)
32 , m_bShowCheck(FALSE)
33 , m_bDestroyIcon(FALSE)
34 , m_nDefButton(0)
35 , m_uType(0)
36 , m_bChecked(FALSE)
38 SecureZeroMemory(&m_LogFont, sizeof(LOGFONT));
41 CMessageBox::~CMessageBox(void)
43 if (m_bDestroyIcon)
44 ::DestroyIcon(m_hIcon);
47 UINT CMessageBox::ShowCheck(HWND hWnd, UINT nMessage, UINT nCaption, int nDef, LPCTSTR icon, UINT nButton1, UINT nButton2, UINT nButton3, LPCTSTR lpRegistry, UINT nCheckMessage/* = NULL*/, BOOL *bChecked)
49 CString sButton1;
50 CString sButton2;
51 CString sButton3;
52 CString sMessage;
53 CString sCaption;
54 CString nCheckMsg;
55 sButton1.LoadString(nButton1);
56 sButton2.LoadString(nButton2);
57 sButton3.LoadString(nButton3);
58 sMessage.LoadString(nMessage);
59 sCaption.LoadString(nCaption);
60 nCheckMsg.LoadString(nCheckMessage);
61 return CMessageBox::ShowCheck(hWnd, sMessage, sCaption, nDef, icon, sButton1, sButton2, sButton3, lpRegistry, nCheckMsg, bChecked);
64 UINT CMessageBox::ShowCheck(HWND hWnd, LPCTSTR lpMessage, LPCTSTR lpCaption, int nDef, LPCTSTR icon, LPCTSTR lpButton1, LPCTSTR lpButton2, LPCTSTR lpButton3, LPCTSTR lpRegistry, LPCTSTR lpCheckMessage/* = NULL*/, BOOL *bChecked)
66 //check the registry if we have to show the box or just return with the last used return value
67 //this would be the case if the user pressed "do not show again".
68 DWORD dwRetVal;
69 HKEY hKey;
70 CString path;
71 #ifdef XMESSAGEBOX_APPREGPATH
72 path = XMESSAGEBOX_APPREGPATH;
73 #else
74 path = "Software\\TortoiseGit\\";
75 path += AfxGetApp()->m_pszProfileName;
76 #endif
77 if (lpRegistry && *lpRegistry && RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_EXECUTE, &hKey)==ERROR_SUCCESS)
79 int size = sizeof(dwRetVal);
80 DWORD type;
81 if (RegQueryValueEx(hKey, lpRegistry, NULL, &type, (BYTE*) &dwRetVal,(LPDWORD) &size)==ERROR_SUCCESS)
83 ASSERT(type==REG_DWORD);
84 RegCloseKey(hKey);
85 return (UINT)dwRetVal; //return with the last saved value
87 else
89 RegCloseKey(hKey);
93 CMessageBox box;
94 box.m_bShowCheck = TRUE;
95 box.m_sRegistryValue = lpRegistry;
96 if (lpCheckMessage == NULL)
98 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
99 box.m_sCheckbox = _T("do not show again");
100 #else
101 CString m_i18l;
102 m_i18l.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN);
103 box.m_sCheckbox = m_i18l;
104 #endif
106 else
107 box.m_sCheckbox = lpCheckMessage;
108 box.m_bChecked = bChecked ? *bChecked : FALSE;
109 box.m_sButton1 = lpButton1;
110 box.m_sButton2 = lpButton2;
111 box.m_sButton3 = lpButton3;
112 box.m_hIcon = (HICON)::LoadImage(AfxGetResourceHandle(), icon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
113 if (box.m_hIcon == NULL)
114 box.m_hIcon = (HICON)::LoadImage(NULL, icon, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
115 else
116 box.m_bDestroyIcon = TRUE;
117 if (!IsWindow(hWnd))
118 hWnd = NULL;
119 int result = box.GoModal(CWnd::FromHandle(hWnd), lpCaption, lpMessage, nDef);
120 if (bChecked)
121 *bChecked = box.m_bChecked;
122 return result;
125 UINT CMessageBox::Show(HWND hWnd, LPCTSTR lpMessage, LPCTSTR lpCaption, int nDef, LPCTSTR icon, LPCTSTR lpButton1, LPCTSTR lpButton2/* = NULL*/, LPCTSTR lpButton3/* = NULL*/)
127 CMessageBox box;
128 box.m_sButton1 = lpButton1;
129 box.m_sButton2 = lpButton2;
130 box.m_sButton3 = lpButton3;
131 box.m_hIcon = (HICON)::LoadImage(AfxGetResourceHandle(), icon, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
132 if (box.m_hIcon == NULL)
133 box.m_hIcon = (HICON)::LoadImage(NULL, icon, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
134 else
135 box.m_bDestroyIcon = TRUE;
136 if (!IsWindow(hWnd))
137 hWnd = NULL;
138 return box.GoModal(CWnd::FromHandle(hWnd), lpCaption, lpMessage, nDef);
141 UINT CMessageBox::Show(HWND hWnd, UINT nMessage, UINT nCaption, int nDef, LPCTSTR icon, UINT nButton1, UINT nButton2, UINT nButton3)
143 CString sButton1;
144 CString sButton2;
145 CString sButton3;
146 CString sMessage;
147 CString sCaption;
148 sButton1.LoadString(nButton1);
149 sButton2.LoadString(nButton2);
150 sButton3.LoadString(nButton3);
151 sMessage.LoadString(nMessage);
152 sCaption.LoadString(nCaption);
153 return CMessageBox::Show(hWnd, sMessage, sCaption, nDef, icon, sButton1, sButton2, sButton3);
157 UINT CMessageBox::ShowCheck(HWND hWnd, UINT nMessage, UINT nCaption, UINT uType, LPCTSTR lpRegistry, UINT nCheckMessage, BOOL *bChecked)
159 CString sMessage;
160 CString sCaption;
161 CString sCheckMsg;
162 sMessage.LoadString(nMessage);
163 sCaption.LoadString(nCaption);
164 sCheckMsg.LoadString(nCheckMessage);
165 return CMessageBox::ShowCheck(hWnd, sMessage, sCaption, uType, lpRegistry, sCheckMsg, bChecked);
168 UINT CMessageBox::ShowCheck(HWND hWnd, LPCTSTR lpMessage, LPCTSTR lpCaption, UINT uType, LPCTSTR lpRegistry, LPCTSTR lpCheckMessage, BOOL *bChecked)
170 //check the registry if we have to show the box or just return with the last used return value
171 //this would be the case if the user pressed "do not show again".
172 DWORD dwRetVal;
173 HKEY hKey;
174 CString path;
175 #ifdef XMESSAGEBOX_APPREGPATH
176 path = XMESSAGEBOX_APPREGPATH;
177 #else
178 path = "Software\\TortoiseGit\\";
179 path += AfxGetApp()->m_pszProfileName;
180 #endif
181 if (lpRegistry && *lpRegistry && RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_EXECUTE, &hKey)==ERROR_SUCCESS)
183 int size = sizeof(dwRetVal);
184 DWORD type;
185 if (RegQueryValueEx(hKey, lpRegistry, NULL, &type, (BYTE*) &dwRetVal,(LPDWORD) &size)==ERROR_SUCCESS)
187 ASSERT(type==REG_DWORD);
188 RegCloseKey(hKey);
189 return (UINT)dwRetVal; //return with the last saved value
191 else
193 RegCloseKey(hKey);
197 CMessageBox box;
198 box.m_bShowCheck = TRUE;
199 box.m_sRegistryValue = lpRegistry;
200 if (lpCheckMessage == NULL)
202 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
203 box.m_sCheckbox = _T("do not show again");
204 #else
205 CString m_i18l;
206 m_i18l.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN);
207 box.m_sCheckbox = m_i18l;
208 #endif
210 else
211 box.m_sCheckbox = lpCheckMessage;
212 box.m_bChecked = bChecked ? *bChecked : FALSE;
213 if (!IsWindow(hWnd))
214 hWnd = NULL;
215 int result = box.GoModal(CWnd::FromHandle(hWnd), lpCaption, lpMessage, box.FillBoxStandard(uType));
216 if (bChecked)
217 *bChecked = box.m_bChecked;
218 return result;
221 UINT CMessageBox::Show(HWND hWnd, UINT nMessage, UINT nCaption, UINT uType, LPCTSTR sHelpPath)
223 CString sMessage;
224 CString sCaption;
225 sMessage.LoadString(nMessage);
226 sCaption.LoadString(nCaption);
227 return CMessageBox::Show(hWnd, sMessage, sCaption, uType, sHelpPath);
230 UINT CMessageBox::Show(HWND hWnd, LPCTSTR lpMessage, LPCTSTR lpCaption, UINT uType, LPCTSTR sHelpPath)
232 CMessageBox box;
234 if (!IsWindow(hWnd))
235 hWnd = NULL;
236 if (sHelpPath)
237 box.SetHelpPath(sHelpPath);
238 return box.GoModal(CWnd::FromHandle(hWnd), lpCaption, lpMessage, box.FillBoxStandard(uType));
241 UINT CMessageBox::Show(HWND hWnd, UINT nMessage, UINT nCaption, UINT uType, UINT nHelpID)
243 CMessageBox box;
244 CString sMessage;
245 CString sCaption;
246 sMessage.LoadString(nMessage);
247 sCaption.LoadString(nCaption);
249 if (!IsWindow(hWnd))
250 hWnd = NULL;
251 box.SetHelpID(nHelpID);
253 return box.GoModal(CWnd::FromHandle(hWnd), sCaption, sMessage, box.FillBoxStandard(uType));
256 bool CMessageBox::RemoveRegistryKey(LPCTSTR lpRegistry)
258 HKEY hKey;
259 CString path;
260 #ifdef XMESSAGEBOX_APPREGPATH
261 path = XMESSAGEBOX_APPREGPATH;
262 #else
263 path = "Software\\TortoiseGit\\";
264 path += AfxGetApp()->m_pszProfileName;
265 #endif
266 if (RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
268 bool ret = !!RegDeleteValue(hKey, lpRegistry);
269 RegCloseKey(hKey);
270 return ret;
272 return false;
275 int CMessageBox::FillBoxStandard(UINT uType)
277 int ret = 1;
278 m_uType = uType;
279 m_uCancelRet = IDCANCEL;
280 //load the icons according to uType
281 switch (uType & 0xf0)
283 case MB_ICONEXCLAMATION:
284 m_hIcon = (HICON)::LoadImage(NULL, IDI_EXCLAMATION, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
285 ::MessageBeep(MB_ICONEXCLAMATION);
286 break;
287 case MB_ICONASTERISK:
288 m_hIcon = (HICON)::LoadImage(NULL, IDI_ASTERISK, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
289 ::MessageBeep(MB_ICONASTERISK);
290 break;
291 case MB_ICONQUESTION:
292 m_hIcon = (HICON)::LoadImage(NULL, IDI_QUESTION, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
293 ::MessageBeep(MB_ICONQUESTION);
294 break;
295 case MB_ICONHAND:
296 m_hIcon = (HICON)::LoadImage(NULL, IDI_HAND, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
297 ::MessageBeep(MB_ICONHAND);
298 break;
300 //set up the button texts
301 switch (uType & 0xf)
303 case MB_ABORTRETRYIGNORE:
304 #ifndef IDS_MSGBOX_ABORT
305 m_sButton1 = "Abort";
306 #else
307 m_i18l.LoadString(IDS_MSGBOX_ABORT);
308 m_sButton1 = m_i18l;
309 #endif
310 m_uButton1Ret = IDABORT;
311 #ifndef IDS_MSGBOX_RETRY
312 m_sButton2 = "Retry";
313 #else
314 m_i18l.LoadString(IDS_MSGBOX_RETRY);
315 m_sButton2 = m_i18l;
316 #endif
317 m_uButton2Ret = IDRETRY;
318 #ifndef IDS_MSGBOX_IGNORE
319 m_sButton3 = "Ignore";
320 #else
321 m_i18l.LoadString(IDS_MSGBOX_IGNORE);
322 m_sButton3 = m_i18l;
323 #endif
324 m_uButton3Ret = IDIGNORE;
325 break;
326 case MB_CANCELTRYCONTINUE:
327 #ifndef IDS_MSGBOX_CANCEL
328 m_sButton1 = "Cancel";
329 #else
330 m_i18l.LoadString(IDS_MSGBOX_CANCEL);
331 m_sButton1 = m_i18l;
332 #endif
333 m_uButton1Ret = IDCANCEL;
334 #ifndef IDS_MSGBOX_TRYAGAIN
335 m_sButton2 = "Try Again";
336 #else
337 m_i18l.LoadString(IDS_MSGBOX_TRYAGAIN);
338 m_sButton2 = m_i18l;
339 #endif
340 m_uButton2Ret = IDTRYAGAIN;
341 #ifndef IDS_MSGBOX_CONTINUE
342 m_sButton3 = "Continue";
343 #else
344 m_i18l.LoadString(IDS_MSGBOX_CONTINUE);
345 m_sButton3 = m_i18l;
346 #endif
347 m_uButton3Ret = IDCONTINUE;
348 break;
349 case MB_OKCANCEL:
350 #ifndef IDS_MSGBOX_OK
351 m_sButton1 = "Ok";
352 #else
353 m_i18l.LoadString(IDS_MSGBOX_OK);
354 m_sButton1 = m_i18l;
355 #endif
356 m_uButton1Ret = IDOK;
357 #ifndef IDS_MSGBOX_CANCEL
358 m_sButton2 = "Cancel";
359 #else
360 m_i18l.LoadString(IDS_MSGBOX_CANCEL);
361 m_sButton2 = m_i18l;
362 #endif
363 m_uButton2Ret = IDCANCEL;
364 break;
365 case MB_RETRYCANCEL:
366 #ifndef IDS_MSGBOX_RETRY
367 m_sButton1 = "Retry";
368 #else
369 m_i18l.LoadString(IDS_MSGBOX_RETRY);
370 m_sButton1 = m_i18l;
371 #endif
372 m_uButton1Ret = IDRETRY;
373 #ifndef IDS_MSGBOX_CANCEL
374 m_sButton2 = "Cancel";
375 #else
376 m_i18l.LoadString(IDS_MSGBOX_CANCEL);
377 m_sButton2 = m_i18l;
378 #endif
379 m_uButton2Ret = IDCANCEL;
380 break;
381 case MB_YESNO:
382 #ifndef IDS_MSGBOX_YES
383 m_sButton1 = "Yes";
384 #else
385 m_i18l.LoadString(IDS_MSGBOX_YES);
386 m_sButton1 = m_i18l;
387 #endif
388 m_uButton1Ret = IDYES;
389 #ifndef IDS_MSGBOX_NO
390 m_sButton2 = "No";
391 #else
392 m_i18l.LoadString(IDS_MSGBOX_NO);
393 m_sButton2 = m_i18l;
394 #endif
395 m_uButton2Ret = IDNO;
396 break;
397 case MB_YESNOCANCEL:
398 #ifndef IDS_MSGBOX_YES
399 m_sButton1 = "Yes";
400 #else
401 m_i18l.LoadString(IDS_MSGBOX_YES);
402 m_sButton1 = m_i18l;
403 #endif
404 m_uButton1Ret = IDYES;
405 #ifndef IDS_MSGBOX_NO
406 m_sButton2 = "No";
407 #else
408 m_i18l.LoadString(IDS_MSGBOX_NO);
409 m_sButton2 = m_i18l;
410 #endif
411 m_uButton2Ret = IDNO;
412 #ifndef IDS_MSGBOX_CANCEL
413 m_sButton3 = "Cancel";
414 #else
415 m_i18l.LoadString(IDS_MSGBOX_CANCEL);
416 m_sButton3 = m_i18l;
417 #endif
418 m_uButton3Ret = IDCANCEL;
419 break;
420 case MB_OK:
421 default:
422 #ifndef IDS_MSGBOX_OK
423 m_sButton1 = "Ok";
424 #else
425 m_i18l.LoadString(IDS_MSGBOX_OK);
426 m_sButton1 = m_i18l;
427 #endif
429 //now set the default button
430 switch (uType & 0xf00)
432 case MB_DEFBUTTON2:
433 ret = 2;
434 break;
435 case MB_DEFBUTTON3:
436 ret = 3;
437 break;
439 // do we need to add a help button?
440 if (uType & MB_HELP)
442 CString sHelpText;
443 #ifndef IDS_MSGBOX_HELP
444 sHelpText = _T("Help");
445 #else
446 m_i18l.LoadString(IDS_MSGBOX_HELP);
447 sHelpText = m_i18l;
448 #endif
449 if (m_sButton2.IsEmpty())
451 m_sButton2 = sHelpText;
452 m_uButton2Ret = IDHELP;
454 else if (m_sButton3.IsEmpty())
456 m_sButton3 = sHelpText;
457 m_uButton3Ret = IDHELP;
460 return ret;
463 UINT CMessageBox::GoModal(CWnd * pWnd, const CString& title, const CString& msg, int nDefaultButton)
465 // pre Vista struct, needed for Windows XP
466 struct OLD_NONCLIENTMETRICS
468 UINT cbSize;
469 int iBorderWidth;
470 int iScrollWidth;
471 int iScrollHeight;
472 int iCaptionWidth;
473 int iCaptionHeight;
474 LOGFONT lfCaptionFont;
475 int iSmCaptionWidth;
476 int iSmCaptionHeight;
477 LOGFONT lfSmCaptionFont;
478 int iMenuWidth;
479 int iMenuHeight;
480 LOGFONT lfMenuFont;
481 LOGFONT lfStatusFont;
482 LOGFONT lfMessageFont;
484 const UINT cbProperSize = sizeof(OLD_NONCLIENTMETRICS);
486 NONCLIENTMETRICS ncm;
487 memset(&ncm,0,sizeof(NONCLIENTMETRICS));
488 ncm.cbSize = cbProperSize;
489 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
491 memcpy(&m_LogFont, &(ncm.lfMessageFont), sizeof(LOGFONT));
493 //the problem with the LOGFONT lfHeight is that it is not in pixels,
494 //but the dialog template needs the height in pixels.
495 //We need to convert those values first:
496 CDC * pDC;
497 if (pWnd)
498 pDC = pWnd->GetDC();
499 else
500 pDC = GetDesktopWindow()->GetDC();
501 HDC hdc;
502 if (pDC)
503 hdc = pDC->m_hDC;
504 else
505 hdc = ::GetDC(NULL);
506 if (!hdc)
508 HWND hw = pWnd ? pWnd->m_hWnd : nullptr;
509 int defButton = nDefaultButton == 1 ? MB_DEFBUTTON1 : nDefaultButton == 2 ? MB_DEFBUTTON2 : nDefaultButton == 3 ? MB_DEFBUTTON3 : 0;
510 return ::MessageBox(hw, msg, title, m_uType | defButton);
513 int pix = -MulDiv(m_LogFont.lfHeight, 72, GetDeviceCaps(hdc, LOGPIXELSY));
514 CDlgTemplate dialogTemplate = CDlgTemplate(title, WS_CAPTION | DS_CENTER,
515 0, 0, 0, 0, m_LogFont.lfFaceName, pix);
516 dialogTemplate.AddButton(_T("Button1"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | ((nDefaultButton == 1) ? BS_DEFPUSHBUTTON : 0), 0,
517 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON1);
518 dialogTemplate.AddButton(_T("Button2"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | ((nDefaultButton == 2) ? BS_DEFPUSHBUTTON : 0), 0,
519 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON2);
520 dialogTemplate.AddButton(_T("Button3"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | ((nDefaultButton == 3) ? BS_DEFPUSHBUTTON : 0), 0,
521 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON3);
522 dialogTemplate.AddButton(_T("Checkbox"), WS_CHILD | WS_TABSTOP | BS_AUTOCHECKBOX, 0,
523 0, 0, 0, 0, IDC_MESSAGEBOX_CHECKBOX);
525 m_nDefButton = nDefaultButton;
526 m_sMessage = msg;
527 InitModalIndirect(dialogTemplate, pWnd);
529 return (UINT)DoModal();
532 void CMessageBox::SetRegistryValue(const CString& sValue, DWORD value)
534 if (sValue.IsEmpty())
535 return;
537 CString path;
538 #ifdef XMESSAGEBOX_APPREGPATH
539 path = XMESSAGEBOX_APPREGPATH;
540 #else
541 path = "Software\\TortoiseGit\\";
542 path += AfxGetApp()->m_pszProfileName;
543 #endif
544 DWORD disp;
545 HKEY hKey;
546 if (RegCreateKeyEx(HKEY_CURRENT_USER, path, 0, _T(""), REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &disp)!=ERROR_SUCCESS)
548 return;
550 RegSetValueEx(hKey, sValue, 0, REG_DWORD,(const BYTE*) &value, sizeof(value));
551 RegCloseKey(hKey);
554 CSize CMessageBox::GetTextSize(const CString& str)
556 CRect rect;
557 GetWindowRect(&rect);
559 CDC * pDC = GetDC();
561 CDC memDC;
562 CBitmap bitmap;
563 memDC.CreateCompatibleDC(pDC);
564 bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
565 CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
567 //get the minimum size of the rectangle of the tooltip
568 CSize sz = DrawHTML(&memDC, rect, str, m_LogFont, TRUE);
570 memDC.SelectObject(pOldBitmap);
571 memDC.DeleteDC();
572 bitmap.DeleteObject();
574 ReleaseDC(pDC);
576 return sz;
579 CSize CMessageBox::GetIconSize(HICON hIcon)
581 ICONINFO ii;
582 CSize sz (0, 0);
584 if (hIcon != NULL)
586 //get icon dimensions
587 ::SecureZeroMemory(&ii, sizeof(ICONINFO));
588 if (::GetIconInfo(hIcon, &ii))
590 sz.cx = (DWORD)(ii.xHotspot * 2);
591 sz.cy = (DWORD)(ii.yHotspot * 2);
592 //release icon mask bitmaps
593 if(ii.hbmMask)
594 ::DeleteObject(ii.hbmMask);
595 if(ii.hbmColor)
596 ::DeleteObject(ii.hbmColor);
599 m_szIcon = sz;
600 return sz;
603 CSize CMessageBox::GetButtonSize()
605 CSize sz;
606 int nButtons = 0; //number of buttons - 1
608 SetDlgItemText(IDC_MESSAGEBOX_BUTTON1, m_sButton1);
609 SetDlgItemText(IDC_MESSAGEBOX_BUTTON2, m_sButton2);
610 //GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->SendMessage(BM_SETSTYLE, BS_DEFPUSHBUTTON, 1);
611 SetDlgItemText(IDC_MESSAGEBOX_BUTTON3, m_sButton3);
612 SetDlgItemText(IDC_MESSAGEBOX_CHECKBOX, m_sCheckbox);
614 CSize sz1 = GetTextSize(m_sButton1);
615 CSize sz2 = GetTextSize(m_sButton2);
616 CSize sz3 = GetTextSize(m_sButton3);
618 sz1.cx += 2*MESSAGEBOX_BUTTONX;
619 sz1.cy += 2*MESSAGEBOX_BUTTONY;
621 if (sz2.cx)
623 sz2.cx += 2*MESSAGEBOX_BUTTONX;
624 sz2.cy += 2*MESSAGEBOX_BUTTONY;
625 nButtons++;
627 if (sz3.cx)
629 sz3.cx += 2*MESSAGEBOX_BUTTONX;
630 sz3.cy += 2*MESSAGEBOX_BUTTONY;
631 nButtons++;
634 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->MoveWindow(0, 0, sz1.cx, sz1.cy);
635 GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->MoveWindow(0, 0, sz2.cx, sz2.cy);
636 GetDlgItem(IDC_MESSAGEBOX_BUTTON3)->MoveWindow(0, 0, sz3.cx, sz3.cy);
639 sz.cx = sz1.cx + sz2.cx + sz3.cx + (nButtons * MESSAGEBOX_BUTTONMARGIN);
640 sz.cy = max(sz1.cy, sz2.cy);
641 sz.cy = max(sz.cy, sz3.cy);
642 m_szButtons = sz;
643 if (m_bShowCheck)
645 CSize szCheck = GetTextSize(m_sCheckbox);
646 szCheck.cx += 2*GetSystemMetrics(SM_CXMENUCHECK);
647 szCheck.cy += 2*MESSAGEBOX_BUTTONY;
648 sz.cx = max(sz.cx, szCheck.cx);
649 sz.cy += szCheck.cy + MESSAGEBOX_BUTTONCHECKMARGIN;
650 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX)->MoveWindow(0, 0, szCheck.cx, szCheck.cy);
652 m_szAllButtons = sz;
653 return sz;
656 BEGIN_MESSAGE_MAP(CMessageBox, CDialog)
657 ON_WM_PAINT()
658 ON_WM_MOUSEMOVE()
659 ON_WM_LBUTTONUP()
660 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON1, OnButton1)
661 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON2, OnButton2)
662 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON3, OnButton3)
663 END_MESSAGE_MAP()
665 void CMessageBox::OnPaint()
667 CPaintDC dc(this); // device context for painting
670 CRect rect;
671 CRect drawrect;
672 GetClientRect(&rect);
673 GetClientRect(&drawrect);
675 //create a memory device-context. This is done to help reduce
676 //screen flicker, since we will paint the entire control to the
677 //off screen device context first.
678 CDC memDC;
679 CBitmap bitmap;
680 memDC.CreateCompatibleDC(&dc);
681 bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
682 CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
684 memDC.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dc, 0,0, SRCCOPY);
686 memDC.SetBkMode(TRANSPARENT);
687 memDC.SetBkColor(GetSysColor(COLOR_WINDOW));
688 memDC.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
690 //OnDrawBackground();
691 drawrect.DeflateRect(MESSAGEBOX_BORDERMARGINX, MESSAGEBOX_BORDERMARGINY);
692 if (m_hIcon != NULL)
694 DrawIconEx(memDC.m_hDC, drawrect.left, drawrect.top +
695 ((drawrect.Height() - m_szAllButtons.cy - MESSAGEBOX_TEXTBUTTONMARGIN - m_szIcon.cy) / 2),
696 m_hIcon, m_szIcon.cx, m_szIcon.cy, 0, NULL, DI_NORMAL);
698 drawrect.left += m_szIcon.cx + MESSAGEBOX_ICONMARGIN;
702 DrawHTML(&memDC, drawrect, m_sMessage, m_LogFont);
705 //Copy the memory device context back into the original DC.
706 dc.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0,0, SRCCOPY);
708 //Cleanup resources.
709 memDC.SelectObject(pOldBitmap);
710 memDC.DeleteDC();
711 bitmap.DeleteObject();
716 void CMessageBox::OnMouseMove(UINT nFlags, CPoint point)
718 if (IsPointOverALink(point))
720 m_Cursor.SetCursor(IDC_HAND);
722 else
724 m_Cursor.Restore();
727 __super::OnMouseMove(nFlags, point);
730 void CMessageBox::OnLButtonUp(UINT nFlags, CPoint point)
732 if (IsPointOverALink(point))
734 CString url = GetLinkForPoint(point);
735 ShellExecute(NULL, _T("open"), url, NULL,NULL, 0);
738 __super::OnLButtonUp(nFlags, point);
741 void CMessageBox::OnButton1()
743 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX)->SendMessage(BM_GETCHECK, 0, 0)==BST_CHECKED)
745 m_bChecked = TRUE;
746 SetRegistryValue(m_sRegistryValue, m_uButton1Ret);
748 else
750 m_bChecked = FALSE;
752 EndDialog(m_uButton1Ret);
755 void CMessageBox::OnButton2()
757 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX)->SendMessage(BM_GETCHECK, 0, 0)==BST_CHECKED)
759 m_bChecked = TRUE;
760 SetRegistryValue(m_sRegistryValue, m_uButton2Ret);
762 else
764 m_bChecked = FALSE;
766 if ((m_uButton2Ret == IDHELP)&&(!m_sHelpPath.IsEmpty()))
768 typedef HWND (WINAPI* FPHH)(HWND, LPCWSTR, UINT, DWORD);
769 FPHH pHtmlHelp=NULL; // Function pointer
770 CAutoLibrary hInstHtmlHelp = AtlLoadSystemLibraryUsingFullPath(_T("HHCtrl.ocx"));
771 HWND hHelp = NULL;
772 if (hInstHtmlHelp != NULL)
774 (FARPROC&)pHtmlHelp = GetProcAddress(hInstHtmlHelp, "HtmlHelpW");
775 if (pHtmlHelp)
776 hHelp = pHtmlHelp(m_hWnd, (LPCTSTR)m_sHelpPath, HH_DISPLAY_TOPIC, NULL);
778 if (hHelp == NULL)
779 ::MessageBox(m_hWnd, _T("could not show help file"), _T("Help"), MB_ICONERROR);
781 else if (m_uButton2Ret == IDHELP)
783 OnHelp();
785 else
786 EndDialog(m_uButton2Ret);
789 void CMessageBox::OnButton3()
791 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX)->SendMessage(BM_GETCHECK, 0, 0)==BST_CHECKED)
793 m_bChecked = TRUE;
794 SetRegistryValue(m_sRegistryValue, m_uButton3Ret);
796 else
798 m_bChecked = FALSE;
800 if ((m_uButton3Ret == IDHELP)&&(!m_sHelpPath.IsEmpty()))
802 typedef HWND (WINAPI* FPHH)(HWND, LPCWSTR, UINT, DWORD);
803 FPHH pHtmlHelp=NULL; // Function pointer
804 CAutoLibrary hInstHtmlHelp = AtlLoadSystemLibraryUsingFullPath(_T("HHCtrl.ocx"));
805 HWND hHelp = NULL;
806 if (hInstHtmlHelp != NULL)
808 (FARPROC&)pHtmlHelp = GetProcAddress(hInstHtmlHelp, "HtmlHelpW");
809 if (pHtmlHelp)
810 hHelp = pHtmlHelp(m_hWnd, (LPCTSTR)m_sHelpPath, HH_DISPLAY_TOPIC, NULL);
812 if (hHelp == NULL)
813 ::MessageBox(m_hWnd, _T("could not show help file"), _T("Help"), MB_ICONERROR);
815 else if (m_uButton3Ret == IDHELP)
817 OnHelp();
819 else
820 EndDialog(m_uButton3Ret);
823 void CMessageBox::OnCancel()
825 if (m_uCancelRet == IDCANCEL)
826 EndDialog(m_uCancelRet);
827 //__super::OnCancel();
830 BOOL CMessageBox::OnInitDialog()
832 __super::OnInitDialog();
834 CRect rect(0, 0, 0, 0);
836 //determine the required size of the message box
837 CSize szText = GetTextSize(m_sMessage);
838 CSize szIcon = GetIconSize(m_hIcon);
839 CSize szButtons = GetButtonSize();
841 CSize szIconText;
842 szIconText.cx = szText.cx + szIcon.cx + ((szIcon.cx == 0) ? MESSAGEBOX_ICONMARGIN : (2*MESSAGEBOX_ICONMARGIN));
843 szIconText.cy = max(szIcon.cy, szText.cy);
845 rect.right = max(szButtons.cx, szIconText.cx);
846 rect.right += 2*GetSystemMetrics(SM_CXBORDER);
847 rect.right += 2*MESSAGEBOX_BORDERMARGINX;
848 rect.bottom = szIconText.cy;
849 rect.bottom += szButtons.cy;
850 rect.bottom += 2*MESSAGEBOX_BORDERMARGINY + MESSAGEBOX_TEXTBUTTONMARGIN;
851 rect.bottom += GetSystemMetrics(SM_CYCAPTION);
852 rect.bottom += 2*GetSystemMetrics(SM_CYBORDER);
854 MoveWindow(rect);
855 CenterWindow();
857 GetClientRect(rect);
859 //now size and position the buttons as we need them
860 ASSERT(!m_sButton1.IsEmpty()); //at least the first button must be there!
861 if (m_sButton2.IsEmpty())
863 //only one button
864 CRect rt;
865 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->GetWindowRect(rt);
866 ScreenToClient(rt);
867 rt.MoveToX(rect.left + ((rect.Width() - m_szButtons.cx)/2));
868 rt.MoveToY(rect.bottom - MESSAGEBOX_BORDERMARGINY - m_szButtons.cy);
869 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->MoveWindow(rt);
870 //hide the other two buttons
871 GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->ShowWindow(SW_HIDE);
872 GetDlgItem(IDC_MESSAGEBOX_BUTTON3)->ShowWindow(SW_HIDE);
874 else if (m_sButton3.IsEmpty())
876 //two buttons
877 CRect rt1;
878 CRect rt2;
879 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->GetWindowRect(rt1);
880 ScreenToClient(rt1);
881 GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->GetWindowRect(rt2);
882 ScreenToClient(rt2);
883 rt1.MoveToX(rect.left + ((rect.Width() - m_szButtons.cx)/2));
884 rt1.MoveToY(rect.bottom - MESSAGEBOX_BORDERMARGINY - m_szButtons.cy);
885 rt2.MoveToX(rt1.right + MESSAGEBOX_BUTTONMARGIN);
886 rt2.MoveToY(rect.bottom - MESSAGEBOX_BORDERMARGINY - m_szButtons.cy);
887 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->MoveWindow(rt1);
888 GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->MoveWindow(rt2);
889 //hide the third button
890 GetDlgItem(IDC_MESSAGEBOX_BUTTON3)->ShowWindow(SW_HIDE);
892 else
894 //three buttons
895 CRect buttonrect;
896 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->GetWindowRect(buttonrect);
897 CRect rt1;
898 CRect rt2;
899 CRect rt3;
900 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->GetWindowRect(rt1);
901 ScreenToClient(rt1);
902 GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->GetWindowRect(rt2);
903 ScreenToClient(rt2);
904 GetDlgItem(IDC_MESSAGEBOX_BUTTON3)->GetWindowRect(rt3);
905 ScreenToClient(rt3);
906 rt1.MoveToX(rect.left + ((rect.Width() - m_szButtons.cx)/2));
907 rt1.MoveToY(rect.bottom - MESSAGEBOX_BORDERMARGINY - m_szButtons.cy);
908 rt2.MoveToX(rt1.right + MESSAGEBOX_BUTTONMARGIN);
909 rt2.MoveToY(rect.bottom - MESSAGEBOX_BORDERMARGINY - m_szButtons.cy);
910 rt3.MoveToX(rt2.right + MESSAGEBOX_BUTTONMARGIN);
911 rt3.MoveToY(rect.bottom - MESSAGEBOX_BORDERMARGINY - m_szButtons.cy);
912 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->MoveWindow(rt1);
913 GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->MoveWindow(rt2);
914 GetDlgItem(IDC_MESSAGEBOX_BUTTON3)->MoveWindow(rt3);
916 if (m_bShowCheck)
918 CRect rt;
919 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX)->GetWindowRect(rt);
920 ScreenToClient(rt);
921 rt.MoveToX(rect.left + MESSAGEBOX_BORDERMARGINX/*+ ((rect.Width() - szButtons.cx)/2)*/);
922 rt.MoveToY(rect.bottom - MESSAGEBOX_BORDERMARGINY - szButtons.cy);
923 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX)->MoveWindow(rt);
924 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX)->ShowWindow(SW_SHOW);
926 else
927 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX)->ShowWindow(SW_HIDE);
929 SetWindowPos(&CWnd::wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
930 SetForegroundWindow();
931 SetFocus(); //Just playing safe
933 if (m_nDefButton == 1)
934 GetDlgItem(IDC_MESSAGEBOX_BUTTON1)->SetFocus();
935 if (m_nDefButton == 2)
936 GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->SetFocus();
937 if (m_nDefButton == 3)
938 GetDlgItem(IDC_MESSAGEBOX_BUTTON3)->SetFocus();
940 return FALSE; // return TRUE unless you set the focus to a control
941 // EXCEPTION: OCX Property Pages should return FALSE
944 BOOL CMessageBox::PreTranslateMessage(MSG* pMsg)
946 if (pMsg->message == WM_KEYDOWN)
948 switch (pMsg->wParam)
950 case 'C':
951 case VK_INSERT:
953 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
955 CClipboardHelper clipboardHelper;
956 if(clipboardHelper.Open(GetSafeHwnd()))
958 EmptyClipboard();
959 CStringA sClipboard = CStringA(m_sMessage);
960 HGLOBAL hClipboardData = CClipboardHelper::GlobalAlloc(sClipboard.GetLength()+1);
961 char * pchData = (char*)GlobalLock(hClipboardData);
962 if (pchData)
963 strcpy_s(pchData, sClipboard.GetLength()+1, (LPCSTR)sClipboard);
964 GlobalUnlock(hClipboardData);
965 SetClipboardData(CF_TEXT,hClipboardData);
967 return TRUE;
970 break;
971 case VK_ESCAPE:
973 switch (m_uType & 0xf)
975 case MB_ABORTRETRYIGNORE:
976 EndDialog(m_uButton1Ret);
977 break;
978 case MB_CANCELTRYCONTINUE:
979 EndDialog(m_uButton1Ret);
980 break;
981 case MB_OKCANCEL:
982 EndDialog(m_uButton2Ret);
983 break;
984 case MB_RETRYCANCEL:
985 EndDialog(m_uButton2Ret);
986 break;
987 case MB_YESNO:
988 EndDialog(m_uButton2Ret);
989 break;
990 case MB_YESNOCANCEL:
991 EndDialog(m_uButton3Ret);
992 break;
995 break;
999 return __super::PreTranslateMessage(pMsg);