ReactOS 0.4.15-dev-7942-gd23573b
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{
52
53 this->lines[0][0] = this->lines[1][0] = this->lines[2][0] = UNICODE_NULL;
54 this->cancelMsg[0] = this->title[0] = UNICODE_NULL;
55
56 this->clockHand = -1;
57 this->progressClock[29].ullMark = 0ull;
58 this->dwStartTime = GetTickCount();
59
61}
62
64{
65 if (this->hwnd)
66 this->end_dialog();
67 HeapFree(GetProcessHeap(), 0, this->lines[0]);
68 HeapFree(GetProcessHeap(), 0, this->lines[1]);
69 HeapFree(GetProcessHeap(), 0, this->lines[2]);
71 HeapFree(GetProcessHeap(), 0, this->title);
73}
74
75static void set_buffer(LPWSTR *buffer, LPCWSTR string)
76{
77 if (!string)
78 {
79 (*buffer)[0] = UNICODE_NULL;
80 return;
81 }
82
84}
85
87{
91};
92
93static void load_string(LPWSTR *buffer, HINSTANCE hInstance, UINT uiResourceId)
94{
95 WCHAR string[256];
96
97 LoadStringW(hInstance, uiResourceId, string, sizeof(string)/sizeof(string[0]));
98
99 set_buffer(buffer, string);
100}
101
103{
104 HWND hProgress = GetDlgItem(this->hwnd, IDC_PROGRESS_BAR);
105 SetWindowLongW(hProgress, GWL_STYLE,
107}
108
110{
111 WCHAR empty[] = {0};
112
114 SetWindowTextW(this->hwnd, this->title);
115
116 if (dwUpdate & UPDATE_LINE1)
117 SetDlgItemTextW(this->hwnd, IDC_TEXT_LINE, (this->isCancelled ? empty : this->lines[0]));
118 if (dwUpdate & UPDATE_LINE2)
119 SetDlgItemTextW(this->hwnd, IDC_TEXT_LINE+1, (this->isCancelled ? empty : this->lines[1]));
121 SetDlgItemTextW(this->hwnd, IDC_TEXT_LINE+2, (this->isCancelled ? this->cancelMsg : this->lines[2]));
122
124 {
127
128 /* progress bar requires 32-bit coordinates */
129 while (ullTotal >> 32)
130 {
131 ullTotal >>= 1;
132 ullCompleted >>= 1;
133 }
134
137 }
138}
139
141{
142 SendMessageW(this->hwnd, WM_DLG_DESTROY, 0, 0);
143 /* native doesn't re-enable the window? */
144 if (this->hwndDisabledParent)
146 this->hwnd = NULL;
147}
148
150{
152
153 switch (msg)
154 {
155 case WM_INITDIALOG:
156 {
157 struct create_params *params = (struct create_params *)lParam;
158
159 /* Note: until we set the hEvent, the object is protected by
160 * the critical section held by StartProgress */
162 This = params->This;
163 This->hwnd = hwnd;
164
165 if (This->dwFlags & PROGDLG_NOPROGRESSBAR)
167 if (This->dwFlags & PROGDLG_NOCANCEL)
169 if (This->dwFlags & PROGDLG_MARQUEEPROGRESS)
170 This->set_progress_marquee();
171 if (This->dwFlags & PROGDLG_NOMINIMIZE)
173
174 This->update_dialog(0xffffffff);
175 This->dwUpdate = 0;
176 This->isCancelled = FALSE;
177
178 SetTimer(hwnd, ID_3SECONDS, 3 * 1000, NULL);
179
180 SetEvent(params->hEvent);
181 return TRUE;
182 }
183
184 case WM_DLG_UPDATE:
186 This->update_dialog(This->dwUpdate);
187 This->dwUpdate = 0;
189 return TRUE;
190
191 case WM_DLG_DESTROY:
193 PostThreadMessageW(GetCurrentThreadId(), WM_NULL, 0, 0); /* wake up the GetMessage */
195
196 return TRUE;
197
198 case WM_CLOSE:
199 case WM_COMMAND:
200 if (msg == WM_CLOSE || wParam == IDCANCEL)
201 {
203 This->isCancelled = TRUE;
204
205 if (!This->cancelMsg[0]) {
206 load_string(&This->cancelMsg, _AtlBaseModule.GetResourceInstance(), IDS_CANCELLING);
207 }
208
209 This->set_progress_marquee();
213 }
214 return TRUE;
215
216 case WM_TIMER:
218 if (This->progressClock[29].ullMark != 0ull) {
219 // We have enough info to take a guess
220 ULONGLONG sizeDiff = This->progressClock[This->clockHand].ullMark -
221 This->progressClock[(This->clockHand + 29) % 30].ullMark;
222 DWORD timeDiff = This->progressClock[This->clockHand].dwTime -
223 This->progressClock[(This->clockHand + 29) % 30].dwTime;
224 DWORD runDiff = This->progressClock[This->clockHand].dwTime -
225 This->dwStartTime;
226 ULONGLONG sizeLeft = This->ullTotal - This->progressClock[This->clockHand].ullMark;
227
228 // A guess for time remaining based on the recent slope.
229 DWORD timeLeftD = (DWORD) timeDiff * ((double) sizeLeft) / ((double) sizeDiff);
230 // A guess for time remaining based on the start time and current position
231 DWORD timeLeftI = (DWORD) runDiff * ((double) sizeLeft) / ((double) This->progressClock[This->clockHand].ullMark);
232
233 StrFromTimeIntervalW(This->lines[2], 128, timeLeftD * 0.3 + timeLeftI * 0.7 , 2);
234 This->update_dialog( UPDATE_LINE1 << 2 );
235 }
237
238 return TRUE;
239 }
240 return FALSE;
241}
242
243static DWORD WINAPI dialog_thread(LPVOID lpParameter)
244{
245 /* Note: until we set the hEvent in WM_INITDIALOG, the ProgressDialog object
246 * is protected by the critical section held by StartProgress */
247 struct create_params *params = (struct create_params *) lpParameter;
248 HWND hwnd;
249 MSG msg;
250
251 hwnd = CreateDialogParamW(_AtlBaseModule.GetResourceInstance(),
253 params->hwndParent,
255 (LPARAM)params);
256
257 while (GetMessageW(&msg, NULL, 0, 0) > 0)
258 {
259 if (!IsWindow(hwnd))
260 break;
262 {
265 }
266 }
267
268 return 0;
269}
270
272{
273 static const INITCOMMONCONTROLSEX init = { sizeof(init), ICC_ANIMATE_CLASS };
274
275 struct create_params params;
277
278 // TRACE("(%p, %p, %x, %p)\n", this, punkEnableModeless, dwFlags, reserved);
279 if (punkEnableModeless || reserved)
280 FIXME("Reserved parameters not null (%p, %p)\n", punkEnableModeless, reserved);
282 FIXME("Flags PROGDLG_AUTOTIME not supported\n");
284 FIXME("Flags PROGDLG_NOTIME not supported\n");
285
287
288 EnterCriticalSection(&this->cs);
289
290 if (this->hwnd)
291 {
292 LeaveCriticalSection(&this->cs);
293 return S_OK; /* as on XP */
294 }
295 this->dwFlags = dwFlags;
296 params.This = this;
297 params.hwndParent = hwndParent;
298 params.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
299
302 CloseHandle(params.hEvent);
304
305 this->hwndDisabledParent = NULL;
306 if (hwndParent && (dwFlags & PROGDLG_MODAL))
307 {
308 HWND hwndDisable = GetAncestor(hwndParent, GA_ROOT);
309 if (EnableWindow(hwndDisable, FALSE))
310 this->hwndDisabledParent = hwndDisable;
311 }
312
313 LeaveCriticalSection(&this->cs);
314
315 return S_OK;
316}
317
319{
320 EnterCriticalSection(&this->cs);
321 if (this->hwnd)
322 this->end_dialog();
323 LeaveCriticalSection(&this->cs);
324
325 return S_OK;
326}
327
329{
330 HWND hwnd;
331
332 EnterCriticalSection(&this->cs);
333 set_buffer(&this->title, pwzTitle);
334 this->dwUpdate |= UPDATE_TITLE;
335 hwnd = this->hwnd;
336 LeaveCriticalSection(&this->cs);
337
338 if (hwnd)
340
341 return S_OK;
342}
343
345{
346 HWND hAnimation = GetDlgItem(this->hwnd, IDD_PROGRESS_DLG);
347 SetWindowLongW(hAnimation, GWL_STYLE,
349
350 if(!Animate_OpenEx(hAnimation,hInstance,MAKEINTRESOURCEW(uiResourceId)))
351 return S_FALSE;
352
353 return S_OK;
354}
355
356BOOL WINAPI CProgressDialog::HasUserCancelled()
357{
358 return this->isCancelled;
359}
360
362{
363 HWND hwnd;
364
365 EnterCriticalSection(&this->cs);
366 this->ullTotal = ullTotal;
367 this->ullCompleted = ullCompleted;
368
369 if (GetTickCount() - this->progressClock[(this->clockHand + 29) % 30].dwTime > 20) {
370 this->clockHand = (this->clockHand + 1) % 30;
373 }
374
375 this->dwUpdate |= UPDATE_PROGRESS;
376 hwnd = this->hwnd;
377 LeaveCriticalSection(&this->cs);
378
379 if (hwnd)
381
382 return S_OK; /* Windows sometimes returns S_FALSE */
383}
384
386{
387 return this->SetProgress64(dwCompleted, dwTotal);
388}
389
391{
392 HWND hwnd;
393
394 if (reserved)
395 FIXME("reserved pointer not null (%p)\n", reserved);
396
397 dwLineNum--;
398 if (dwLineNum >= 3) /* Windows seems to do something like that */
399 dwLineNum = 0;
400
401 EnterCriticalSection(&this->cs);
402 set_buffer(&this->lines[dwLineNum], pwzLine);
403 this->dwUpdate |= UPDATE_LINE1 << dwLineNum;
404 hwnd = (this->isCancelled ? NULL : this->hwnd); /* no sense to send the message if window cancelled */
405 LeaveCriticalSection(&this->cs);
406
407 if (hwnd)
409
410 return S_OK;
411}
412
414{
415 HWND hwnd;
416
417 if (reserved)
418 FIXME("reserved pointer not null (%p)\n", reserved);
419
420 EnterCriticalSection(&this->cs);
421 set_buffer(&this->cancelMsg, pwzMsg);
423 hwnd = (this->isCancelled ? this->hwnd : NULL); /* no sense to send the message if window not cancelled */
424 LeaveCriticalSection(&this->cs);
425
426 if (hwnd)
428
429 return S_OK;
430}
431
433{
434 if (reserved)
435 FIXME("Reserved field not NULL but %p\n", reserved);
436
437 return S_OK;
438}
439
441{
442 EnterCriticalSection(&this->cs);
443 *phwnd = this->hwnd;
444 LeaveCriticalSection(&this->cs);
445 return S_OK;
446}
447
449{
450 return E_NOTIMPL;
451}
#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: debug.h:111
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:893
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:135
#define IDC_TEXT_LINE
Definition: resource.h:139
#define IDD_PROGRESS_DLG
Definition: resource.h:140
#define IDC_PROGRESS_BAR
Definition: resource.h:138
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:2147
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:2188
#define Animate_OpenEx(hwnd, hInst, szName)
Definition: commctrl.h:4165
#define ICC_ANIMATE_CLASS
Definition: commctrl.h:65
#define PBS_MARQUEE
Definition: commctrl.h:2198
#define PBM_SETPOS
Definition: commctrl.h:2184
#define ACS_TRANSPARENT
Definition: commctrl.h:4147
#define ACS_AUTOPLAY
Definition: commctrl.h:4148
#define ACS_CENTER
Definition: commctrl.h:4146
#define PROGDLG_NOPROGRESSBAR
Definition: shlobj.h:962
#define PROGDLG_NOTIME
Definition: shlobj.h:960
#define PROGDLG_NOCANCEL
Definition: shlobj.h:964
#define PROGDLG_MARQUEEPROGRESS
Definition: shlobj.h:963
#define PROGDLG_AUTOTIME
Definition: shlobj.h:959
#define PROGDLG_NOMINIMIZE
Definition: shlobj.h:961
#define PROGDLG_MODAL
Definition: shlobj.h:958
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:768
#define WM_CLOSE
Definition: winuser.h:1621
#define DWLP_USER
Definition: winuser.h:872
#define GetWindowLongPtrW
Definition: winuser.h:4829
#define GA_ROOT
Definition: winuser.h:2789
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:831
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:1740
BOOL WINAPI SetDlgItemTextW(_In_ HWND, _In_ int, _In_ LPCWSTR)
#define WM_INITDIALOG
Definition: winuser.h:1739
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:1742
#define WM_NULL
Definition: winuser.h:1607
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:5346
#define GWL_STYLE
Definition: winuser.h:852
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