ReactOS 0.4.16-dev-751-g45ed1a9
CProgressDialog.cpp
Go to the documentation of this file.
1/*
2 * Progress dialog
3 *
4 * Copyright 2007 Mikolaj Zalewski
5 * Copyright 2014 Huw Campbell
6 *
7 * this library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * this library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include <precomp.h>
23
24#define COBJMACROS
25
26#define CANCEL_MSG_LINE 2
27
28/* Note: to avoid a deadlock we don't want to send messages to the dialog
29 * with the critical section held. Instead we only mark what fields should be
30 * updated and the dialog proc does the update */
31#define UPDATE_PROGRESS 0x1
32#define UPDATE_TITLE 0x2
33#define UPDATE_LINE1 0x4
34#define UPDATE_LINE2 (UPDATE_LINE1<<1)
35#define UPDATE_LINE3 (UPDATE_LINE1<<2)
36
37
38#define WM_DLG_UPDATE (WM_APP+1) /* set to the dialog when it should update */
39#define WM_DLG_DESTROY (WM_APP+2) /* DestroyWindow must be called from the owning thread */
40
41#define ID_3SECONDS 101
42
43#define BUFFER_SIZE 256
44
46{
47 this->hwnd = NULL;
53
54 this->lines[0][0] = this->lines[1][0] = this->lines[2][0] = UNICODE_NULL;
55 this->cancelMsg[0] = this->title[0] = UNICODE_NULL;
56
57 this->clockHand = -1;
58 this->progressClock[29].ullMark = 0ull;
59 this->dwStartTime = GetTickCount();
60
62}
63
65{
66 if (this->hwnd)
67 this->end_dialog();
68 HeapFree(GetProcessHeap(), 0, this->lines[0]);
69 HeapFree(GetProcessHeap(), 0, this->lines[1]);
70 HeapFree(GetProcessHeap(), 0, this->lines[2]);
72 HeapFree(GetProcessHeap(), 0, this->title);
74}
75
76static void set_buffer(LPWSTR *buffer, LPCWSTR string)
77{
78 if (!string)
79 {
80 (*buffer)[0] = UNICODE_NULL;
81 return;
82 }
83
85}
86
88{
92};
93
94static void load_string(LPWSTR *buffer, HINSTANCE hInstance, UINT uiResourceId)
95{
96 WCHAR string[256];
97
98 LoadStringW(hInstance, uiResourceId, string, sizeof(string)/sizeof(string[0]));
99
100 set_buffer(buffer, string);
101}
102
104{
105 HWND hProgress = GetDlgItem(this->hwnd, IDC_PROGRESS_BAR);
106 SetWindowLongW(hProgress, GWL_STYLE,
108}
109
111{
112 WCHAR empty[] = {0};
113
115 SetWindowTextW(this->hwnd, this->title);
116
117 if (dwUpdate & UPDATE_LINE1)
118 SetDlgItemTextW(this->hwnd, IDC_TEXT_LINE, (this->isCancelled ? empty : this->lines[0]));
119 if (dwUpdate & UPDATE_LINE2)
120 SetDlgItemTextW(this->hwnd, IDC_TEXT_LINE+1, (this->isCancelled ? empty : this->lines[1]));
122 SetDlgItemTextW(this->hwnd, IDC_TEXT_LINE+2, (this->isCancelled ? this->cancelMsg : this->lines[2]));
123
125 {
128
129 /* progress bar requires 32-bit coordinates */
130 while (ullTotal >> 32)
131 {
132 ullTotal >>= 1;
133 ullCompleted >>= 1;
134 }
135
138 }
139}
140
142{
143 SendMessageW(this->hwnd, WM_DLG_DESTROY, 0, 0);
144 /* native doesn't re-enable the window? */
145 if (this->hwndDisabledParent)
147 this->hwnd = NULL;
148}
149
151{
153
154 switch (msg)
155 {
156 case WM_INITDIALOG:
157 {
158 struct create_params *params = (struct create_params *)lParam;
159
160 /* Note: until we set the hEvent, the object is protected by
161 * the critical section held by StartProgress */
163 This = params->This;
164 This->hwnd = hwnd;
165
166 if (This->dwFlags & PROGDLG_NOPROGRESSBAR)
168 if (This->dwFlags & PROGDLG_NOCANCEL)
170 if (This->dwFlags & PROGDLG_MARQUEEPROGRESS)
171 This->set_progress_marquee();
172 if (This->dwFlags & PROGDLG_NOMINIMIZE)
174
175 This->update_dialog(0xffffffff);
176 This->dwUpdate = 0;
177 This->isCancelled = FALSE;
178
179 SetTimer(hwnd, ID_3SECONDS, 3 * 1000, NULL);
180
181 SetEvent(params->hEvent);
182 return TRUE;
183 }
184
185 case WM_DLG_UPDATE:
187 This->update_dialog(This->dwUpdate);
188 This->dwUpdate = 0;
190 return TRUE;
191
192 case WM_DLG_DESTROY:
194 PostThreadMessageW(GetCurrentThreadId(), WM_NULL, 0, 0); /* wake up the GetMessage */
196
197 return TRUE;
198
199 case WM_CLOSE:
200 case WM_COMMAND:
201 if (msg == WM_CLOSE || wParam == IDCANCEL)
202 {
204 This->isCancelled = TRUE;
205
206 if (!This->cancelMsg[0]) {
207 load_string(&This->cancelMsg, _AtlBaseModule.GetResourceInstance(), IDS_CANCELLING);
208 }
209
210 This->set_progress_marquee();
214 }
215 return TRUE;
216
217 case WM_TIMER:
219 if (This->progressClock[29].ullMark != 0ull) {
220 // We have enough info to take a guess
221 ULONGLONG sizeDiff = This->progressClock[This->clockHand].ullMark -
222 This->progressClock[(This->clockHand + 29) % 30].ullMark;
223 DWORD timeDiff = This->progressClock[This->clockHand].dwTime -
224 This->progressClock[(This->clockHand + 29) % 30].dwTime;
225 DWORD runDiff = This->progressClock[This->clockHand].dwTime -
226 This->dwStartTime;
227 ULONGLONG sizeLeft = This->ullTotal - This->progressClock[This->clockHand].ullMark;
228
229 // A guess for time remaining based on the recent slope.
230 DWORD timeLeftD = (DWORD) timeDiff * ((double) sizeLeft) / ((double) sizeDiff);
231 // A guess for time remaining based on the start time and current position
232 DWORD timeLeftI = (DWORD) runDiff * ((double) sizeLeft) / ((double) This->progressClock[This->clockHand].ullMark);
233
234 StrFromTimeIntervalW(This->lines[2], 128, timeLeftD * 0.3 + timeLeftI * 0.7 , 2);
235 This->update_dialog( UPDATE_LINE1 << 2 );
236 }
238
239 return TRUE;
240 }
241 return FALSE;
242}
243
244static DWORD WINAPI dialog_thread(LPVOID lpParameter)
245{
246 /* Note: until we set the hEvent in WM_INITDIALOG, the ProgressDialog object
247 * is protected by the critical section held by StartProgress */
248 struct create_params *params = (struct create_params *) lpParameter;
249 HWND hwnd;
250 MSG msg;
251
252 hwnd = CreateDialogParamW(_AtlBaseModule.GetResourceInstance(),
254 params->hwndParent,
256 (LPARAM)params);
257
258 while (GetMessageW(&msg, NULL, 0, 0) > 0)
259 {
260 if (!IsWindow(hwnd))
261 break;
263 {
266 }
267 }
268
269 return 0;
270}
271
273{
274 static const INITCOMMONCONTROLSEX init = { sizeof(init), ICC_ANIMATE_CLASS };
275
276 struct create_params params;
278
279 // TRACE("(%p, %p, %x, %p)\n", this, punkEnableModeless, dwFlags, reserved);
280 if (punkEnableModeless || reserved)
281 FIXME("Reserved parameters not null (%p, %p)\n", punkEnableModeless, reserved);
283 FIXME("Flags PROGDLG_AUTOTIME not supported\n");
285 FIXME("Flags PROGDLG_NOTIME not supported\n");
286
288
289 EnterCriticalSection(&this->cs);
290
291 if (this->hwnd)
292 {
293 LeaveCriticalSection(&this->cs);
294 return S_OK; /* as on XP */
295 }
296 this->dwFlags = dwFlags;
297 params.This = this;
298 params.hwndParent = hwndParent;
299 params.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
300
303 CloseHandle(params.hEvent);
305
306 this->hwndDisabledParent = NULL;
307 if (hwndParent && (dwFlags & PROGDLG_MODAL))
308 {
309 HWND hwndDisable = GetAncestor(hwndParent, GA_ROOT);
310 if (EnableWindow(hwndDisable, FALSE))
311 this->hwndDisabledParent = hwndDisable;
312 }
313
314 LeaveCriticalSection(&this->cs);
315
316 return S_OK;
317}
318
320{
321 EnterCriticalSection(&this->cs);
322 if (this->hwnd)
323 this->end_dialog();
324 LeaveCriticalSection(&this->cs);
325
326 return S_OK;
327}
328
330{
331 HWND hwnd;
332
333 EnterCriticalSection(&this->cs);
334 set_buffer(&this->title, pwzTitle);
335 this->dwUpdate |= UPDATE_TITLE;
336 hwnd = this->hwnd;
337 LeaveCriticalSection(&this->cs);
338
339 if (hwnd)
341
342 return S_OK;
343}
344
346{
347 HWND hAnimation = GetDlgItem(this->hwnd, IDD_PROGRESS_DLG);
348 SetWindowLongW(hAnimation, GWL_STYLE,
350
351 if(!Animate_OpenEx(hAnimation,hInstance,MAKEINTRESOURCEW(uiResourceId)))
352 return S_FALSE;
353
354 return S_OK;
355}
356
357BOOL WINAPI CProgressDialog::HasUserCancelled()
358{
359 return this->isCancelled;
360}
361
363{
364 HWND hwnd;
365
366 EnterCriticalSection(&this->cs);
367 this->ullTotal = ullTotal;
368 this->ullCompleted = ullCompleted;
369
370 if (GetTickCount() - this->progressClock[(this->clockHand + 29) % 30].dwTime > 20) {
371 this->clockHand = (this->clockHand + 1) % 30;
374 }
375
376 this->dwUpdate |= UPDATE_PROGRESS;
377 hwnd = this->hwnd;
378 LeaveCriticalSection(&this->cs);
379
380 if (hwnd)
382
383 return S_OK; /* Windows sometimes returns S_FALSE */
384}
385
387{
388 return this->SetProgress64(dwCompleted, dwTotal);
389}
390
392{
393 HWND hwnd;
394
395 if (reserved)
396 FIXME("reserved pointer not null (%p)\n", reserved);
397
398 dwLineNum--;
399 if (dwLineNum >= 3) /* Windows seems to do something like that */
400 dwLineNum = 0;
401
402 EnterCriticalSection(&this->cs);
403 set_buffer(&this->lines[dwLineNum], pwzLine);
404 this->dwUpdate |= UPDATE_LINE1 << dwLineNum;
405 hwnd = (this->isCancelled ? NULL : this->hwnd); /* no sense to send the message if window cancelled */
406 LeaveCriticalSection(&this->cs);
407
408 if (hwnd)
410
411 return S_OK;
412}
413
415{
416 HWND hwnd;
417
418 if (reserved)
419 FIXME("reserved pointer not null (%p)\n", reserved);
420
421 EnterCriticalSection(&this->cs);
422 set_buffer(&this->cancelMsg, pwzMsg);
424 hwnd = (this->isCancelled ? this->hwnd : NULL); /* no sense to send the message if window not cancelled */
425 LeaveCriticalSection(&this->cs);
426
427 if (hwnd)
429
430 return S_OK;
431}
432
434{
435 if (reserved)
436 FIXME("Reserved field not NULL but %p\n", reserved);
437
438 return S_OK;
439}
440
442{
443 EnterCriticalSection(&this->cs);
444 *phwnd = this->hwnd;
445 LeaveCriticalSection(&this->cs);
446 return S_OK;
447}
448
450{
451 return E_NOTIMPL;
452}
#define UPDATE_LINE2
static INT_PTR CALLBACK dialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
#define WM_DLG_UPDATE
static void load_string(LPWSTR *buffer, HINSTANCE hInstance, UINT uiResourceId)
#define ID_3SECONDS
#define UPDATE_LINE3
#define BUFFER_SIZE
static DWORD WINAPI dialog_thread(LPVOID lpParameter)
#define UPDATE_TITLE
#define WM_DLG_DESTROY
static void set_buffer(LPWSTR *buffer, LPCWSTR string)
#define UPDATE_PROGRESS
#define CANCEL_MSG_LINE
#define UPDATE_LINE1
#define msg(x)
Definition: auth_time.c:54
#define FIXME(fmt,...)
Definition: precomp.h:53
HINSTANCE hInstance
Definition: charmap.c:19
STDMETHOD() SetProgress64(ULONGLONG ullCompleted, ULONGLONG ullTotal) override
STDMETHOD() SetLine(DWORD dwLineNum, LPCWSTR pwzLine, BOOL bPath, LPCVOID reserved) override
STDMETHOD() StopProgressDialog() override
void update_dialog(DWORD dwUpdate)
STDMETHOD() SetProgress(DWORD dwCompleted, DWORD dwTotal) override
ULONGLONG ullTotal
STDMETHOD() GetWindow(HWND *phwnd) override
STDMETHOD() SetCancelMsg(LPCWSTR pwzMsg, LPCVOID reserved) override
STDMETHOD() Timer(DWORD dwTimerAction, LPCVOID reserved) override
CRITICAL_SECTION cs
STDMETHOD() SetAnimation(HINSTANCE hInstance, UINT uiResourceId) override
STDMETHOD() ContextSensitiveHelp(BOOL fEnterMode) override
STDMETHOD() StartProgressDialog(HWND hwndParent, IUnknown *punkEnableModeless, DWORD dwFlags, LPCVOID reserved) override
STDMETHOD() SetTitle(LPCWSTR pwzTitle) override
progressMark progressClock[30]
ULONGLONG ullCompleted
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
BOOL WINAPI InitCommonControlsEx(const INITCOMMONCONTROLSEX *lpInitCtrls)
Definition: commctrl.c:900
static HWND hwndParent
Definition: cryptui.c:300
#define E_NOTIMPL
Definition: ddrawi.h:99
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define IDS_CANCELLING
Definition: resource.h:134
#define IDC_TEXT_LINE
Definition: resource.h:138
#define IDD_PROGRESS_DLG
Definition: resource.h:139
#define IDC_PROGRESS_BAR
Definition: resource.h:137
static const WCHAR empty[]
Definition: main.c:47
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CALLBACK
Definition: compat.h:35
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS, int iDigits)
Definition: string.c:2153
r reserved
Definition: btrfs.c:3006
#define INFINITE
Definition: serial.h:102
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint buffer
Definition: glext.h:5915
GLenum const GLfloat * params
Definition: glext.h:5645
#define S_OK
Definition: intsafe.h:52
#define BUFFER_SIZE
Definition: freeldrpage.c:26
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned int UINT
Definition: ndis.h:50
HANDLE hThread
Definition: wizard.c:28
#define DWORD
Definition: nt_native.h:44
#define UNICODE_NULL
#define WS_MINIMIZEBOX
Definition: pedump.c:631
#define PBM_SETRANGE32
Definition: commctrl.h:2193
#define Animate_OpenEx(hwnd, hInst, szName)
Definition: commctrl.h:4170
#define ICC_ANIMATE_CLASS
Definition: commctrl.h:65
#define PBS_MARQUEE
Definition: commctrl.h:2203
#define PBM_SETPOS
Definition: commctrl.h:2189
#define ACS_TRANSPARENT
Definition: commctrl.h:4152
#define ACS_AUTOPLAY
Definition: commctrl.h:4153
#define ACS_CENTER
Definition: commctrl.h:4151
#define PROGDLG_NOPROGRESSBAR
Definition: shlobj.h:969
#define PROGDLG_NOTIME
Definition: shlobj.h:967
#define PROGDLG_NOCANCEL
Definition: shlobj.h:971
#define PROGDLG_MARQUEEPROGRESS
Definition: shlobj.h:970
#define PROGDLG_AUTOTIME
Definition: shlobj.h:966
#define PROGDLG_NOMINIMIZE
Definition: shlobj.h:968
#define PROGDLG_MODAL
Definition: shlobj.h:965
DWORD dwTime
Definition: solitaire.cpp:27
STRSAFEAPI StringCbCopyW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:166
CProgressDialog * This
static GLboolean set_buffer(GLcontext *ctx, GLenum mode)
Definition: swimpl.c:872
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:651
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
int32_t INT_PTR
Definition: typedefs.h:64
uint64_t ULONGLONG
Definition: typedefs.h:67
DWORD WINAPI GetCurrentThreadId(void)
Definition: thread.c:459
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
UINT_PTR WPARAM
Definition: windef.h:207
CONST void * LPCVOID
Definition: windef.h:191
#define WINAPI
Definition: msvc.h:6
#define S_FALSE
Definition: winerror.h:2357
static int init
Definition: wintirpc.c:33
HWND WINAPI CreateDialogParamW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_opt_ HWND, _In_opt_ DLGPROC, _In_ LPARAM)
BOOL WINAPI IsWindow(_In_opt_ HWND)
#define SW_HIDE
Definition: winuser.h:771
#define WM_CLOSE
Definition: winuser.h:1624
#define DWLP_USER
Definition: winuser.h:875
#define GetWindowLongPtrW
Definition: winuser.h:4832
#define GA_ROOT
Definition: winuser.h:2792
BOOL WINAPI TranslateMessage(_In_ const MSG *)
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
BOOL WINAPI IsDialogMessageW(_In_ HWND, _In_ LPMSG)
#define IDCANCEL
Definition: winuser.h:834
BOOL WINAPI GetMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT)
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
LONG WINAPI SetWindowLongW(_In_ HWND, _In_ int, _In_ LONG)
LONG WINAPI GetWindowLongW(_In_ HWND, _In_ int)
#define WM_COMMAND
Definition: winuser.h:1743
BOOL WINAPI SetDlgItemTextW(_In_ HWND, _In_ int, _In_ LPCWSTR)
#define WM_INITDIALOG
Definition: winuser.h:1742
HWND WINAPI GetDlgItem(_In_opt_ HWND, _In_ int)
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
LRESULT WINAPI SendDlgItemMessageW(_In_ HWND, _In_ int, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI SetWindowTextW(_In_ HWND, _In_opt_ LPCWSTR)
BOOL WINAPI PostThreadMessageW(_In_ DWORD, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_TIMER
Definition: winuser.h:1745
#define WM_NULL
Definition: winuser.h:1610
BOOL WINAPI EnableWindow(_In_ HWND, _In_ BOOL)
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
#define SetWindowLongPtrW
Definition: winuser.h:5358
#define GWL_STYLE
Definition: winuser.h:855
BOOL WINAPI DestroyWindow(_In_ HWND)
HWND WINAPI GetAncestor(_In_ HWND, _In_ UINT)
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185