1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2016, 2018 - 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>
28 #define BTN_OFFSET 100 // use an offset in order to not interfere with IDYES and so on...
30 CMessageBox::CMessageBox(void)
37 , m_bDestroyIcon(FALSE
)
42 SecureZeroMemory(&m_LogFont
, sizeof(LOGFONT
));
45 CMessageBox::~CMessageBox(void)
48 ::DestroyIcon(m_hIcon
);
51 static HWND
GetMainHWND(HWND hWnd
)
53 if (!hWnd
|| !IsWindow(hWnd
))
54 return CWnd::GetSafeOwner_(nullptr, nullptr);
58 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
)
66 sButton1
.LoadString(nButton1
);
67 sButton2
.LoadString(nButton2
);
68 sButton3
.LoadString(nButton3
);
69 sMessage
.LoadString(nMessage
);
70 sCaption
.LoadString(nCaption
);
71 nCheckMsg
.LoadString(nCheckMessage
);
72 return CMessageBox::ShowCheck(hWnd
, sMessage
, sCaption
, nDef
, icon
, sButton1
, sButton2
, sButton3
, lpRegistry
, nCheckMsg
, bChecked
);
75 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
)
77 //check the registry if we have to show the box or just return with the last used return value
78 //this would be the case if the user pressed "do not show again".
82 #ifdef XMESSAGEBOX_APPREGPATH
83 path
= XMESSAGEBOX_APPREGPATH
;
85 path
= "Software\\TortoiseGit\\";
86 path
+= AfxGetApp()->m_pszProfileName
;
88 if (lpRegistry
&& *lpRegistry
&& RegOpenKeyEx(HKEY_CURRENT_USER
, path
, 0, KEY_EXECUTE
, &hKey
)==ERROR_SUCCESS
)
90 int size
= sizeof(dwRetVal
);
92 if (RegQueryValueEx(hKey
, lpRegistry
, nullptr, &type
, (BYTE
*)&dwRetVal
,(LPDWORD
)&size
) == ERROR_SUCCESS
)
94 ASSERT(type
==REG_DWORD
);
96 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Using stored value %ld for \"%s\"\n", dwRetVal
, lpMessage
);
97 return (UINT
)dwRetVal
; //return with the last saved value
105 if (CTaskDialog::IsSupported())
107 CTaskDialog
taskdlg(lpMessage
, L
"", lpCaption
, 0, TDF_USE_COMMAND_LINKS
| TDF_POSITION_RELATIVE_TO_WINDOW
);
108 taskdlg
.AddCommandControl(BTN_OFFSET
+ 1, lpButton1
);
109 if (lpButton2
&& *lpButton2
)
110 taskdlg
.AddCommandControl(BTN_OFFSET
+ 2, lpButton2
);
111 if (lpButton3
&& *lpButton3
)
112 taskdlg
.AddCommandControl(BTN_OFFSET
+ 3, lpButton3
);
113 taskdlg
.SetDefaultCommandControl(BTN_OFFSET
+ nDef
);
114 taskdlg
.SetMainIcon(icon
);
117 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
118 taskdlg
.SetVerificationCheckboxText(L
"do not show again");
121 m_i18l
.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN
);
122 taskdlg
.SetVerificationCheckboxText(m_i18l
);
126 taskdlg
.SetVerificationCheckboxText(lpCheckMessage
);
127 int result
= (int)taskdlg
.DoModal(GetMainHWND(hWnd
)) - BTN_OFFSET
;
129 *bChecked
= taskdlg
.GetVerificationCheckboxState();
130 if (lpRegistry
&& *lpRegistry
&& taskdlg
.GetVerificationCheckboxState())
131 SetRegistryValue(lpRegistry
, result
);
137 box
.m_bShowCheck
= TRUE
;
138 box
.m_sRegistryValue
= lpRegistry
;
141 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
142 box
.m_sCheckbox
= L
"do not show again";
145 m_i18l
.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN
);
146 box
.m_sCheckbox
= m_i18l
;
150 box
.m_sCheckbox
= lpCheckMessage
;
151 box
.m_bChecked
= bChecked
? *bChecked
: FALSE
;
152 box
.m_sButton1
= lpButton1
;
153 box
.m_sButton2
= lpButton2
;
154 box
.m_sButton3
= lpButton3
;
155 box
.m_hIcon
= (HICON
)::LoadImage(AfxGetResourceHandle(), icon
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
157 box
.m_hIcon
= (HICON
)::LoadImage(nullptr, icon
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
159 box
.m_bDestroyIcon
= TRUE
;
162 int result
= box
.GoModal(CWnd::FromHandle(hWnd
), lpCaption
, lpMessage
, nDef
);
164 *bChecked
= box
.m_bChecked
;
168 UINT
CMessageBox::Show(HWND hWnd
, LPCTSTR lpMessage
, LPCTSTR lpCaption
, int nDef
, LPCTSTR icon
, LPCTSTR lpButton1
, LPCTSTR lpButton2
/* = nullptr*/, LPCTSTR lpButton3
/* = nullptr*/)
170 if (CTaskDialog::IsSupported())
172 CTaskDialog
taskdlg(lpMessage
, L
"", lpCaption
, 0, TDF_USE_COMMAND_LINKS
| TDF_POSITION_RELATIVE_TO_WINDOW
);
173 taskdlg
.AddCommandControl(BTN_OFFSET
+ 1, lpButton1
);
174 if (lpButton2
&& *lpButton2
)
175 taskdlg
.AddCommandControl(BTN_OFFSET
+ 2, lpButton2
);
176 if (lpButton3
&& *lpButton3
)
177 taskdlg
.AddCommandControl(BTN_OFFSET
+ 3, lpButton3
);
178 taskdlg
.SetDefaultCommandControl(BTN_OFFSET
+ nDef
);
179 taskdlg
.SetMainIcon(icon
);
180 return (UINT
)taskdlg
.DoModal(GetMainHWND(hWnd
)) - BTN_OFFSET
;
183 box
.m_sButton1
= lpButton1
;
184 box
.m_sButton2
= lpButton2
;
185 box
.m_sButton3
= lpButton3
;
186 box
.m_hIcon
= (HICON
)::LoadImage(AfxGetResourceHandle(), icon
, IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
188 box
.m_hIcon
= (HICON
)::LoadImage(nullptr, icon
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
190 box
.m_bDestroyIcon
= TRUE
;
193 return box
.GoModal(CWnd::FromHandle(hWnd
), lpCaption
, lpMessage
, nDef
);
196 UINT
CMessageBox::Show(HWND hWnd
, UINT nMessage
, UINT nCaption
, int nDef
, LPCTSTR icon
, UINT nButton1
, UINT nButton2
, UINT nButton3
)
203 sButton1
.LoadString(nButton1
);
204 sButton2
.LoadString(nButton2
);
205 sButton3
.LoadString(nButton3
);
206 sMessage
.LoadString(nMessage
);
207 sCaption
.LoadString(nCaption
);
208 return CMessageBox::Show(hWnd
, sMessage
, sCaption
, nDef
, icon
, sButton1
, sButton2
, sButton3
);
211 UINT
CMessageBox::ShowCheck(HWND hWnd
, UINT nMessage
, UINT nCaption
, UINT uType
, LPCTSTR lpRegistry
, UINT nCheckMessage
, BOOL
*bChecked
)
216 sMessage
.LoadString(nMessage
);
217 sCaption
.LoadString(nCaption
);
218 sCheckMsg
.LoadString(nCheckMessage
);
219 return CMessageBox::ShowCheck(hWnd
, sMessage
, sCaption
, uType
, lpRegistry
, sCheckMsg
, bChecked
);
222 UINT
CMessageBox::ShowCheck(HWND hWnd
, LPCTSTR lpMessage
, LPCTSTR lpCaption
, UINT uType
, LPCTSTR lpRegistry
, LPCTSTR lpCheckMessage
, BOOL
*bChecked
)
224 //check the registry if we have to show the box or just return with the last used return value
225 //this would be the case if the user pressed "do not show again".
229 #ifdef XMESSAGEBOX_APPREGPATH
230 path
= XMESSAGEBOX_APPREGPATH
;
232 path
= "Software\\TortoiseGit\\";
233 path
+= AfxGetApp()->m_pszProfileName
;
235 if (lpRegistry
&& *lpRegistry
&& RegOpenKeyEx(HKEY_CURRENT_USER
, path
, 0, KEY_EXECUTE
, &hKey
)==ERROR_SUCCESS
)
237 int size
= sizeof(dwRetVal
);
239 if (RegQueryValueEx(hKey
, lpRegistry
, nullptr, &type
, (BYTE
*)&dwRetVal
,(LPDWORD
)&size
) == ERROR_SUCCESS
)
241 ASSERT(type
==REG_DWORD
);
243 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Using stored value %ld for \"%s\"\n", dwRetVal
, lpMessage
);
244 return (UINT
)dwRetVal
; //return with the last saved value
251 if (CTaskDialog::IsSupported() && !(uType
& MB_HELP
) && !((uType
& 0xf) == MB_ABORTRETRYIGNORE
) && !((uType
& 0xf) == MB_CANCELTRYCONTINUE
))
253 CTaskDialog
taskdlg(lpMessage
, L
"", lpCaption
, 0, TDF_POSITION_RELATIVE_TO_WINDOW
);
255 switch (uType
& 0xf0)
257 case MB_ICONEXCLAMATION
:
258 taskdlg
.SetMainIcon(IDI_EXCLAMATION
);
260 case MB_ICONASTERISK
:
261 taskdlg
.SetMainIcon(IDI_ASTERISK
);
263 case MB_ICONQUESTION
:
264 taskdlg
.SetMainIcon(IDI_QUESTION
);
267 taskdlg
.SetMainIcon(IDI_HAND
);
270 // set up the buttons
273 case MB_ABORTRETRYIGNORE
:
276 case MB_CANCELTRYCONTINUE
:
280 taskdlg
.SetCommonButtons(TDCBF_OK_BUTTON
| TDCBF_CANCEL_BUTTON
);
281 switch (uType
& 0xf00)
284 taskdlg
.SetDefaultCommandControl(IDCANCEL
);
289 taskdlg
.SetCommonButtons(TDCBF_RETRY_BUTTON
| TDCBF_CANCEL_BUTTON
);
290 switch (uType
& 0xf00)
293 taskdlg
.SetDefaultCommandControl(IDCANCEL
);
298 taskdlg
.SetCommonButtons(TDCBF_YES_BUTTON
| TDCBF_NO_BUTTON
);
299 switch (uType
& 0xf00)
302 taskdlg
.SetDefaultCommandControl(IDNO
);
307 taskdlg
.SetCommonButtons(TDCBF_YES_BUTTON
| TDCBF_NO_BUTTON
| TDCBF_CANCEL_BUTTON
);
308 switch (uType
& 0xf00)
311 taskdlg
.SetDefaultCommandControl(IDNO
);
314 taskdlg
.SetDefaultCommandControl(IDCANCEL
);
320 taskdlg
.SetCommonButtons(TDCBF_OK_BUTTON
);
325 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
326 taskdlg
.SetVerificationCheckboxText(L
"do not show again");
329 m_i18l
.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN
);
330 taskdlg
.SetVerificationCheckboxText(m_i18l
);
334 taskdlg
.SetVerificationCheckboxText(lpCheckMessage
);
335 int result
= (int)taskdlg
.DoModal(GetMainHWND(hWnd
));
337 *bChecked
= taskdlg
.GetVerificationCheckboxState();
338 if (lpRegistry
&& *lpRegistry
&& taskdlg
.GetVerificationCheckboxState())
339 SetRegistryValue(lpRegistry
, result
);
345 box
.m_bShowCheck
= TRUE
;
346 box
.m_sRegistryValue
= lpRegistry
;
349 #ifndef IDS_MSGBOX_DONOTSHOWAGAIN
350 box
.m_sCheckbox
= L
"do not show again";
353 m_i18l
.LoadString(IDS_MSGBOX_DONOTSHOWAGAIN
);
354 box
.m_sCheckbox
= m_i18l
;
358 box
.m_sCheckbox
= lpCheckMessage
;
359 box
.m_bChecked
= bChecked
? *bChecked
: FALSE
;
362 int result
= box
.GoModal(CWnd::FromHandle(hWnd
), lpCaption
, lpMessage
, box
.FillBoxStandard(uType
));
364 *bChecked
= box
.m_bChecked
;
368 UINT
CMessageBox::Show(HWND hWnd
, UINT nMessage
, UINT nCaption
, UINT uType
, LPCTSTR sHelpPath
)
372 sMessage
.LoadString(nMessage
);
373 sCaption
.LoadString(nCaption
);
374 return CMessageBox::Show(hWnd
, sMessage
, sCaption
, uType
, sHelpPath
);
377 UINT
CMessageBox::Show(HWND hWnd
, LPCTSTR lpMessage
, LPCTSTR lpCaption
, UINT uType
, LPCTSTR sHelpPath
)
384 box
.SetHelpPath(sHelpPath
);
385 return box
.GoModal(CWnd::FromHandle(hWnd
), lpCaption
, lpMessage
, box
.FillBoxStandard(uType
));
388 return ::MessageBox(GetMainHWND(hWnd
), lpMessage
, lpCaption
, uType
);
391 UINT
CMessageBox::Show(HWND hWnd
, UINT nMessage
, UINT nCaption
, UINT uType
, UINT nHelpID
)
395 sMessage
.LoadString(nMessage
);
396 sCaption
.LoadString(nCaption
);
403 box
.SetHelpID(nHelpID
);
404 return box
.GoModal(CWnd::FromHandle(hWnd
), sCaption
, sMessage
, box
.FillBoxStandard(uType
));
407 return ::MessageBox(GetMainHWND(hWnd
), sMessage
, sCaption
, uType
);
410 bool CMessageBox::RemoveRegistryKey(LPCTSTR lpRegistry
)
414 #ifdef XMESSAGEBOX_APPREGPATH
415 path
= XMESSAGEBOX_APPREGPATH
;
417 path
= "Software\\TortoiseGit\\";
418 path
+= AfxGetApp()->m_pszProfileName
;
420 if (RegOpenKeyEx(HKEY_CURRENT_USER
, path
, 0, KEY_WRITE
, &hKey
) == ERROR_SUCCESS
)
422 bool ret
= !!RegDeleteValue(hKey
, lpRegistry
);
429 int CMessageBox::FillBoxStandard(UINT uType
)
433 m_uCancelRet
= IDCANCEL
;
434 //load the icons according to uType
435 switch (uType
& 0xf0)
437 case MB_ICONEXCLAMATION
:
438 m_hIcon
= (HICON
)::LoadImage(nullptr, IDI_EXCLAMATION
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
439 ::MessageBeep(MB_ICONEXCLAMATION
);
441 case MB_ICONASTERISK
:
442 m_hIcon
= (HICON
)::LoadImage(nullptr, IDI_ASTERISK
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
443 ::MessageBeep(MB_ICONASTERISK
);
445 case MB_ICONQUESTION
:
446 m_hIcon
= (HICON
)::LoadImage(nullptr, IDI_QUESTION
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
447 ::MessageBeep(MB_ICONQUESTION
);
450 m_hIcon
= (HICON
)::LoadImage(nullptr, IDI_HAND
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
451 ::MessageBeep(MB_ICONHAND
);
454 //set up the button texts
457 case MB_ABORTRETRYIGNORE
:
458 #ifndef IDS_MSGBOX_ABORT
459 m_sButton1
= "&Abort";
461 m_i18l
.LoadString(IDS_MSGBOX_ABORT
);
464 m_uButton1Ret
= IDABORT
;
465 #ifndef IDS_MSGBOX_RETRY
466 m_sButton2
= "&Retry";
468 m_i18l
.LoadString(IDS_MSGBOX_RETRY
);
471 m_uButton2Ret
= IDRETRY
;
472 #ifndef IDS_MSGBOX_IGNORE
473 m_sButton3
= "&Ignore";
475 m_i18l
.LoadString(IDS_MSGBOX_IGNORE
);
478 m_uButton3Ret
= IDIGNORE
;
480 case MB_CANCELTRYCONTINUE
:
481 #ifndef IDS_MSGBOX_CANCEL
482 m_sButton1
= "Cancel";
484 m_i18l
.LoadString(IDS_MSGBOX_CANCEL
);
487 m_uButton1Ret
= IDCANCEL
;
488 #ifndef IDS_MSGBOX_TRYAGAIN
489 m_sButton2
= "&Try Again";
491 m_i18l
.LoadString(IDS_MSGBOX_TRYAGAIN
);
494 m_uButton2Ret
= IDTRYAGAIN
;
495 #ifndef IDS_MSGBOX_CONTINUE
496 m_sButton3
= "&Continue";
498 m_i18l
.LoadString(IDS_MSGBOX_CONTINUE
);
501 m_uButton3Ret
= IDCONTINUE
;
504 #ifndef IDS_MSGBOX_OK
507 m_i18l
.LoadString(IDS_MSGBOX_OK
);
510 m_uButton1Ret
= IDOK
;
511 #ifndef IDS_MSGBOX_CANCEL
512 m_sButton2
= "Cancel";
514 m_i18l
.LoadString(IDS_MSGBOX_CANCEL
);
517 m_uButton2Ret
= IDCANCEL
;
520 #ifndef IDS_MSGBOX_RETRY
521 m_sButton1
= "&Retry";
523 m_i18l
.LoadString(IDS_MSGBOX_RETRY
);
526 m_uButton1Ret
= IDRETRY
;
527 #ifndef IDS_MSGBOX_CANCEL
528 m_sButton2
= "Cancel";
530 m_i18l
.LoadString(IDS_MSGBOX_CANCEL
);
533 m_uButton2Ret
= IDCANCEL
;
536 #ifndef IDS_MSGBOX_YES
539 m_i18l
.LoadString(IDS_MSGBOX_YES
);
542 m_uButton1Ret
= IDYES
;
543 #ifndef IDS_MSGBOX_NO
546 m_i18l
.LoadString(IDS_MSGBOX_NO
);
549 m_uButton2Ret
= IDNO
;
552 #ifndef IDS_MSGBOX_YES
555 m_i18l
.LoadString(IDS_MSGBOX_YES
);
558 m_uButton1Ret
= IDYES
;
559 #ifndef IDS_MSGBOX_NO
562 m_i18l
.LoadString(IDS_MSGBOX_NO
);
565 m_uButton2Ret
= IDNO
;
566 #ifndef IDS_MSGBOX_CANCEL
567 m_sButton3
= "Cancel";
569 m_i18l
.LoadString(IDS_MSGBOX_CANCEL
);
572 m_uButton3Ret
= IDCANCEL
;
576 #ifndef IDS_MSGBOX_OK
579 m_i18l
.LoadString(IDS_MSGBOX_OK
);
583 //now set the default button
584 switch (uType
& 0xf00)
593 // do we need to add a help button?
597 #ifndef IDS_MSGBOX_HELP
600 m_i18l
.LoadString(IDS_MSGBOX_HELP
);
603 if (m_sButton2
.IsEmpty())
605 m_sButton2
= sHelpText
;
606 m_uButton2Ret
= IDHELP
;
608 else if (m_sButton3
.IsEmpty())
610 m_sButton3
= sHelpText
;
611 m_uButton3Ret
= IDHELP
;
617 UINT
CMessageBox::GoModal(CWnd
* pWnd
, const CString
& title
, const CString
& msg
, int nDefaultButton
)
619 NONCLIENTMETRICS ncm
= { 0 };
620 ncm
.cbSize
= sizeof(NONCLIENTMETRICS
);
621 SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(NONCLIENTMETRICS
), &ncm
, 0);
623 memcpy(&m_LogFont
, &(ncm
.lfMessageFont
), sizeof(LOGFONT
));
625 //the problem with the LOGFONT lfHeight is that it is not in pixels,
626 //but the dialog template needs the height in pixels.
627 //We need to convert those values first:
632 pDC
= GetDesktopWindow()->GetDC();
637 hdc
= ::GetDC(nullptr);
640 HWND hw
= pWnd
? pWnd
->m_hWnd
: nullptr;
641 int defButton
= nDefaultButton
== 1 ? MB_DEFBUTTON1
: nDefaultButton
== 2 ? MB_DEFBUTTON2
: nDefaultButton
== 3 ? MB_DEFBUTTON3
: 0;
642 return ::MessageBox(hw
, msg
, title
, m_uType
| defButton
);
645 int pix
= -CDPIAware::Instance().PointsToPixelsY(m_LogFont
.lfHeight
);
646 CDlgTemplate dialogTemplate
= CDlgTemplate(title
, WS_CAPTION
| DS_CENTER
,
647 0, 0, 0, 0, m_LogFont
.lfFaceName
, pix
);
648 dialogTemplate
.AddButton(L
"Button1", WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
| BS_PUSHBUTTON
| ((nDefaultButton
== 1) ? BS_DEFPUSHBUTTON
: 0), 0,
649 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON1
);
650 dialogTemplate
.AddButton(L
"Button2", WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
| BS_PUSHBUTTON
| ((nDefaultButton
== 2) ? BS_DEFPUSHBUTTON
: 0), 0,
651 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON2
);
652 dialogTemplate
.AddButton(L
"Button3", WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
| BS_PUSHBUTTON
| ((nDefaultButton
== 3) ? BS_DEFPUSHBUTTON
: 0), 0,
653 2 + 3, 62, 56, 13, IDC_MESSAGEBOX_BUTTON3
);
654 dialogTemplate
.AddButton(L
"Checkbox", WS_CHILD
| WS_TABSTOP
| BS_AUTOCHECKBOX
, 0,
655 0, 0, 0, 0, IDC_MESSAGEBOX_CHECKBOX
);
657 m_nDefButton
= nDefaultButton
;
659 InitModalIndirect(dialogTemplate
, pWnd
);
661 return (UINT
)DoModal();
664 void CMessageBox::SetRegistryValue(const CString
& sValue
, DWORD value
)
666 if (sValue
.IsEmpty())
670 #ifdef XMESSAGEBOX_APPREGPATH
671 path
= XMESSAGEBOX_APPREGPATH
;
673 path
= "Software\\TortoiseGit\\";
674 path
+= AfxGetApp()->m_pszProfileName
;
678 if (RegCreateKeyEx(HKEY_CURRENT_USER
, path
, 0, L
"", REG_OPTION_NON_VOLATILE
, KEY_WRITE
, nullptr, &hKey
, &disp
) != ERROR_SUCCESS
)
682 RegSetValueEx(hKey
, sValue
, 0, REG_DWORD
,(const BYTE
*) &value
, sizeof(value
));
692 CSize
DrawText(CDC
* pDC
, CRect rect
, const CString
& str
, LOGFONT font
, BOOL bCalculate
= FALSE
)
699 CPoint pt
= rect
.TopLeft();
703 memcpy(&lf
, &font
, sizeof(LOGFONT
));
706 tempFont
.CreateFontIndirect(&lf
);
708 CFont
* pOldFont
= pDC
->SelectObject(&tempFont
);
710 TEXTMETRIC textMetric
;
711 pDC
->GetTextMetrics(&textMetric
);
712 int nHeight
= textMetric
.tmHeight
;
713 int nWidth
= textMetric
.tmAveCharWidth
;
717 //iterate through all characters of the string
718 for (int i
= 0; i
<= str
.GetLength(); ++i
)
721 if (i
< str
.GetLength())
723 switch (str
.GetAt(i
))
734 strText
+= str
.GetAt(i
);
738 else // Immitates new line at the end of the string
743 if (!strText
.IsEmpty())
746 pDC
->TextOut(ptCur
.x
, ptCur
.y
, strText
);
747 CSize s
= pDC
->GetTextExtent(strText
);
757 sz
.cx
= max(sz
.cx
, ptCur
.x
- pt
.x
);
763 int nTemp
= (ptCur
.x
- pt
.x
) % (nWidth
* 4);
767 ptCur
.x
+= (nWidth
* 4) - nTemp
;
769 ptCur
.x
+= nWidth
* 4;
775 //Gets real height of the tooltip
776 sz
.cy
= ptCur
.y
- pt
.y
;
778 pDC
->SelectObject(pOldFont
);
779 tempFont
.DeleteObject();
784 CSize
CMessageBox::GetTextSize(const CString
& str
)
787 GetWindowRect(&rect
);
793 memDC
.CreateCompatibleDC(pDC
);
794 bitmap
.CreateCompatibleBitmap(pDC
, rect
.Width(), rect
.Height());
795 CBitmap
* pOldBitmap
= memDC
.SelectObject(&bitmap
);
797 //get the minimum size of the rectangle of the tooltip
798 CSize sz
= DrawText(&memDC
, rect
, str
, m_LogFont
, TRUE
);
800 memDC
.SelectObject(pOldBitmap
);
802 bitmap
.DeleteObject();
809 CSize
CMessageBox::GetIconSize(HICON hIcon
)
816 //get icon dimensions
817 if (::GetIconInfo(hIcon
, &ii
))
819 sz
.cx
= (DWORD
)(ii
.xHotspot
* 2);
820 sz
.cy
= (DWORD
)(ii
.yHotspot
* 2);
821 //release icon mask bitmaps
823 ::DeleteObject(ii
.hbmMask
);
825 ::DeleteObject(ii
.hbmColor
);
832 CSize
CMessageBox::GetButtonSize()
835 int nButtons
= 0; //number of buttons - 1
837 SetDlgItemText(IDC_MESSAGEBOX_BUTTON1
, m_sButton1
);
838 SetDlgItemText(IDC_MESSAGEBOX_BUTTON2
, m_sButton2
);
839 //GetDlgItem(IDC_MESSAGEBOX_BUTTON2)->SendMessage(BM_SETSTYLE, BS_DEFPUSHBUTTON, 1);
840 SetDlgItemText(IDC_MESSAGEBOX_BUTTON3
, m_sButton3
);
841 SetDlgItemText(IDC_MESSAGEBOX_CHECKBOX
, m_sCheckbox
);
843 CSize sz1
= GetTextSize(m_sButton1
);
844 CSize sz2
= GetTextSize(m_sButton2
);
845 CSize sz3
= GetTextSize(m_sButton3
);
847 sz1
.cx
+= 2*MESSAGEBOX_BUTTONX
;
848 sz1
.cy
+= 2*MESSAGEBOX_BUTTONY
;
852 sz2
.cx
+= 2*MESSAGEBOX_BUTTONX
;
853 sz2
.cy
+= 2*MESSAGEBOX_BUTTONY
;
858 sz3
.cx
+= 2*MESSAGEBOX_BUTTONX
;
859 sz3
.cy
+= 2*MESSAGEBOX_BUTTONY
;
863 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->MoveWindow(0, 0, sz1
.cx
, sz1
.cy
);
864 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->MoveWindow(0, 0, sz2
.cx
, sz2
.cy
);
865 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->MoveWindow(0, 0, sz3
.cx
, sz3
.cy
);
867 sz
.cx
= sz1
.cx
+ sz2
.cx
+ sz3
.cx
+ (nButtons
* MESSAGEBOX_BUTTONMARGIN
);
868 sz
.cy
= max(sz1
.cy
, sz2
.cy
);
869 sz
.cy
= max(sz
.cy
, sz3
.cy
);
873 CSize szCheck
= GetTextSize(m_sCheckbox
);
874 szCheck
.cx
+= 2*GetSystemMetrics(SM_CXMENUCHECK
);
875 szCheck
.cy
+= 2*MESSAGEBOX_BUTTONY
;
876 sz
.cx
= max(sz
.cx
, szCheck
.cx
);
877 sz
.cy
+= szCheck
.cy
+ MESSAGEBOX_BUTTONCHECKMARGIN
;
878 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->MoveWindow(0, 0, szCheck
.cx
, szCheck
.cy
);
884 BEGIN_MESSAGE_MAP(CMessageBox
, CDialog
)
886 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON1
, OnButton1
)
887 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON2
, OnButton2
)
888 ON_BN_CLICKED(IDC_MESSAGEBOX_BUTTON3
, OnButton3
)
891 void CMessageBox::OnPaint()
893 CPaintDC
dc(this); // device context for painting
897 GetClientRect(&rect
);
898 GetClientRect(&drawrect
);
900 //create a memory device-context. This is done to help reduce
901 //screen flicker, since we will paint the entire control to the
902 //off screen device context first.
905 memDC
.CreateCompatibleDC(&dc
);
906 bitmap
.CreateCompatibleBitmap(&dc
, rect
.Width(), rect
.Height());
907 CBitmap
* pOldBitmap
= memDC
.SelectObject(&bitmap
);
909 memDC
.BitBlt(rect
.left
, rect
.top
, rect
.Width(), rect
.Height(), &dc
, 0,0, SRCCOPY
);
911 memDC
.SetBkMode(TRANSPARENT
);
912 memDC
.SetBkColor(GetSysColor(COLOR_WINDOW
));
913 memDC
.SetTextColor(GetSysColor(COLOR_WINDOWTEXT
));
915 //OnDrawBackground();
916 drawrect
.DeflateRect(MESSAGEBOX_BORDERMARGINX
, MESSAGEBOX_BORDERMARGINY
);
919 DrawIconEx(memDC
.m_hDC
, drawrect
.left
, max(drawrect
.top
, drawrect
.top
+
920 ((drawrect
.Height() - m_szAllButtons
.cy
- MESSAGEBOX_TEXTBUTTONMARGIN
- m_szIcon
.cy
) / 2)),
921 m_hIcon
, m_szIcon
.cx
, m_szIcon
.cy
, 0, nullptr, DI_NORMAL
);
923 drawrect
.left
+= m_szIcon
.cx
+ MESSAGEBOX_ICONMARGIN
;
924 if (m_szIcon
.cy
> m_szText
.cy
)
925 drawrect
.top
+= (m_szIcon
.cy
- m_szText
.cy
) / 2;
928 DrawText(&memDC
, drawrect
, m_sMessage
, m_LogFont
);
930 //Copy the memory device context back into the original DC.
931 dc
.BitBlt(rect
.left
, rect
.top
, rect
.Width(), rect
.Height(), &memDC
, 0,0, SRCCOPY
);
934 memDC
.SelectObject(pOldBitmap
);
936 bitmap
.DeleteObject();
939 void CMessageBox::OnButton1()
941 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->SendMessage(BM_GETCHECK
, 0, 0)==BST_CHECKED
)
944 SetRegistryValue(m_sRegistryValue
, m_uButton1Ret
);
948 EndDialog(m_uButton1Ret
);
951 void CMessageBox::OnButton2()
953 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->SendMessage(BM_GETCHECK
, 0, 0)==BST_CHECKED
)
956 SetRegistryValue(m_sRegistryValue
, m_uButton2Ret
);
960 if ((m_uButton2Ret
== IDHELP
)&&(!m_sHelpPath
.IsEmpty()))
962 typedef HWND (WINAPI
* FPHH
)(HWND
, LPCWSTR
, UINT
, DWORD
);
963 FPHH pHtmlHelp
= nullptr; // Function pointer
964 CAutoLibrary hInstHtmlHelp
= AtlLoadSystemLibraryUsingFullPath(L
"HHCtrl.ocx");
965 HWND hHelp
= nullptr;
968 (FARPROC
&)pHtmlHelp
= GetProcAddress(hInstHtmlHelp
, "HtmlHelpW");
970 hHelp
= pHtmlHelp(m_hWnd
, (LPCTSTR
)m_sHelpPath
, HH_DISPLAY_TOPIC
, NULL
);
973 ::MessageBox(m_hWnd
, L
"could not show help file", L
"Help", MB_ICONERROR
);
975 else if (m_uButton2Ret
== IDHELP
)
978 EndDialog(m_uButton2Ret
);
981 void CMessageBox::OnButton3()
983 if (GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->SendMessage(BM_GETCHECK
, 0, 0)==BST_CHECKED
)
986 SetRegistryValue(m_sRegistryValue
, m_uButton3Ret
);
990 if ((m_uButton3Ret
== IDHELP
)&&(!m_sHelpPath
.IsEmpty()))
992 typedef HWND (WINAPI
* FPHH
)(HWND
, LPCWSTR
, UINT
, DWORD
);
993 FPHH pHtmlHelp
= nullptr; // Function pointer
994 CAutoLibrary hInstHtmlHelp
= AtlLoadSystemLibraryUsingFullPath(L
"HHCtrl.ocx");
995 HWND hHelp
= nullptr;
998 (FARPROC
&)pHtmlHelp
= GetProcAddress(hInstHtmlHelp
, "HtmlHelpW");
1000 hHelp
= pHtmlHelp(m_hWnd
, (LPCTSTR
)m_sHelpPath
, HH_DISPLAY_TOPIC
, NULL
);
1003 ::MessageBox(m_hWnd
, L
"could not show help file", L
"Help", MB_ICONERROR
);
1005 else if (m_uButton3Ret
== IDHELP
)
1008 EndDialog(m_uButton3Ret
);
1011 void CMessageBox::OnCancel()
1013 if (m_uCancelRet
== IDCANCEL
)
1014 EndDialog(m_uCancelRet
);
1015 //__super::OnCancel();
1018 BOOL
CMessageBox::OnInitDialog()
1020 __super::OnInitDialog();
1022 CRect
rect(0, 0, 0, 0);
1024 //determine the required size of the message box
1025 m_szText
= GetTextSize(m_sMessage
);
1026 CSize szIcon
= GetIconSize(m_hIcon
);
1027 CSize szButtons
= GetButtonSize();
1030 szIconText
.cx
= m_szText
.cx
+ szIcon
.cx
+ ((szIcon
.cx
== 0) ? MESSAGEBOX_ICONMARGIN
: (2 * MESSAGEBOX_ICONMARGIN
));
1031 szIconText
.cy
= max(szIcon
.cy
, m_szText
.cy
);
1033 rect
.right
= max(szButtons
.cx
, szIconText
.cx
);
1034 rect
.right
+= 2*GetSystemMetrics(SM_CXBORDER
);
1035 rect
.right
+= 2*MESSAGEBOX_BORDERMARGINX
;
1036 rect
.bottom
= szIconText
.cy
;
1037 rect
.bottom
+= szButtons
.cy
;
1038 rect
.bottom
+= 2*MESSAGEBOX_BORDERMARGINY
+ MESSAGEBOX_TEXTBUTTONMARGIN
;
1039 rect
.bottom
+= GetSystemMetrics(SM_CYCAPTION
);
1040 rect
.bottom
+= 2 * GetSystemMetrics(SM_CYFIXEDFRAME
);
1041 rect
.bottom
+= 2*GetSystemMetrics(SM_CYBORDER
);
1046 GetClientRect(rect
);
1048 //now size and position the buttons as we need them
1049 ASSERT(!m_sButton1
.IsEmpty()); //at least the first button must be there!
1050 if (m_sButton2
.IsEmpty())
1054 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->GetWindowRect(rt
);
1056 rt
.MoveToX(rect
.left
+ ((rect
.Width() - m_szButtons
.cx
)/2));
1057 rt
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1058 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->MoveWindow(rt
);
1059 //hide the other two buttons
1060 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->ShowWindow(SW_HIDE
);
1061 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->ShowWindow(SW_HIDE
);
1063 else if (m_sButton3
.IsEmpty())
1068 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->GetWindowRect(rt1
);
1069 ScreenToClient(rt1
);
1070 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->GetWindowRect(rt2
);
1071 ScreenToClient(rt2
);
1072 rt1
.MoveToX(rect
.left
+ ((rect
.Width() - m_szButtons
.cx
)/2));
1073 rt1
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1074 rt2
.MoveToX(rt1
.right
+ MESSAGEBOX_BUTTONMARGIN
);
1075 rt2
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1076 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->MoveWindow(rt1
);
1077 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->MoveWindow(rt2
);
1078 //hide the third button
1079 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->ShowWindow(SW_HIDE
);
1085 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->GetWindowRect(buttonrect
);
1089 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->GetWindowRect(rt1
);
1090 ScreenToClient(rt1
);
1091 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->GetWindowRect(rt2
);
1092 ScreenToClient(rt2
);
1093 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->GetWindowRect(rt3
);
1094 ScreenToClient(rt3
);
1095 rt1
.MoveToX(rect
.left
+ ((rect
.Width() - m_szButtons
.cx
)/2));
1096 rt1
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1097 rt2
.MoveToX(rt1
.right
+ MESSAGEBOX_BUTTONMARGIN
);
1098 rt2
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1099 rt3
.MoveToX(rt2
.right
+ MESSAGEBOX_BUTTONMARGIN
);
1100 rt3
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- m_szButtons
.cy
);
1101 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->MoveWindow(rt1
);
1102 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->MoveWindow(rt2
);
1103 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->MoveWindow(rt3
);
1108 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->GetWindowRect(rt
);
1110 rt
.MoveToX(rect
.left
+ MESSAGEBOX_BORDERMARGINX
/*+ ((rect.Width() - szButtons.cx)/2)*/);
1111 rt
.MoveToY(rect
.bottom
- MESSAGEBOX_BORDERMARGINY
- szButtons
.cy
);
1112 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->MoveWindow(rt
);
1113 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->ShowWindow(SW_SHOW
);
1116 GetDlgItem(IDC_MESSAGEBOX_CHECKBOX
)->ShowWindow(SW_HIDE
);
1118 SetWindowPos(&CWnd::wndTopMost
,0,0,0,0,SWP_NOMOVE
|SWP_NOSIZE
);
1119 SetForegroundWindow();
1120 SetFocus(); //Just playing safe
1122 if (m_nDefButton
== 1)
1123 GetDlgItem(IDC_MESSAGEBOX_BUTTON1
)->SetFocus();
1124 if (m_nDefButton
== 2)
1125 GetDlgItem(IDC_MESSAGEBOX_BUTTON2
)->SetFocus();
1126 if (m_nDefButton
== 3)
1127 GetDlgItem(IDC_MESSAGEBOX_BUTTON3
)->SetFocus();
1129 return FALSE
; // return TRUE unless you set the focus to a control
1130 // EXCEPTION: OCX Property Pages should return FALSE
1133 BOOL
CMessageBox::PreTranslateMessage(MSG
* pMsg
)
1135 if (pMsg
->message
== WM_KEYDOWN
)
1137 switch (pMsg
->wParam
)
1142 if (GetAsyncKeyState(VK_CONTROL
)&0x8000)
1144 CClipboardHelper clipboardHelper
;
1145 if(clipboardHelper
.Open(GetSafeHwnd()))
1148 CStringA sClipboard
= CStringA(m_sMessage
);
1149 HGLOBAL hClipboardData
= CClipboardHelper::GlobalAlloc(sClipboard
.GetLength()+1);
1150 char * pchData
= (char*)GlobalLock(hClipboardData
);
1152 strcpy_s(pchData
, sClipboard
.GetLength()+1, (LPCSTR
)sClipboard
);
1153 GlobalUnlock(hClipboardData
);
1154 SetClipboardData(CF_TEXT
,hClipboardData
);
1162 switch (m_uType
& 0xf)
1164 case MB_ABORTRETRYIGNORE
:
1165 EndDialog(m_uButton1Ret
);
1167 case MB_CANCELTRYCONTINUE
:
1168 EndDialog(m_uButton1Ret
);
1171 EndDialog(m_uButton2Ret
);
1173 case MB_RETRYCANCEL
:
1174 EndDialog(m_uButton2Ret
);
1177 EndDialog(m_uButton2Ret
);
1179 case MB_YESNOCANCEL
:
1180 EndDialog(m_uButton3Ret
);
1188 return __super::PreTranslateMessage(pMsg
);