Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/browseui/progressdlg.c
5968 views
1
/*
2
* Progress dialog
3
*
4
* Copyright 2007 Mikolaj Zalewski
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library 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 GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#include <stdarg.h>
22
23
#define COBJMACROS
24
25
#include "wine/debug.h"
26
#include "windef.h"
27
#include "winbase.h"
28
#include "winreg.h"
29
#include "winuser.h"
30
#include "shlwapi.h"
31
#include "winerror.h"
32
#include "objbase.h"
33
34
#include "shlguid.h"
35
#include "shlobj.h"
36
37
#include "browseui.h"
38
#include "resids.h"
39
40
WINE_DEFAULT_DEBUG_CHANNEL(browseui);
41
42
#define CANCEL_MSG_LINE 2
43
44
/* Note: to avoid a deadlock we don't want to send messages to the dialog
45
* with the critical section held. Instead we only mark what fields should be
46
* updated and the dialog proc does the update */
47
#define UPDATE_PROGRESS 0x1
48
#define UPDATE_TITLE 0x2
49
#define UPDATE_LINE1 0x4
50
#define UPDATE_LINE2 (UPDATE_LINE1<<1)
51
#define UPDATE_LINE3 (UPDATE_LINE2<<2)
52
53
54
#define WM_DLG_UPDATE (WM_APP+1) /* set to the dialog when it should update */
55
#define WM_DLG_DESTROY (WM_APP+2) /* DestroyWindow must be called from the owning thread */
56
57
typedef struct tagProgressDialog {
58
IProgressDialog IProgressDialog_iface;
59
IOleWindow IOleWindow_iface;
60
LONG refCount;
61
CRITICAL_SECTION cs;
62
HWND hwnd;
63
DWORD dwFlags;
64
DWORD dwUpdate;
65
LPWSTR lines[3];
66
LPWSTR cancelMsg;
67
LPWSTR title;
68
BOOL isCancelled;
69
ULONGLONG ullCompleted;
70
ULONGLONG ullTotal;
71
HWND hwndDisabledParent; /* For modal dialog: the parent that need to be re-enabled when the dialog ends */
72
ULONGLONG startTime;
73
LPWSTR remainingMsg[2];
74
LPWSTR timeMsg[3];
75
} ProgressDialog;
76
77
static inline ProgressDialog *impl_from_IProgressDialog(IProgressDialog *iface)
78
{
79
return CONTAINING_RECORD(iface, ProgressDialog, IProgressDialog_iface);
80
}
81
82
static inline ProgressDialog *impl_from_IOleWindow(IOleWindow *iface)
83
{
84
return CONTAINING_RECORD(iface, ProgressDialog, IOleWindow_iface);
85
}
86
87
static void set_buffer(LPWSTR *buffer, LPCWSTR string)
88
{
89
free(*buffer);
90
*buffer = wcsdup(string ? string : L"");
91
}
92
93
struct create_params
94
{
95
ProgressDialog *This;
96
HANDLE hEvent;
97
HWND hwndParent;
98
};
99
100
static LPWSTR load_string(HINSTANCE hInstance, UINT uiResourceId)
101
{
102
WCHAR string[256];
103
LoadStringW(hInstance, uiResourceId, string, ARRAY_SIZE(string));
104
return wcsdup(string);
105
}
106
107
static void set_progress_marquee(ProgressDialog *This)
108
{
109
HWND hProgress = GetDlgItem(This->hwnd, IDC_PROGRESS_BAR);
110
SetWindowLongW(hProgress, GWL_STYLE,
111
GetWindowLongW(hProgress, GWL_STYLE)|PBS_MARQUEE);
112
}
113
114
static void update_dialog(ProgressDialog *This, DWORD dwUpdate)
115
{
116
if (dwUpdate & UPDATE_TITLE)
117
SetWindowTextW(This->hwnd, This->title);
118
119
if (dwUpdate & UPDATE_LINE1)
120
SetDlgItemTextW(This->hwnd, IDC_TEXT_LINE, (This->isCancelled ? L"" : This->lines[0]));
121
if (dwUpdate & UPDATE_LINE2)
122
SetDlgItemTextW(This->hwnd, IDC_TEXT_LINE+1, (This->isCancelled ? L"" : This->lines[1]));
123
if (dwUpdate & UPDATE_LINE3)
124
SetDlgItemTextW(This->hwnd, IDC_TEXT_LINE+2, (This->isCancelled ? This->cancelMsg : This->lines[2]));
125
126
if (dwUpdate & UPDATE_PROGRESS)
127
{
128
ULONGLONG ullTotal = This->ullTotal;
129
ULONGLONG ullCompleted = This->ullCompleted;
130
131
/* progress bar requires 32-bit coordinates */
132
while (ullTotal >> 32)
133
{
134
ullTotal >>= 1;
135
ullCompleted >>= 1;
136
}
137
138
SendDlgItemMessageW(This->hwnd, IDC_PROGRESS_BAR, PBM_SETRANGE32, 0, (DWORD)ullTotal);
139
SendDlgItemMessageW(This->hwnd, IDC_PROGRESS_BAR, PBM_SETPOS, (DWORD)ullCompleted, 0);
140
}
141
}
142
143
static void load_time_strings(ProgressDialog *This)
144
{
145
int i;
146
147
for (i = 0; i < 2; i++)
148
{
149
if (!This->remainingMsg[i])
150
This->remainingMsg[i] = load_string(BROWSEUI_hinstance, IDS_REMAINING1 + i);
151
}
152
for (i = 0; i < 3; i++)
153
{
154
if (!This->timeMsg[i])
155
This->timeMsg[i] = load_string(BROWSEUI_hinstance, IDS_SECONDS + i);
156
}
157
}
158
159
static void end_dialog(ProgressDialog *This)
160
{
161
SendMessageW(This->hwnd, WM_DLG_DESTROY, 0, 0);
162
/* native doesn't re-enable the window? */
163
if (This->hwndDisabledParent)
164
EnableWindow(This->hwndDisabledParent, TRUE);
165
This->hwnd = NULL;
166
}
167
168
static INT_PTR CALLBACK dialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
169
{
170
ProgressDialog *This = (ProgressDialog *)GetWindowLongPtrW(hwnd, DWLP_USER);
171
172
switch (msg)
173
{
174
case WM_INITDIALOG:
175
{
176
struct create_params *params = (struct create_params *)lParam;
177
178
/* Note: until we set the hEvent, the object is protected by
179
* the critical section held by StartProgress */
180
SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR)params->This);
181
This = params->This;
182
This->hwnd = hwnd;
183
184
if (This->dwFlags & PROGDLG_NOPROGRESSBAR)
185
ShowWindow(GetDlgItem(hwnd, IDC_PROGRESS_BAR), SW_HIDE);
186
if (This->dwFlags & PROGDLG_NOCANCEL)
187
ShowWindow(GetDlgItem(hwnd, IDCANCEL), SW_HIDE);
188
if (This->dwFlags & PROGDLG_MARQUEEPROGRESS)
189
set_progress_marquee(This);
190
if (This->dwFlags & PROGDLG_NOMINIMIZE)
191
SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE) & (~WS_MINIMIZEBOX));
192
193
update_dialog(This, 0xffffffff);
194
This->dwUpdate = 0;
195
This->isCancelled = FALSE;
196
SetEvent(params->hEvent);
197
return TRUE;
198
}
199
200
case WM_DLG_UPDATE:
201
EnterCriticalSection(&This->cs);
202
update_dialog(This, This->dwUpdate);
203
This->dwUpdate = 0;
204
LeaveCriticalSection(&This->cs);
205
return TRUE;
206
207
case WM_DLG_DESTROY:
208
DestroyWindow(hwnd);
209
PostThreadMessageW(GetCurrentThreadId(), WM_NULL, 0, 0); /* wake up the GetMessage */
210
return TRUE;
211
212
case WM_CLOSE:
213
case WM_COMMAND:
214
if (msg == WM_CLOSE || wParam == IDCANCEL)
215
{
216
EnterCriticalSection(&This->cs);
217
This->isCancelled = TRUE;
218
219
if (!This->cancelMsg)
220
This->cancelMsg = load_string(BROWSEUI_hinstance, IDS_CANCELLING);
221
222
set_progress_marquee(This);
223
EnableWindow(GetDlgItem(This->hwnd, IDCANCEL), FALSE);
224
update_dialog(This, UPDATE_LINE1|UPDATE_LINE2|UPDATE_LINE3);
225
LeaveCriticalSection(&This->cs);
226
}
227
return TRUE;
228
}
229
return FALSE;
230
}
231
232
static DWORD WINAPI dialog_thread(LPVOID lpParameter)
233
{
234
/* Note: until we set the hEvent in WM_INITDIALOG, the ProgressDialog object
235
* is protected by the critical section held by StartProgress */
236
struct create_params *params = lpParameter;
237
ProgressDialog *This = params->This;
238
HWND hwnd;
239
MSG msg;
240
241
hwnd = CreateDialogParamW(BROWSEUI_hinstance, MAKEINTRESOURCEW(IDD_PROGRESS_DLG),
242
params->hwndParent, dialog_proc, (LPARAM)params);
243
244
while (GetMessageW(&msg, NULL, 0, 0) > 0)
245
{
246
if (!IsWindow(hwnd))
247
break;
248
if(!IsDialogMessageW(hwnd, &msg))
249
{
250
TranslateMessage(&msg);
251
DispatchMessageW(&msg);
252
}
253
}
254
255
IProgressDialog_Release(&This->IProgressDialog_iface);
256
return 0;
257
}
258
259
static void ProgressDialog_Destructor(ProgressDialog *This)
260
{
261
int i;
262
TRACE("destroying %p\n", This);
263
if (This->hwnd)
264
end_dialog(This);
265
for (i = 0; i < ARRAY_SIZE(This->lines); i++)
266
free(This->lines[i]);
267
free(This->cancelMsg);
268
free(This->title);
269
for (i = 0; i < ARRAY_SIZE(This->remainingMsg); i++)
270
free(This->remainingMsg[i]);
271
for (i = 0; i < ARRAY_SIZE(This->timeMsg); i++)
272
free(This->timeMsg[i]);
273
This->cs.DebugInfo->Spare[0] = 0;
274
DeleteCriticalSection(&This->cs);
275
free(This);
276
InterlockedDecrement(&BROWSEUI_refCount);
277
}
278
279
static HRESULT WINAPI ProgressDialog_QueryInterface(IProgressDialog *iface, REFIID iid, LPVOID *ppvOut)
280
{
281
ProgressDialog *This = impl_from_IProgressDialog(iface);
282
283
TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), ppvOut);
284
if (!ppvOut)
285
return E_POINTER;
286
287
*ppvOut = NULL;
288
if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IProgressDialog))
289
{
290
*ppvOut = iface;
291
}
292
else if (IsEqualIID(iid, &IID_IOleWindow))
293
{
294
*ppvOut = &This->IOleWindow_iface;
295
}
296
297
if (*ppvOut)
298
{
299
IProgressDialog_AddRef(iface);
300
return S_OK;
301
}
302
303
WARN("unsupported interface: %s\n", debugstr_guid(iid));
304
return E_NOINTERFACE;
305
}
306
307
static ULONG WINAPI ProgressDialog_AddRef(IProgressDialog *iface)
308
{
309
ProgressDialog *This = impl_from_IProgressDialog(iface);
310
return InterlockedIncrement(&This->refCount);
311
}
312
313
static ULONG WINAPI ProgressDialog_Release(IProgressDialog *iface)
314
{
315
ProgressDialog *This = impl_from_IProgressDialog(iface);
316
ULONG ret;
317
318
ret = InterlockedDecrement(&This->refCount);
319
if (ret == 0)
320
ProgressDialog_Destructor(This);
321
return ret;
322
}
323
324
static HRESULT WINAPI ProgressDialog_StartProgressDialog(IProgressDialog *iface, HWND hwndParent, IUnknown *punkEnableModeless, DWORD dwFlags, LPCVOID reserved)
325
{
326
static const INITCOMMONCONTROLSEX init = { sizeof(init), ICC_ANIMATE_CLASS };
327
ProgressDialog *This = impl_from_IProgressDialog(iface);
328
struct create_params params;
329
HANDLE hThread;
330
331
TRACE("(%p, %p, %lx, %p)\n", iface, punkEnableModeless, dwFlags, reserved);
332
if (punkEnableModeless || reserved)
333
FIXME("Reserved parameters not null (%p, %p)\n", punkEnableModeless, reserved);
334
if (dwFlags & PROGDLG_NOTIME)
335
FIXME("Flags PROGDLG_NOTIME not supported\n");
336
337
InitCommonControlsEx( &init );
338
339
EnterCriticalSection(&This->cs);
340
341
if (This->hwnd)
342
{
343
LeaveCriticalSection(&This->cs);
344
return S_OK; /* as on XP */
345
}
346
This->dwFlags = dwFlags;
347
348
params.This = This;
349
params.hwndParent = hwndParent;
350
params.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
351
352
/* thread holds one reference to ensure clean shutdown */
353
IProgressDialog_AddRef(&This->IProgressDialog_iface);
354
355
hThread = CreateThread(NULL, 0, dialog_thread, &params, 0, NULL);
356
WaitForSingleObject(params.hEvent, INFINITE);
357
CloseHandle(params.hEvent);
358
CloseHandle(hThread);
359
360
This->hwndDisabledParent = NULL;
361
if (hwndParent && (dwFlags & PROGDLG_MODAL))
362
{
363
HWND hwndDisable = GetAncestor(hwndParent, GA_ROOT);
364
if (EnableWindow(hwndDisable, FALSE))
365
This->hwndDisabledParent = hwndDisable;
366
}
367
368
if (dwFlags & PROGDLG_AUTOTIME)
369
load_time_strings(This);
370
371
This->startTime = GetTickCount64();
372
LeaveCriticalSection(&This->cs);
373
374
return S_OK;
375
}
376
377
static HRESULT WINAPI ProgressDialog_StopProgressDialog(IProgressDialog *iface)
378
{
379
ProgressDialog *This = impl_from_IProgressDialog(iface);
380
381
EnterCriticalSection(&This->cs);
382
if (This->hwnd)
383
end_dialog(This);
384
LeaveCriticalSection(&This->cs);
385
386
return S_OK;
387
}
388
389
static HRESULT WINAPI ProgressDialog_SetTitle(IProgressDialog *iface, LPCWSTR pwzTitle)
390
{
391
ProgressDialog *This = impl_from_IProgressDialog(iface);
392
HWND hwnd;
393
394
TRACE("(%p, %s)\n", This, wine_dbgstr_w(pwzTitle));
395
396
EnterCriticalSection(&This->cs);
397
set_buffer(&This->title, pwzTitle);
398
This->dwUpdate |= UPDATE_TITLE;
399
hwnd = This->hwnd;
400
LeaveCriticalSection(&This->cs);
401
402
if (hwnd)
403
SendMessageW(hwnd, WM_DLG_UPDATE, 0, 0);
404
405
return S_OK;
406
}
407
408
static HRESULT WINAPI ProgressDialog_SetAnimation(IProgressDialog *iface, HINSTANCE hInstance, UINT uiResourceId)
409
{
410
ProgressDialog *This = impl_from_IProgressDialog(iface);
411
412
TRACE("(%p, %p, %u)\n", iface, hInstance, uiResourceId);
413
414
if (IS_INTRESOURCE(uiResourceId))
415
{
416
if (!SendDlgItemMessageW(This->hwnd, IDC_ANIMATION, ACM_OPENW, (WPARAM)hInstance, uiResourceId))
417
WARN("Failed to load animation\n");
418
}
419
420
return S_OK;
421
}
422
423
static BOOL WINAPI ProgressDialog_HasUserCancelled(IProgressDialog *iface)
424
{
425
ProgressDialog *This = impl_from_IProgressDialog(iface);
426
return This->isCancelled;
427
}
428
429
static void update_time_remaining(ProgressDialog *This, ULONGLONG ullCompleted, ULONGLONG ullTotal)
430
{
431
unsigned int remaining, remainder = 0;
432
ULONGLONG elapsed;
433
WCHAR line[128];
434
int i;
435
DWORD_PTR args[4];
436
437
if (!This->startTime || !ullCompleted || !ullTotal)
438
return;
439
440
elapsed = GetTickCount64() - This->startTime;
441
remaining = (elapsed * ullTotal / ullCompleted - elapsed) / 1000;
442
443
for (i = 0; remaining >= 60 && i < 2; i++)
444
{
445
remainder = remaining % 60;
446
remaining /= 60;
447
}
448
449
args[0] = remaining;
450
args[1] = (DWORD_PTR)This->timeMsg[i];
451
args[2] = remainder;
452
args[3] = (DWORD_PTR)This->timeMsg[i-1];
453
454
if (i > 0 && remaining < 2 && remainder != 0)
455
FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
456
This->remainingMsg[1], 0, 0, line, ARRAY_SIZE(line), (va_list *)args);
457
else
458
FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
459
This->remainingMsg[0], 0, 0, line, ARRAY_SIZE(line), (va_list *)args);
460
461
set_buffer(&This->lines[2], line);
462
This->dwUpdate |= UPDATE_LINE3;
463
}
464
465
static HRESULT WINAPI ProgressDialog_SetProgress64(IProgressDialog *iface, ULONGLONG ullCompleted, ULONGLONG ullTotal)
466
{
467
ProgressDialog *This = impl_from_IProgressDialog(iface);
468
HWND hwnd;
469
470
TRACE("(%p, 0x%s, 0x%s)\n", This, wine_dbgstr_longlong(ullCompleted), wine_dbgstr_longlong(ullTotal));
471
472
EnterCriticalSection(&This->cs);
473
This->ullTotal = ullTotal;
474
This->ullCompleted = ullCompleted;
475
This->dwUpdate |= UPDATE_PROGRESS;
476
hwnd = This->hwnd;
477
if (This->dwFlags & PROGDLG_AUTOTIME)
478
update_time_remaining(This, ullCompleted, ullTotal);
479
LeaveCriticalSection(&This->cs);
480
481
if (hwnd)
482
SendMessageW(hwnd, WM_DLG_UPDATE, 0, 0);
483
484
return S_OK; /* Windows sometimes returns S_FALSE */
485
}
486
487
static HRESULT WINAPI ProgressDialog_SetProgress(IProgressDialog *iface, DWORD dwCompleted, DWORD dwTotal)
488
{
489
return IProgressDialog_SetProgress64(iface, dwCompleted, dwTotal);
490
}
491
492
static HRESULT WINAPI ProgressDialog_SetLine(IProgressDialog *iface, DWORD dwLineNum, LPCWSTR pwzLine, BOOL bPath, LPCVOID reserved)
493
{
494
ProgressDialog *This = impl_from_IProgressDialog(iface);
495
HWND hwnd;
496
497
TRACE("(%p, %ld, %s, %d)\n", This, dwLineNum, wine_dbgstr_w(pwzLine), bPath);
498
499
if (reserved)
500
FIXME("reserved pointer not null (%p)\n", reserved);
501
502
dwLineNum--;
503
if (dwLineNum >= 3) /* Windows seems to do something like that */
504
dwLineNum = 0;
505
506
EnterCriticalSection(&This->cs);
507
set_buffer(&This->lines[dwLineNum], pwzLine);
508
This->dwUpdate |= UPDATE_LINE1 << dwLineNum;
509
hwnd = (This->isCancelled ? NULL : This->hwnd); /* no sense to send the message if window cancelled */
510
LeaveCriticalSection(&This->cs);
511
512
if (hwnd)
513
SendMessageW(hwnd, WM_DLG_UPDATE, 0, 0);
514
515
return S_OK;
516
}
517
518
static HRESULT WINAPI ProgressDialog_SetCancelMsg(IProgressDialog *iface, LPCWSTR pwzMsg, LPCVOID reserved)
519
{
520
ProgressDialog *This = impl_from_IProgressDialog(iface);
521
HWND hwnd;
522
523
TRACE("(%p, %s)\n", This, wine_dbgstr_w(pwzMsg));
524
525
if (reserved)
526
FIXME("reserved pointer not null (%p)\n", reserved);
527
528
EnterCriticalSection(&This->cs);
529
set_buffer(&This->cancelMsg, pwzMsg);
530
This->dwUpdate |= UPDATE_LINE1 << CANCEL_MSG_LINE;
531
hwnd = (This->isCancelled ? This->hwnd : NULL); /* no sense to send the message if window not cancelled */
532
LeaveCriticalSection(&This->cs);
533
534
if (hwnd)
535
SendMessageW(hwnd, WM_DLG_UPDATE, 0, 0);
536
537
return S_OK;
538
}
539
540
static HRESULT WINAPI ProgressDialog_Timer(IProgressDialog *iface, DWORD dwTimerAction, LPCVOID reserved)
541
{
542
ProgressDialog *This = impl_from_IProgressDialog(iface);
543
544
FIXME("(%p, %ld, %p) - stub\n", This, dwTimerAction, reserved);
545
546
if (reserved)
547
FIXME("Reserved field not NULL but %p\n", reserved);
548
549
return S_OK;
550
}
551
552
static const IProgressDialogVtbl ProgressDialogVtbl =
553
{
554
ProgressDialog_QueryInterface,
555
ProgressDialog_AddRef,
556
ProgressDialog_Release,
557
558
ProgressDialog_StartProgressDialog,
559
ProgressDialog_StopProgressDialog,
560
ProgressDialog_SetTitle,
561
ProgressDialog_SetAnimation,
562
ProgressDialog_HasUserCancelled,
563
ProgressDialog_SetProgress,
564
ProgressDialog_SetProgress64,
565
ProgressDialog_SetLine,
566
ProgressDialog_SetCancelMsg,
567
ProgressDialog_Timer
568
};
569
570
static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID iid, LPVOID *ppvOut)
571
{
572
ProgressDialog *This = impl_from_IOleWindow(iface);
573
return ProgressDialog_QueryInterface(&This->IProgressDialog_iface, iid, ppvOut);
574
}
575
576
static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
577
{
578
ProgressDialog *This = impl_from_IOleWindow(iface);
579
return ProgressDialog_AddRef(&This->IProgressDialog_iface);
580
}
581
582
static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
583
{
584
ProgressDialog *This = impl_from_IOleWindow(iface);
585
return ProgressDialog_Release(&This->IProgressDialog_iface);
586
}
587
588
static HRESULT WINAPI OleWindow_GetWindow(IOleWindow* iface, HWND* phwnd)
589
{
590
ProgressDialog *This = impl_from_IOleWindow(iface);
591
592
TRACE("(%p, %p)\n", This, phwnd);
593
EnterCriticalSection(&This->cs);
594
*phwnd = This->hwnd;
595
LeaveCriticalSection(&This->cs);
596
return S_OK;
597
}
598
599
static HRESULT WINAPI OleWindow_ContextSensitiveHelp(IOleWindow* iface, BOOL fEnterMode)
600
{
601
ProgressDialog *This = impl_from_IOleWindow(iface);
602
603
FIXME("(%p, %d): stub\n", This, fEnterMode);
604
return E_NOTIMPL;
605
}
606
607
static const IOleWindowVtbl OleWindowVtbl =
608
{
609
OleWindow_QueryInterface,
610
OleWindow_AddRef,
611
OleWindow_Release,
612
OleWindow_GetWindow,
613
OleWindow_ContextSensitiveHelp
614
};
615
616
617
HRESULT ProgressDialog_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
618
{
619
ProgressDialog *This;
620
if (pUnkOuter)
621
return CLASS_E_NOAGGREGATION;
622
623
if (!(This = calloc(1, sizeof(*This))))
624
return E_OUTOFMEMORY;
625
626
This->IProgressDialog_iface.lpVtbl = &ProgressDialogVtbl;
627
This->IOleWindow_iface.lpVtbl = &OleWindowVtbl;
628
This->refCount = 1;
629
InitializeCriticalSectionEx(&This->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
630
This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ProgressDialog.cs");
631
632
TRACE("returning %p\n", This);
633
*ppOut = (IUnknown *)&This->IProgressDialog_iface;
634
InterlockedIncrement(&BROWSEUI_refCount);
635
return S_OK;
636
}
637
638