1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2016 - 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.
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"
25 #include <afxtaskdialog.h>
27 #define BTN_OFFSET 100 // use an offset in order to not interfere with IDYES and so on...
29 CMessageBox::CMessageBox(void)
36 , m_bDestroyIcon(FALSE
)
41 SecureZeroMemory(&m_LogFont
, sizeof(LOGFONT
));
44 CMessageBox::~CMessageBox(void)
47 ::DestroyIcon(m_hIcon
);
50 UINT
CMessageBox::ShowCheck(HWND hWnd
, UINT nMessage
, UINT nCaption
, int nDef
, LPCTSTR icon
, UINT nButton1
, UINT nButton2
, UINT nButton3
, LPCTSTR lpRegistry
, UINT nCheckMessage
/* = nullptr*/, BOOL
* bChecked
)
58 sButton1
.LoadString(nButton1
);
59 sButton2
.LoadString(nButton2
);
60 sButton3
.LoadString(nButton3
);
61 sMessage
.LoadString(nMessage
);
62 sCaption
.LoadString(nCaption
);
63 nCheckMsg
.LoadString(nCheckMessage
);
64 return CMessageBox::ShowCheck(hWnd
, sMessage
, sCaption
, nDef
, icon
, sButton1
, sButton2
, sButton3
, lpRegistry
, nCheckMsg
, bChecked
);
67 UINT
CMessageBox::ShowCheck(HWND hWnd
, LPCTSTR lpMessage
, LPCTSTR lpCaption
, int nDef
, LPCTSTR icon
, LPCTSTR lpButton1
, LPCTSTR lpButton2
, LPCTSTR lpButton3
, LPCTSTR lpRegistry
, LPCTSTR lpCheckMessage
/* = nullptr*/, BOOL
* bChecked
)
69 //check the registry if we have to show the box or just return with the last used return value
70 //this would be the case if the user pressed "do not show again".
74 #ifdef XMESSAGEBOX_APPREGPATH
75 path
= XMESSAGEBOX_APPREGPATH
;
77 path
= "Software\\TortoiseGit\\";
78 path
+= AfxGetApp()->m_pszProfileName
;
80 if (lpRegistry
&& *lpRegistry
&& RegOpenKeyEx(HKEY_CURRENT_USER
, path
, 0, KEY_EXECUTE
, &hKey
)==ERROR_SUCCESS
)
82 int size
= sizeof(dwRetVal
);
84 if (RegQueryValueEx(hKey
, lpRegistry
, nullptr, &type
, (BYTE
*)&dwRetVal
,(LPDWORD
)&size
) == ERROR_SUCCESS
)
86 ASSERT(type
==REG_DWORD
);
88 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) _T(": Using stored value %ld for \"%s\"\n"), dwRetVal
, lpMessage
);
89 return (UINT
)dwRetVal
; //return with the last saved value
97 if (CTaskDialog::IsSupported())
99 CTaskDialog
taskdlg(lpMessage
, L
"", lpCaption
, 0, TDF_USE_COMMAND_LINKS
| TDF_POSITION_RELATIVE_TO_WINDOW
);
100 taskdlg
.AddCommandControl(BTN_OFFSET
+ 1, lpButton1
);
101 if (lpButton2
&& *lpButton2
)
102 taskdlg
.AddCommandControl(BTN_OFFSET
+ 2, lpButton2
);
103 if (lpButton3
&& *lpButton3
)
104 taskdlg
.AddCommandControl(BTN_OFFSET
+ 3, lpButton3
);
105 taskdlg
.SetDefaultCommandControl(BTN_OFFSET
+ nDef
);
106 taskdlg
.SetMainIcon(icon
);
109 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
110 taskdlg
.SetVerificationCheckboxText(L
"do not show again");
113 m_i18l
.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN
);
114 taskdlg
.SetVerificationCheckboxText(m_i18l
);
118 taskdlg
.SetVerificationCheckboxText(lpCheckMessage
);
119 int result
= (int)taskdlg
.DoModal(hWnd
) - BTN_OFFSET
;
121 *bChecked
= taskdlg
.GetVerificationCheckboxState();
122 if (lpRegistry
&& *lpRegistry
&& taskdlg
.GetVerificationCheckboxState())
123 SetRegistryValue(lpRegistry
, result
);
129 box
.m_bShowCheck
= TRUE
;
130 box
.m_sRegistryValue
= lpRegistry
;
133 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
134 box
.m_sCheckbox
= _T("do not show again");
137 m_i18l
.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN
);
138 box
.m_sCheckbox
= m_i18l
;
142 box
.m_sCheckbox
= lpCheckMessage
;
143 box
.m_bChecked
= bChecked
? *bChecked
: FALSE
;
144 box
.m_sButton1
= lpButton1
;
145 box
.m_sButton2
= lpButton2
;
146 box
.m_sButton3
= lpButton3
;
147 box
.m_hIcon
= (HICON
)::LoadImage(AfxGetResourceHandle(), icon
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
149 box
.m_hIcon
= (HICON
)::LoadImage(nullptr, icon
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
151 box
.m_bDestroyIcon
= TRUE
;
154 int result
= box
.GoModal(CWnd::FromHandle(hWnd
), lpCaption
, lpMessage
, nDef
);
156 *bChecked
= box
.m_bChecked
;
160 UINT
CMessageBox::Show(HWND hWnd
, LPCTSTR lpMessage
, LPCTSTR lpCaption
, int nDef
, LPCTSTR icon
, LPCTSTR lpButton1
, LPCTSTR lpButton2
/* = nullptr*/, LPCTSTR lpButton3
/* = nullptr*/)
162 if (CTaskDialog::IsSupported())
164 CTaskDialog
taskdlg(lpMessage
, L
"", lpCaption
, 0, TDF_USE_COMMAND_LINKS
| TDF_POSITION_RELATIVE_TO_WINDOW
);
165 taskdlg
.AddCommandControl(BTN_OFFSET
+ 1, lpButton1
);
166 if (lpButton2
&& *lpButton2
)
167 taskdlg
.AddCommandControl(BTN_OFFSET
+ 2, lpButton2
);
168 if (lpButton3
&& *lpButton3
)
169 taskdlg
.AddCommandControl(BTN_OFFSET
+ 3, lpButton3
);
170 taskdlg
.SetDefaultCommandControl(BTN_OFFSET
+ nDef
);
171 taskdlg
.SetMainIcon(icon
);
172 return (UINT
)taskdlg
.DoModal(hWnd
) - BTN_OFFSET
;
175 box
.m_sButton1
= lpButton1
;
176 box
.m_sButton2
= lpButton2
;
177 box
.m_sButton3
= lpButton3
;
178 box
.m_hIcon
= (HICON
)::LoadImage(AfxGetResourceHandle(), icon
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
180 box
.m_hIcon
= (HICON
)::LoadImage(nullptr, icon
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
182 box
.m_bDestroyIcon
= TRUE
;
185 return box
.GoModal(CWnd::FromHandle(hWnd
), lpCaption
, lpMessage
, nDef
);
188 UINT
CMessageBox::Show(HWND hWnd
, UINT nMessage
, UINT nCaption
, int nDef
, LPCTSTR icon
, UINT nButton1
, UINT nButton2
, UINT nButton3
)
195 sButton1
.LoadString(nButton1
);
196 sButton2
.LoadString(nButton2
);
197 sButton3
.LoadString(nButton3
);
198 sMessage
.LoadString(nMessage
);
199 sCaption
.LoadString(nCaption
);
200 return CMessageBox::Show(hWnd
, sMessage
, sCaption
, nDef
, icon
, sButton1
, sButton2
, sButton3
);
203 UINT
CMessageBox::ShowCheck(HWND hWnd
, UINT nMessage
, UINT nCaption
, UINT uType
, LPCTSTR lpRegistry
, UINT nCheckMessage
, BOOL
*bChecked
)
208 sMessage
.LoadString(nMessage
);
209 sCaption
.LoadString(nCaption
);
210 sCheckMsg
.LoadString(nCheckMessage
);
211 return CMessageBox::ShowCheck(hWnd
, sMessage
, sCaption
, uType
, lpRegistry
, sCheckMsg
, bChecked
);
214 UINT
CMessageBox::ShowCheck(HWND hWnd
, LPCTSTR lpMessage
, LPCTSTR lpCaption
, UINT uType
, LPCTSTR lpRegistry
, LPCTSTR lpCheckMessage
, BOOL
*bChecked
)
216 //check the registry if we have to show the box or just return with the last used return value
217 //this would be the case if the user pressed "do not show again".
221 #ifdef XMESSAGEBOX_APPREGPATH
222 path
= XMESSAGEBOX_APPREGPATH
;
224 path
= "Software\\TortoiseGit\\";
225 path
+= AfxGetApp()->m_pszProfileName
;
227 if (lpRegistry
&& *lpRegistry
&& RegOpenKeyEx(HKEY_CURRENT_USER
, path
, 0, KEY_EXECUTE
, &hKey
)==ERROR_SUCCESS
)
229 int size
= sizeof(dwRetVal
);
231 if (RegQueryValueEx(hKey
, lpRegistry
, nullptr, &type
, (BYTE
*)&dwRetVal
,(LPDWORD
)&size
) == ERROR_SUCCESS
)
233 ASSERT(type
==REG_DWORD
);
235 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) _T(": Using stored value %ld for \"%s\"\n"), dwRetVal
, lpMessage
);
236 return (UINT
)dwRetVal
; //return with the last saved value
243 if (CTaskDialog::IsSupported() && !(uType
& MB_HELP
) && !((uType
& 0xf) == MB_ABORTRETRYIGNORE
) && !((uType
& 0xf) == MB_CANCELTRYCONTINUE
))
245 CTaskDialog
taskdlg(lpMessage
, L
"", lpCaption
, 0, TDF_POSITION_RELATIVE_TO_WINDOW
);
247 switch (uType
& 0xf0)
249 case MB_ICONEXCLAMATION
:
250 taskdlg
.SetMainIcon(IDI_EXCLAMATION
);
252 case MB_ICONASTERISK
:
253 taskdlg
.SetMainIcon(IDI_ASTERISK
);
255 case MB_ICONQUESTION
:
256 taskdlg
.SetMainIcon(IDI_QUESTION
);
259 taskdlg
.SetMainIcon(IDI_HAND
);
262 // set up the buttons
265 case MB_ABORTRETRYIGNORE
:
268 case MB_CANCELTRYCONTINUE
:
272 taskdlg
.SetCommonButtons(TDCBF_OK_BUTTON
| TDCBF_CANCEL_BUTTON
);
273 switch (uType
& 0xf00)
276 taskdlg
.SetDefaultCommandControl(IDCANCEL
);
281 taskdlg
.SetCommonButtons(TDCBF_RETRY_BUTTON
| TDCBF_CANCEL_BUTTON
);
282 switch (uType
& 0xf00)
285 taskdlg
.SetDefaultCommandControl(IDCANCEL
);
290 taskdlg
.SetCommonButtons(TDCBF_YES_BUTTON
| TDCBF_NO_BUTTON
);
291 switch (uType
& 0xf00)
294 taskdlg
.SetDefaultCommandControl(IDNO
);
299 taskdlg
.SetCommonButtons(TDCBF_YES_BUTTON
| TDCBF_NO_BUTTON
| TDCBF_CANCEL_BUTTON
);
300 switch (uType
& 0xf00)
303 taskdlg
.SetDefaultCommandControl(IDNO
);
306 taskdlg
.SetDefaultCommandControl(IDCANCEL
);
312 taskdlg
.SetCommonButtons(TDCBF_OK_BUTTON
);
317 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
318 taskdlg
.SetVerificationCheckboxText(L
"do not show again");
321 m_i18l
.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN
);
322 taskdlg
.SetVerificationCheckboxText(m_i18l
);
326 taskdlg
.SetVerificationCheckboxText(lpCheckMessage
);
327 int result
= (int)taskdlg
.DoModal(hWnd
) - BTN_OFFSET
;
329 *bChecked
= taskdlg
.GetVerificationCheckboxState();
330 if (lpRegistry
&& *lpRegistry
&& taskdlg
.GetVerificationCheckboxState())
331 SetRegistryValue(lpRegistry
, result
);
337 box
.m_bShowCheck
= TRUE
;
338 box
.m_sRegistryValue
= lpRegistry
;
341 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
342 box
.m_sCheckbox
= _T("do not show again");
345 m_i18l
.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN
);
346 box
.m_sCheckbox
= m_i18l
;
350 box
.m_sCheckbox
= lpCheckMessage
;
351 box
.m_bChecked
= bChecked
? *bChecked
: FALSE
;
354 int result
= box
.GoModal(CWnd::FromHandle(hWnd
), lpCaption
, lpMessage
, box
.FillBoxStandard(uType
));
356 *bChecked
= box
.m_bChecked
;
360 UINT
CMessageBox::Show(HWND hWnd
, UINT nMessage
, UINT nCaption
, UINT uType
, LPCTSTR sHelpPath
)
364 sMessage
.LoadString(nMessage
);
365 sCaption
.LoadString(nCaption
);
366 return CMessageBox::Show(hWnd
, sMessage
, sCaption
, uType
, sHelpPath
);
369 UINT
CMessageBox::Show(HWND hWnd
, LPCTSTR lpMessage
, LPCTSTR lpCaption
, UINT uType
, LPCTSTR sHelpPath
)
376 box
.SetHelpPath(sHelpPath
);
377 return box
.GoModal(CWnd::FromHandle(hWnd
), lpCaption
, lpMessage
, box
.FillBoxStandard(uType
));
379 return ::MessageBox(hWnd
, lpMessage
, lpCaption
, uType
);
382 UINT
CMessageBox::Show(HWND hWnd
, UINT nMessage
, UINT nCaption
, UINT uType
, UINT nHelpID
)
386 sMessage
.LoadString(nMessage
);
387 sCaption
.LoadString(nCaption
);
394 box
.SetHelpID(nHelpID
);
395 return box
.GoModal(CWnd::FromHandle(hWnd
), sCaption
, sMessage
, box
.FillBoxStandard(uType
));
398 return ::MessageBox(hWnd
, sMessage
, sCaption
, uType
);
401 bool CMessageBox::RemoveRegistryKey(LPCTSTR lpRegistry
)
405 #ifdef XMESSAGEBOX_APPREGPATH
406 path
= XMESSAGEBOX_APPREGPATH
;
408 path
= "Software\\TortoiseGit\\";
409 path
+= AfxGetApp()->m_pszProfileName
;
411 if (RegOpenKeyEx(HKEY_CURRENT_USER
, path
, 0, KEY_WRITE
, &hKey
) == ERROR_SUCCESS
)
413 bool ret
= !!RegDeleteValue(hKey
, lpRegistry
);
420 int CMessageBox::FillBoxStandard(UINT uType
)
424 m_uCancelRet
= IDCANCEL
;
425 //load the icons according to uType
426 switch (uType
& 0xf0)
428 case MB_ICONEXCLAMATION
:
429 m_hIcon
= (HICON
)::LoadImage(nullptr, IDI_EXCLAMATION
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
430 ::MessageBeep(MB_ICONEXCLAMATION
);
432 case MB_ICONASTERISK
:
433 m_hIcon
= (HICON
)::LoadImage(nullptr, IDI_ASTERISK
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
434 ::MessageBeep(MB_ICONASTERISK
);
436 case MB_ICONQUESTION
:
437 m_hIcon
= (HICON
)::LoadImage(nullptr, IDI_QUESTION
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
438 ::MessageBeep(MB_ICONQUESTION
);
441 m_hIcon
= (HICON
)::LoadImage(nullptr, IDI_HAND
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
442 ::MessageBeep(MB_ICONHAND
);
445 //set up the button texts
448 case MB_ABORTRETRYIGNORE
:
449 #ifndef IDS_MSGBOX_ABORT
450 m_sButton1
= "&Abort";
452 m_i18l
.LoadString(IDS_MSGBOX_ABORT
);
455 m_uButton1Ret
= IDABORT
;
456 #ifndef IDS_MSGBOX_RETRY
457 m_sButton2
= "&Retry";
459 m_i18l
.LoadString(IDS_MSGBOX_RETRY
);
462 m_uButton2Ret
= IDRETRY
;
463 #ifndef IDS_MSGBOX_IGNORE
464 m_sButton3
= "&Ignore";
466 m_i18l
.LoadString(IDS_MSGBOX_IGNORE
);
469 m_uButton3Ret
= IDIGNORE
;
471 case MB_CANCELTRYCONTINUE
:
472 #ifndef IDS_MSGBOX_CANCEL
473 m_sButton1
= "Cancel";
475 m_i18l
.LoadString(IDS_MSGBOX_CANCEL
);
478 m_uButton1Ret
= IDCANCEL
;
479 #ifndef IDS_MSGBOX_TRYAGAIN
480 m_sButton2
= "&Try Again";
482 m_i18l
.LoadString(IDS_MSGBOX_TRYAGAIN
);
485 m_uButton2Ret
= IDTRYAGAIN
;
486 #ifndef IDS_MSGBOX_CONTINUE
487 m_sButton3
= "&Continue";
489 m_i18l
.LoadString(IDS_MSGBOX_CONTINUE
);
492 m_uButton3Ret
= IDCONTINUE
;
495 #ifndef IDS_MSGBOX_OK
498 m_i18l
.LoadString(IDS_MSGBOX_OK
);
501 m_uButton1Ret
= IDOK
;
502 #ifndef IDS_MSGBOX_CANCEL
503 m_sButton2
= "Cancel";
505 m_i18l
.LoadString(IDS_MSGBOX_CANCEL
);
508 m_uButton2Ret
= IDCANCEL
;
511 #ifndef IDS_MSGBOX_RETRY
512 m_sButton1
= "&Retry";
514 m_i18l
.LoadString(IDS_MSGBOX_RETRY
);
517 m_uButton1Ret
= IDRETRY
;
518 #ifndef IDS_MSGBOX_CANCEL
519 m_sButton2
= "Cancel";
521 m_i18l
.LoadString(IDS_MSGBOX_CANCEL
);
524 m_uButton2Ret
= IDCANCEL
;
527 #ifndef IDS_MSGBOX_YES
530 m_i18l
.LoadString(IDS_MSGBOX_YES
);
533 m_uButton1Ret
= IDYES
;
534 #ifndef IDS_MSGBOX_NO
537 m_i18l
.LoadString(IDS_MSGBOX_NO
);
540 m_uButton2Ret
= IDNO
;
543 #ifndef IDS_MSGBOX_YES
546 m_i18l
.LoadString(IDS_MSGBOX_YES
);
549 m_uButton1Ret
= IDYES
;
550 #ifndef IDS_MSGBOX_NO
553 m_i18l
.LoadString(IDS_MSGBOX_NO
);
556 m_uButton2Ret
= IDNO
;
557 #ifndef IDS_MSGBOX_CANCEL
558 m_sButton3
= "Cancel";
560 m_i18l
.LoadString(IDS_MSGBOX_CANCEL
);
563 m_uButton3Ret
= IDCANCEL
;
567 #ifndef IDS_MSGBOX_OK
570 m_i18l
.LoadString(IDS_MSGBOX_OK
);
574 //now set the default button
575 switch (uType
& 0xf00)
584 // do we need to add a help button?
588 #ifndef IDS_MSGBOX_HELP
589 sHelpText
= _T("Help");
591 m_i18l
.LoadString(IDS_MSGBOX_HELP
);
594 if (m_sButton2
.IsEmpty())
596 m_sButton2
= sHelpText
;
597 m_uButton2Ret
= IDHELP
;
599 else if (m_sButton3
.IsEmpty())
601 m_sButton3
= sHelpText
;
602 m_uButton3Ret
= IDHELP
;
608 UINT
CMessageBox::GoModal(CWnd
* pWnd
, const CString
& title
, const CString
& msg
, int nDefaultButton
)
610 // pre Vista struct, needed for Windows XP
611 struct OLD_NONCLIENTMETRICS
619 LOGFONT lfCaptionFont
;
621 int iSmCaptionHeight
;
622 LOGFONT lfSmCaptionFont
;
626 LOGFONT lfStatusFont
;
627 LOGFONT lfMessageFont
;
629 const UINT cbProperSize
= sizeof(OLD_NONCLIENTMETRICS
);
631 NONCLIENTMETRICS ncm
= { 0 };
632 ncm
.cbSize
= cbProperSize
;
633 SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICS
), &ncm
, 0);
635 memcpy(&m_LogFont
, &(ncm
.lfMessageFont
), sizeof(LOGFONT
));
637 //the problem with the LOGFONT lfHeight is that it is not in pixels,
638 //but the dialog template needs the height in pixels.
639 //We need to convert those values first:
644 pDC
= GetDesktopWindow()->GetDC();
649 hdc
= ::GetDC(nullptr);
652 HWND hw
= pWnd
? pWnd
->m_hWnd
: nullptr;
653 int defButton
= nDefaultButton
== 1 ? MB_DEFBUTTON1
: nDefaultButton
== 2 ? MB_DEFBUTTON2
: nDefaultButton
== 3 ? MB_DEFBUTTON3
: 0;
654 return ::MessageBox(hw
, msg
, title
, m_uType
| defButton
);
657 int pix
= -MulDiv(m_LogFont
.lfHeight
, 72, GetDeviceCaps(hdc
, LOGPIXELSY
));
658 CDlgTemplate dialogTemplate
= CDlgTemplate(title
, WS_CAPTION
| DS_CENTER
,
659 0, 0, 0, 0, m_LogFont
.lfFaceName
, pix
);
660 dialogTemplate
.AddButton(_T("Button1"), WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
| BS_PUSHBUTTON
| ((nDefaultButton
== 1) ? BS_DEFPUSHBUTTON
: 0), 0,
661 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON1
);
662 dialogTemplate
.AddButton(_T("Button2"), WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
| BS_PUSHBUTTON
| ((nDefaultButton
== 2) ? BS_DEFPUSHBUTTON
: 0), 0,
663 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON2
);
664 dialogTemplate
.AddButton(_T("Button3"), WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
| BS_PUSHBUTTON
| ((nDefaultButton
== 3) ? BS_DEFPUSHBUTTON
: 0), 0,
665 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON3
);
666 dialogTemplate
.AddButton(_T("Checkbox"), WS_CHILD
| WS_TABSTOP
| BS_AUTOCHECKBOX
, 0,
667 0, 0, 0, 0, IDC_MESSAGEBOX_CHECKBOX
);
669 m_nDefButton
= nDefaultButton
;
671 InitModalIndirect(dialogTemplate
, pWnd
);
673 return (UINT
)DoModal();
676 void CMessageBox::SetRegistryValue(const CString
& sValue
, DWORD value
)
678 if (sValue
.IsEmpty())
682 #ifdef XMESSAGEBOX_APPREGPATH
683 path
= XMESSAGEBOX_APPREGPATH
;
685 path
= "Software\\TortoiseGit\\";
686 path
+= AfxGetApp()->m_pszProfileName
;
690 if (RegCreateKeyEx(HKEY_CURRENT_USER
, path
, 0, _T(""), REG_OPTION_NON_VOLATILE
, KEY_WRITE
, nullptr, &hKey
, &disp
) != ERROR_SUCCESS
)
694 RegSetValueEx(hKey
, sValue
, 0, REG_DWORD
,(const BYTE
*) &value
, sizeof(value
));
698 CSize
CMessageBox::GetTextSize(const CString
& str
)
701 GetWindowRect(&rect
);
707 memDC
.CreateCompatibleDC(pDC
);
708 bitmap
.CreateCompatibleBitmap(pDC
, rect
.Width(), rect
.Height());
709 CBitmap
* pOldBitmap
= memDC
.SelectObject(&bitmap
);
711 //get the minimum size of the rectangle of the tooltip
712 CSize sz
= DrawHTML(&memDC
, rect
, str
, m_LogFont
, TRUE
);
714 memDC
.SelectObject(pOldBitmap
);
716 bitmap
.DeleteObject();
723 CSize
CMessageBox::GetIconSize(HICON hIcon
)
730 //get icon dimensions
731 if (::GetIconInfo(hIcon
, &ii
))
733 sz
.cx
= (DWORD
)(ii
.xHotspot
* 2);
734 sz
.cy
= (DWORD
)(ii
.yHotspot
* 2);
735 //release icon mask bitmaps
737 ::DeleteObject(ii
.hbmMask
);
739 ::DeleteObject(ii
.hbmColor
);
746 CSize
CMessageBox::GetButtonSize()
749 int nButtons
= 0; //number of buttons - 1
751 SetDlgItemText(IDC_MESSAGEBOX_BUTTON1
, m_sButton1
);
752 SetDlgItemText(IDC_MESSAGEBOX_BUTTON2
, m_sButton2
);
753 //GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->SendMessage(BM_SETSTYLE, BS_DEFPUSHBUTTON, 1);
754 SetDlgItemText(IDC_MESSAGEBOX_BUTTON3
, m_sButton3
);
755 SetDlgItemText(IDC_MESSAGEBOX_CHECKBOX
, m_sCheckbox
);
757 CSize sz1
= GetTextSize(m_sButton1
);
758 CSize sz2
= GetTextSize(m_sButton2
);
759 CSize sz3
= GetTextSize(m_sButton3
);
761 sz1
.cx
+= 2*MESSAGEBOX_BUTTONX
;
762 sz1
.cy
+= 2*MESSAGEBOX_BUTTONY
;
766 sz2
.cx
+= 2*MESSAGEBOX_BUTTONX
;
767 sz2
.cy
+= 2*MESSAGEBOX_BUTTONY
;
772 sz3
.cx
+= 2*MESSAGEBOX_BUTTONX
;
773 sz3
.cy
+= 2*MESSAGEBOX_BUTTONY
;
777 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->MoveWindow(0, 0, sz1
.cx
, sz1
.cy
);
778 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->MoveWindow(0, 0, sz2
.cx
, sz2
.cy
);
779 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->MoveWindow(0, 0, sz3
.cx
, sz3
.cy
);
781 sz
.cx
= sz1
.cx
+ sz2
.cx
+ sz3
.cx
+ (nButtons
* MESSAGEBOX_BUTTONMARGIN
);
782 sz
.cy
= max(sz1
.cy
, sz2
.cy
);
783 sz
.cy
= max(sz
.cy
, sz3
.cy
);
787 CSize szCheck
= GetTextSize(m_sCheckbox
);
788 szCheck
.cx
+= 2*GetSystemMetrics(SM_CXMENUCHECK
);
789 szCheck
.cy
+= 2*MESSAGEBOX_BUTTONY
;
790 sz
.cx
= max(sz
.cx
, szCheck
.cx
);
791 sz
.cy
+= szCheck
.cy
+ MESSAGEBOX_BUTTONCHECKMARGIN
;
792 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->MoveWindow(0, 0, szCheck
.cx
, szCheck
.cy
);
798 BEGIN_MESSAGE_MAP(CMessageBox
, CDialog
)
802 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON1
, OnButton1
)
803 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON2
, OnButton2
)
804 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON3
, OnButton3
)
807 void CMessageBox::OnPaint()
809 CPaintDC
dc(this); // device context for painting
813 GetClientRect(&rect
);
814 GetClientRect(&drawrect
);
816 //create a memory device-context. This is done to help reduce
817 //screen flicker, since we will paint the entire control to the
818 //off screen device context first.
821 memDC
.CreateCompatibleDC(&dc
);
822 bitmap
.CreateCompatibleBitmap(&dc
, rect
.Width(), rect
.Height());
823 CBitmap
* pOldBitmap
= memDC
.SelectObject(&bitmap
);
825 memDC
.BitBlt(rect
.left
, rect
.top
, rect
.Width(), rect
.Height(), &dc
, 0,0, SRCCOPY
);
827 memDC
.SetBkMode(TRANSPARENT
);
828 memDC
.SetBkColor(GetSysColor(COLOR_WINDOW
));
829 memDC
.SetTextColor(GetSysColor(COLOR_WINDOWTEXT
));
831 //OnDrawBackground();
832 drawrect
.DeflateRect(MESSAGEBOX_BORDERMARGINX
, MESSAGEBOX_BORDERMARGINY
);
835 DrawIconEx(memDC
.m_hDC
, drawrect
.left
, max(drawrect
.top
, drawrect
.top
+
836 ((drawrect
.Height() - m_szAllButtons
.cy
- MESSAGEBOX_TEXTBUTTONMARGIN
- m_szIcon
.cy
) / 2)),
837 m_hIcon
, m_szIcon
.cx
, m_szIcon
.cy
, 0, nullptr, DI_NORMAL
);
839 drawrect
.left
+= m_szIcon
.cx
+ MESSAGEBOX_ICONMARGIN
;
840 if (m_szIcon
.cy
> m_szText
.cy
)
841 drawrect
.top
+= (m_szIcon
.cy
- m_szText
.cy
) / 2;
844 DrawHTML(&memDC
, drawrect
, m_sMessage
, m_LogFont
);
846 //Copy the memory device context back into the original DC.
847 dc
.BitBlt(rect
.left
, rect
.top
, rect
.Width(), rect
.Height(), &memDC
, 0,0, SRCCOPY
);
850 memDC
.SelectObject(pOldBitmap
);
852 bitmap
.DeleteObject();
855 void CMessageBox::OnMouseMove(UINT nFlags
, CPoint point
)
857 if (IsPointOverALink(point
))
858 m_Cursor
.SetCursor(IDC_HAND
);
862 __super::OnMouseMove(nFlags
, point
);
865 void CMessageBox::OnLButtonUp(UINT nFlags
, CPoint point
)
867 if (IsPointOverALink(point
))
869 CString url
= GetLinkForPoint(point
);
870 ShellExecute(nullptr, _T("open"), url
, nullptr, nullptr, SW_HIDE
);
873 __super::OnLButtonUp(nFlags
, point
);
876 void CMessageBox::OnButton1()
878 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->SendMessage(BM_GETCHECK
, 0, 0)==BST_CHECKED
)
881 SetRegistryValue(m_sRegistryValue
, m_uButton1Ret
);
885 EndDialog(m_uButton1Ret
);
888 void CMessageBox::OnButton2()
890 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->SendMessage(BM_GETCHECK
, 0, 0)==BST_CHECKED
)
893 SetRegistryValue(m_sRegistryValue
, m_uButton2Ret
);
897 if ((m_uButton2Ret
== IDHELP
)&&(!m_sHelpPath
.IsEmpty()))
899 typedef HWND (WINAPI
* FPHH
)(HWND
, LPCWSTR
, UINT
, DWORD
);
900 FPHH pHtmlHelp
= nullptr; // Function pointer
901 CAutoLibrary hInstHtmlHelp
= AtlLoadSystemLibraryUsingFullPath(_T("HHCtrl.ocx"));
902 HWND hHelp
= nullptr;
905 (FARPROC
&)pHtmlHelp
= GetProcAddress(hInstHtmlHelp
, "HtmlHelpW");
907 hHelp
= pHtmlHelp(m_hWnd
, (LPCTSTR
)m_sHelpPath
, HH_DISPLAY_TOPIC
, NULL
);
910 ::MessageBox(m_hWnd
, _T("could not show help file"), _T("Help"), MB_ICONERROR
);
912 else if (m_uButton2Ret
== IDHELP
)
915 EndDialog(m_uButton2Ret
);
918 void CMessageBox::OnButton3()
920 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->SendMessage(BM_GETCHECK
, 0, 0)==BST_CHECKED
)
923 SetRegistryValue(m_sRegistryValue
, m_uButton3Ret
);
927 if ((m_uButton3Ret
== IDHELP
)&&(!m_sHelpPath
.IsEmpty()))
929 typedef HWND (WINAPI
* FPHH
)(HWND
, LPCWSTR
, UINT
, DWORD
);
930 FPHH pHtmlHelp
= nullptr; // Function pointer
931 CAutoLibrary hInstHtmlHelp
= AtlLoadSystemLibraryUsingFullPath(_T("HHCtrl.ocx"));
932 HWND hHelp
= nullptr;
935 (FARPROC
&)pHtmlHelp
= GetProcAddress(hInstHtmlHelp
, "HtmlHelpW");
937 hHelp
= pHtmlHelp(m_hWnd
, (LPCTSTR
)m_sHelpPath
, HH_DISPLAY_TOPIC
, NULL
);
940 ::MessageBox(m_hWnd
, _T("could not show help file"), _T("Help"), MB_ICONERROR
);
942 else if (m_uButton3Ret
== IDHELP
)
945 EndDialog(m_uButton3Ret
);
948 void CMessageBox::OnCancel()
950 if (m_uCancelRet
== IDCANCEL
)
951 EndDialog(m_uCancelRet
);
952 //__super::OnCancel();
955 BOOL
CMessageBox::OnInitDialog()
957 __super::OnInitDialog();
959 CRect
rect(0, 0, 0, 0);
961 //determine the required size of the message box
962 m_szText
= GetTextSize(m_sMessage
);
963 CSize szIcon
= GetIconSize(m_hIcon
);
964 CSize szButtons
= GetButtonSize();
967 szIconText
.cx
= m_szText
.cx
+ szIcon
.cx
+ ((szIcon
.cx
== 0) ? MESSAGEBOX_ICONMARGIN
: (2 * MESSAGEBOX_ICONMARGIN
));
968 szIconText
.cy
= max(szIcon
.cy
, m_szText
.cy
);
970 rect
.right
= max(szButtons
.cx
, szIconText
.cx
);
971 rect
.right
+= 2*GetSystemMetrics(SM_CXBORDER
);
972 rect
.right
+= 2*MESSAGEBOX_BORDERMARGINX
;
973 rect
.bottom
= szIconText
.cy
;
974 rect
.bottom
+= szButtons
.cy
;
975 rect
.bottom
+= 2*MESSAGEBOX_BORDERMARGINY
+ MESSAGEBOX_TEXTBUTTONMARGIN
;
976 rect
.bottom
+= GetSystemMetrics(SM_CYCAPTION
);
977 rect
.bottom
+= 2 * GetSystemMetrics(SM_CYFIXEDFRAME
);
978 rect
.bottom
+= 2*GetSystemMetrics(SM_CYBORDER
);
985 //now size and position the buttons as we need them
986 ASSERT(!m_sButton1
.IsEmpty()); //at least the first button must be there!
987 if (m_sButton2
.IsEmpty())
991 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->GetWindowRect(rt
);
993 rt
.MoveToX(rect
.left
+ ((rect
.Width() - m_szButtons
.cx
)/2));
994 rt
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
995 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->MoveWindow(rt
);
996 //hide the other two buttons
997 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->ShowWindow(SW_HIDE
);
998 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->ShowWindow(SW_HIDE
);
1000 else if (m_sButton3
.IsEmpty())
1005 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->GetWindowRect(rt1
);
1006 ScreenToClient(rt1
);
1007 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->GetWindowRect(rt2
);
1008 ScreenToClient(rt2
);
1009 rt1
.MoveToX(rect
.left
+ ((rect
.Width() - m_szButtons
.cx
)/2));
1010 rt1
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1011 rt2
.MoveToX(rt1
.right
+ MESSAGEBOX_BUTTONMARGIN
);
1012 rt2
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1013 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->MoveWindow(rt1
);
1014 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->MoveWindow(rt2
);
1015 //hide the third button
1016 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->ShowWindow(SW_HIDE
);
1022 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->GetWindowRect(buttonrect
);
1026 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->GetWindowRect(rt1
);
1027 ScreenToClient(rt1
);
1028 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->GetWindowRect(rt2
);
1029 ScreenToClient(rt2
);
1030 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->GetWindowRect(rt3
);
1031 ScreenToClient(rt3
);
1032 rt1
.MoveToX(rect
.left
+ ((rect
.Width() - m_szButtons
.cx
)/2));
1033 rt1
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1034 rt2
.MoveToX(rt1
.right
+ MESSAGEBOX_BUTTONMARGIN
);
1035 rt2
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1036 rt3
.MoveToX(rt2
.right
+ MESSAGEBOX_BUTTONMARGIN
);
1037 rt3
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1038 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->MoveWindow(rt1
);
1039 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->MoveWindow(rt2
);
1040 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->MoveWindow(rt3
);
1045 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->GetWindowRect(rt
);
1047 rt
.MoveToX(rect
.left
+ MESSAGEBOX_BORDERMARGINX
/*+ ((rect.Width() - szButtons.cx)/2)*/);
1048 rt
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- szButtons
.cy
);
1049 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->MoveWindow(rt
);
1050 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->ShowWindow(SW_SHOW
);
1053 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->ShowWindow(SW_HIDE
);
1055 SetWindowPos(&CWnd::wndTopMost
,0,0,0,0,SWP_NOMOVE
|SWP_NOSIZE
);
1056 SetForegroundWindow();
1057 SetFocus(); //Just playing safe
1059 if (m_nDefButton
== 1)
1060 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->SetFocus();
1061 if (m_nDefButton
== 2)
1062 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->SetFocus();
1063 if (m_nDefButton
== 3)
1064 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->SetFocus();
1066 return FALSE
; // return TRUE unless you set the focus to a control
1067 // EXCEPTION: OCX Property Pages should return FALSE
1070 BOOL
CMessageBox::PreTranslateMessage(MSG
* pMsg
)
1072 if (pMsg
->message
== WM_KEYDOWN
)
1074 switch (pMsg
->wParam
)
1079 if (GetAsyncKeyState(VK_CONTROL
)&0x8000)
1081 CClipboardHelper clipboardHelper
;
1082 if(clipboardHelper
.Open(GetSafeHwnd()))
1085 CStringA sClipboard
= CStringA(m_sMessage
);
1086 HGLOBAL hClipboardData
= CClipboardHelper::GlobalAlloc(sClipboard
.GetLength()+1);
1087 char * pchData
= (char*)GlobalLock(hClipboardData
);
1089 strcpy_s(pchData
, sClipboard
.GetLength()+1, (LPCSTR
)sClipboard
);
1090 GlobalUnlock(hClipboardData
);
1091 SetClipboardData(CF_TEXT
,hClipboardData
);
1099 switch (m_uType
& 0xf)
1101 case MB_ABORTRETRYIGNORE
:
1102 EndDialog(m_uButton1Ret
);
1104 case MB_CANCELTRYCONTINUE
:
1105 EndDialog(m_uButton1Ret
);
1108 EndDialog(m_uButton2Ret
);
1110 case MB_RETRYCANCEL
:
1111 EndDialog(m_uButton2Ret
);
1114 EndDialog(m_uButton2Ret
);
1116 case MB_YESNOCANCEL
:
1117 EndDialog(m_uButton3Ret
);
1125 return __super::PreTranslateMessage(pMsg
);