1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2010-2012 - TortoiseGit
4 // Copyright (C) 2003-2006,2008-2011 - 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 "SysProgressDlg.h"
23 CSysProgressDlg::CSysProgressDlg()
26 , m_dwDlgFlags(PROGDLG_NORMAL
)
32 CSysProgressDlg::~CSysProgressDlg()
36 if (m_isVisible
) //still visible, so stop first before destroying
37 m_pIDlg
->StopProgressDialog();
44 bool CSysProgressDlg::EnsureValid()
49 HRESULT hr
= m_pIDlg
.CoCreateInstance (CLSID_ProgressDialog
, NULL
, CLSCTX_INPROC_SERVER
);
50 return (SUCCEEDED(hr
));
53 void CSysProgressDlg::SetTitle(LPCTSTR szTitle
)
58 m_pIDlg
->SetTitle(T2COLE(szTitle
));
61 void CSysProgressDlg::SetTitle ( UINT idTitle
)
63 SetTitle(CString(MAKEINTRESOURCE(idTitle
)));
66 void CSysProgressDlg::SetLine(DWORD dwLine
, LPCTSTR szText
, bool bCompactPath
/* = false */)
71 m_pIDlg
->SetLine(dwLine
, T2COLE(szText
), bCompactPath
, NULL
);
76 void CSysProgressDlg::SetCancelMsg ( UINT idMessage
)
78 SetCancelMsg(CString(MAKEINTRESOURCE(idMessage
)));
82 void CSysProgressDlg::SetCancelMsg(LPCTSTR szMessage
)
87 m_pIDlg
->SetCancelMsg(T2COLE(szMessage
), NULL
);
91 void CSysProgressDlg::SetAnimation(HINSTANCE hinst
, UINT uRsrcID
)
95 m_pIDlg
->SetAnimation(hinst
, uRsrcID
);
99 void CSysProgressDlg::SetAnimation(UINT uRsrcID
)
103 m_pIDlg
->SetAnimation(AfxGetResourceHandle(), uRsrcID
);
107 void CSysProgressDlg::SetTime(bool bTime
/* = true */)
109 m_dwDlgFlags
&= ~(PROGDLG_NOTIME
| PROGDLG_AUTOTIME
);
112 m_dwDlgFlags
|= PROGDLG_AUTOTIME
;
114 m_dwDlgFlags
|= PROGDLG_NOTIME
;
117 void CSysProgressDlg::SetShowProgressBar(bool bShow
/* = true */)
120 m_dwDlgFlags
&= ~PROGDLG_NOPROGRESSBAR
;
122 m_dwDlgFlags
|= PROGDLG_NOPROGRESSBAR
;
125 HRESULT
CSysProgressDlg::ShowModal (CWnd
* pwndParent
, BOOL immediately
/* = true */)
128 return ShowModal(pwndParent
->GetSafeHwnd(), immediately
);
131 HRESULT
CSysProgressDlg::ShowModeless(CWnd
* pwndParent
, BOOL immediately
)
134 return ShowModeless(pwndParent
->GetSafeHwnd(), immediately
);
137 void CSysProgressDlg::FormatPathLine ( DWORD dwLine
, UINT idFormatText
, ...)
140 va_start(args
, idFormatText
);
143 sText
.FormatV(CString(MAKEINTRESOURCE(idFormatText
)), args
);
144 SetLine(dwLine
, sText
, true);
149 void CSysProgressDlg::FormatPathLine ( DWORD dwLine
, CString FormatText
, ...)
152 va_start(args
, FormatText
);
155 sText
.FormatV(FormatText
, args
);
156 SetLine(dwLine
, sText
, true);
161 void CSysProgressDlg::FormatNonPathLine(DWORD dwLine
, UINT idFormatText
, ...)
164 va_start(args
, idFormatText
);
167 sText
.FormatV(CString(MAKEINTRESOURCE(idFormatText
)), args
);
168 SetLine(dwLine
, sText
, false);
173 void CSysProgressDlg::FormatNonPathLine(DWORD dwLine
, CString FormatText
, ...)
176 va_start(args
, FormatText
);
179 sText
.FormatV(FormatText
, args
);
180 SetLine(dwLine
, sText
, false);
186 HRESULT
CSysProgressDlg::ShowModal(HWND hWndParent
, BOOL immediately
/* = true */)
189 m_hWndProgDlg
= NULL
;
192 m_hWndParent
= hWndParent
;
193 HRESULT hr
= m_pIDlg
->StartProgressDialog(hWndParent
, NULL
, m_dwDlgFlags
| PROGDLG_MODAL
, NULL
);
197 ATL::CComPtr
<IOleWindow
> pOleWindow
;
198 HRESULT hr2
= m_pIDlg
.QueryInterface(&pOleWindow
);
201 hr2
= pOleWindow
->GetWindow(&m_hWndProgDlg
);
204 // StartProgressDialog creates a new thread to host the progress window.
205 // When the window receives WM_DESTROY message StopProgressDialog() wrongly
206 // attempts to re-enable the parent in the calling thread (our thread),
207 // after the progress window is destroyed and the progress thread has died.
208 // When the progress window dies, the system tries to assign a new foreground window.
209 // It cannot assign to hwndParent because StartProgressDialog (w/PROGDLG_MODAL) disabled the parent window.
210 // So the system hands the foreground activation to the next process that wants it in the
211 // system foreground queue. Thus we lose our right to recapture the foreground window.
212 // The way to fix this bug is to insert a call to EnableWindow(hWndParent) in the WM_DESTROY
213 // handler for the progress window in the progress thread.
215 // To do that, we Subclass the progress dialog
216 // Since the window and thread created by the progress dialog object live on a few
217 // milliseconds after calling Stop() and Release(), we must not store anything
218 // in member variables of this class but must only store everything in the window
219 // itself: thus we use SetProp()/GetProp() to store the data.
222 m_OrigProc
= (WNDPROC
) SetWindowLongPtr(m_hWndProgDlg
, GWLP_WNDPROC
, (LONG_PTR
) fnSubclass
);
223 SetProp(m_hWndProgDlg
, L
"ParentWindow", m_hWndParent
);
224 SetProp(m_hWndProgDlg
, L
"OrigProc", m_OrigProc
);
227 ShowWindow(m_hWndProgDlg
, SW_SHOW
);
235 HRESULT
CSysProgressDlg::ShowModeless(HWND hWndParent
, BOOL immediately
)
238 m_hWndProgDlg
= NULL
;
241 m_hWndParent
= hWndParent
;
242 HRESULT hr
= m_pIDlg
->StartProgressDialog(hWndParent
, NULL
, m_dwDlgFlags
, NULL
);
246 ATL::CComPtr
<IOleWindow
> pOleWindow
;
247 HRESULT hr2
= m_pIDlg
.QueryInterface(&pOleWindow
);
250 hr2
= pOleWindow
->GetWindow(&m_hWndProgDlg
);
253 // see comment in ShowModal() for why we subclass the window
256 m_OrigProc
= (WNDPROC
) SetWindowLongPtr(m_hWndProgDlg
, GWLP_WNDPROC
, (LONG_PTR
) fnSubclass
);
257 SetProp(m_hWndProgDlg
, L
"ParentWindow", m_hWndParent
);
258 SetProp(m_hWndProgDlg
, L
"OrigProc", m_OrigProc
);
261 ShowWindow(m_hWndProgDlg
, SW_SHOW
);
268 void CSysProgressDlg::SetProgress(DWORD dwProgress
, DWORD dwMax
)
272 m_pIDlg
->SetProgress(dwProgress
, dwMax
);
276 void CSysProgressDlg::SetProgress64(ULONGLONG u64Progress
, ULONGLONG u64ProgressMax
)
280 m_pIDlg
->SetProgress64(u64Progress
, u64ProgressMax
);
284 bool CSysProgressDlg::HasUserCancelled()
289 return (0 != m_pIDlg
->HasUserCancelled());
292 void CSysProgressDlg::Stop()
294 if ((m_isVisible
)&&(IsValid()))
296 m_pIDlg
->StopProgressDialog();
297 // Sometimes the progress dialog sticks around after stopping it,
298 // until the mouse pointer is moved over it or some other triggers.
299 // We hide the window here immediately.
302 ShowWindow(m_hWndProgDlg
, SW_HIDE
);
307 m_hWndProgDlg
= NULL
;
311 void CSysProgressDlg::ResetTimer()
315 m_pIDlg
->Timer(PDTIMER_RESET
, NULL
);
319 LRESULT
CSysProgressDlg::fnSubclass(HWND hwnd
,UINT uMsg
,WPARAM wParam
,LPARAM lParam
)
321 LONG_PTR origproc
= (LONG_PTR
)GetProp(hwnd
, L
"OrigProc");
322 if (uMsg
== WM_DESTROY
)
324 HWND hParent
= (HWND
)GetProp(hwnd
, L
"ParentWindow");
325 EnableWindow(hParent
, TRUE
);
327 SetWindowLongPtr (hwnd
, GWLP_WNDPROC
, origproc
);
328 RemoveProp(hwnd
, L
"ParentWindow");
329 RemoveProp(hwnd
, L
"OrigProc");
331 return CallWindowProc ((WNDPROC
)origproc
, hwnd
, uMsg
, wParam
, lParam
);