1 // ProgressDialog2.cpp
2
3 #include "StdAfx.h"
4
5 #ifdef Z7_OLD_WIN_SDK
6 #include <ShlGuid.h>
7 #endif
8
9 #include "../../../Common/IntToString.h"
10 #include "../../../Common/StringConvert.h"
11
12 #include "../../../Windows/Clipboard.h"
13 #include "../../../Windows/ErrorMsg.h"
14
15 #include "../GUI/ExtractRes.h"
16
17 #include "LangUtils.h"
18
19 #include "DialogSize.h"
20 #include "ProgressDialog2.h"
21 #include "ProgressDialog2Res.h"
22
23 using namespace NWindows;
24
25 extern HINSTANCE g_hInstance;
26 extern bool g_DisableUserQuestions;
27
28 static const UINT_PTR kTimerID = 3;
29
30 static const UINT kCloseMessage = WM_APP + 1;
31 // we can't use WM_USER, since WM_USER can be used by standard Windows procedure for Dialog
32
33 static const UINT kTimerElapse =
34 #ifdef UNDER_CE
35 500
36 #else
37 200
38 #endif
39 ;
40
41 static const UINT kCreateDelay =
42 #ifdef UNDER_CE
43 2500
44 #else
45 500
46 #endif
47 ;
48
49 static const DWORD kPauseSleepTime = 100;
50
51 #ifdef Z7_LANG
52
53 static const UInt32 kLangIDs[] =
54 {
55 IDT_PROGRESS_ELAPSED,
56 IDT_PROGRESS_REMAINING,
57 IDT_PROGRESS_TOTAL,
58 IDT_PROGRESS_SPEED,
59 IDT_PROGRESS_PROCESSED,
60 IDT_PROGRESS_RATIO,
61 IDT_PROGRESS_ERRORS,
62 IDB_PROGRESS_BACKGROUND,
63 IDB_PAUSE
64 };
65
66 static const UInt32 kLangIDs_Colon[] =
67 {
68 IDT_PROGRESS_PACKED,
69 IDT_PROGRESS_FILES
70 };
71
72 #endif
73
74
75 #define UNDEFINED_VAL ((UInt64)(Int64)-1)
76 #define INIT_AS_UNDEFINED(v) v = UNDEFINED_VAL;
77 #define IS_UNDEFINED_VAL(v) ((v) == UNDEFINED_VAL)
78 #define IS_DEFINED_VAL(v) ((v) != UNDEFINED_VAL)
79
CProgressSync()80 CProgressSync::CProgressSync():
81 _stopped(false),
82 _paused(false),
83 _filesProgressMode(false),
84 _isDir(false),
85 _totalBytes(UNDEFINED_VAL), _completedBytes(0),
86 _totalFiles(UNDEFINED_VAL), _curFiles(0),
87 _inSize(UNDEFINED_VAL),
88 _outSize(UNDEFINED_VAL)
89 {}
90
91 #define CHECK_STOP if (_stopped) return E_ABORT; if (!_paused) return S_OK;
92 #define CRITICAL_LOCK NSynchronization::CCriticalSectionLock lock(_cs);
93
Get_Paused()94 bool CProgressSync::Get_Paused()
95 {
96 CRITICAL_LOCK
97 return _paused;
98 }
99
CheckStop()100 HRESULT CProgressSync::CheckStop()
101 {
102 for (;;)
103 {
104 {
105 CRITICAL_LOCK
106 CHECK_STOP
107 }
108 ::Sleep(kPauseSleepTime);
109 }
110 }
111
Clear_Stop_Status()112 void CProgressSync::Clear_Stop_Status()
113 {
114 CRITICAL_LOCK
115 if (_stopped)
116 _stopped = false;
117 }
118
ScanProgress(UInt64 numFiles,UInt64 totalSize,const FString & fileName,bool isDir)119 HRESULT CProgressSync::ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir)
120 {
121 {
122 CRITICAL_LOCK
123 _totalFiles = numFiles;
124 _totalBytes = totalSize;
125 _filePath = fs2us(fileName);
126 _isDir = isDir;
127 // _completedBytes = 0;
128 CHECK_STOP
129 }
130 return CheckStop();
131 }
132
Set_NumFilesTotal(UInt64 val)133 HRESULT CProgressSync::Set_NumFilesTotal(UInt64 val)
134 {
135 {
136 CRITICAL_LOCK
137 _totalFiles = val;
138 CHECK_STOP
139 }
140 return CheckStop();
141 }
142
Set_NumBytesTotal(UInt64 val)143 void CProgressSync::Set_NumBytesTotal(UInt64 val)
144 {
145 CRITICAL_LOCK
146 _totalBytes = val;
147 }
148
Set_NumFilesCur(UInt64 val)149 void CProgressSync::Set_NumFilesCur(UInt64 val)
150 {
151 CRITICAL_LOCK
152 _curFiles = val;
153 }
154
Set_NumBytesCur(const UInt64 * val)155 HRESULT CProgressSync::Set_NumBytesCur(const UInt64 *val)
156 {
157 {
158 CRITICAL_LOCK
159 if (val)
160 _completedBytes = *val;
161 CHECK_STOP
162 }
163 return CheckStop();
164 }
165
Set_NumBytesCur(UInt64 val)166 HRESULT CProgressSync::Set_NumBytesCur(UInt64 val)
167 {
168 {
169 CRITICAL_LOCK
170 _completedBytes = val;
171 CHECK_STOP
172 }
173 return CheckStop();
174 }
175
Set_Ratio(const UInt64 * inSize,const UInt64 * outSize)176 void CProgressSync::Set_Ratio(const UInt64 *inSize, const UInt64 *outSize)
177 {
178 CRITICAL_LOCK
179 if (inSize)
180 _inSize = *inSize;
181 if (outSize)
182 _outSize = *outSize;
183 }
184
Set_TitleFileName(const UString & fileName)185 void CProgressSync::Set_TitleFileName(const UString &fileName)
186 {
187 CRITICAL_LOCK
188 _titleFileName = fileName;
189 }
190
Set_Status(const UString & s)191 void CProgressSync::Set_Status(const UString &s)
192 {
193 CRITICAL_LOCK
194 _status = s;
195 }
196
Set_Status2(const UString & s,const wchar_t * path,bool isDir)197 HRESULT CProgressSync::Set_Status2(const UString &s, const wchar_t *path, bool isDir)
198 {
199 {
200 CRITICAL_LOCK
201 _status = s;
202 if (path)
203 _filePath = path;
204 else
205 _filePath.Empty();
206 _isDir = isDir;
207 }
208 return CheckStop();
209 }
210
Set_FilePath(const wchar_t * path,bool isDir)211 void CProgressSync::Set_FilePath(const wchar_t *path, bool isDir)
212 {
213 CRITICAL_LOCK
214 if (path)
215 _filePath = path;
216 else
217 _filePath.Empty();
218 _isDir = isDir;
219 }
220
221
AddError_Message(const wchar_t * message)222 void CProgressSync::AddError_Message(const wchar_t *message)
223 {
224 CRITICAL_LOCK
225 Messages.Add(message);
226 }
227
AddError_Message_Name(const wchar_t * message,const wchar_t * name)228 void CProgressSync::AddError_Message_Name(const wchar_t *message, const wchar_t *name)
229 {
230 UString s;
231 if (name && *name != 0)
232 s += name;
233 if (message && *message != 0)
234 {
235 if (!s.IsEmpty())
236 s.Add_LF();
237 s += message;
238 if (!s.IsEmpty() && s.Back() == L'\n')
239 s.DeleteBack();
240 }
241 AddError_Message(s);
242 }
243
AddError_Code_Name(HRESULT systemError,const wchar_t * name)244 void CProgressSync::AddError_Code_Name(HRESULT systemError, const wchar_t *name)
245 {
246 UString s = NError::MyFormatMessage(systemError);
247 if (systemError == 0)
248 s = "Error";
249 AddError_Message_Name(s, name);
250 }
251
CProgressDialog()252 CProgressDialog::CProgressDialog():
253 _isDir(false),
254 _wasCreated(false),
255 _needClose(false),
256 _errorsWereDisplayed(false),
257 _waitCloseByCancelButton(false),
258 _cancelWasPressed(false),
259 _inCancelMessageBox(false),
260 _externalCloseMessageWasReceived(false),
261 _background(false),
262 WaitMode(false),
263 MessagesDisplayed(false),
264 CompressingMode(true),
265 ShowCompressionInfo(true),
266 _numPostedMessages(0),
267 _numAutoSizeMessages(0),
268 _numMessages(0),
269 _timer(0),
270 IconID(-1),
271 MainWindow(NULL)
272 {
273
274 if (_dialogCreatedEvent.Create() != S_OK)
275 throw 1334987;
276 if (_createDialogEvent.Create() != S_OK)
277 throw 1334987;
278 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
279 CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void**)&_taskbarList);
280 if (_taskbarList)
281 _taskbarList->HrInit();
282 // #endif
283 }
284
285 #ifndef Z7_SFX
286
~CProgressDialog()287 CProgressDialog::~CProgressDialog()
288 {
289 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
290 SetTaskbarProgressState(TBPF_NOPROGRESS);
291 // #endif
292 AddToTitle(L"");
293 }
AddToTitle(LPCWSTR s)294 void CProgressDialog::AddToTitle(LPCWSTR s)
295 {
296 if (MainWindow)
297 {
298 CWindow window(MainWindow);
299 window.SetText((UString)s + MainTitle);
300 }
301 }
302
303 #endif
304
305
SetTaskbarProgressState()306 void CProgressDialog::SetTaskbarProgressState()
307 {
308 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
309 if (_taskbarList && _hwndForTaskbar)
310 {
311 TBPFLAG tbpFlags;
312 if (Sync.Get_Paused())
313 tbpFlags = TBPF_PAUSED;
314 else
315 tbpFlags = _errorsWereDisplayed ? TBPF_ERROR: TBPF_NORMAL;
316 SetTaskbarProgressState(tbpFlags);
317 }
318 // #endif
319 }
320
321 static const unsigned kTitleFileNameSizeLimit = 36;
322 static const unsigned kCurrentFileNameSizeLimit = 82;
323
ReduceString(UString & s,unsigned size)324 static void ReduceString(UString &s, unsigned size)
325 {
326 if (s.Len() <= size)
327 return;
328 s.Delete(size / 2, s.Len() - size);
329 s.Insert(size / 2, L" ... ");
330 }
331
EnableErrorsControls(bool enable)332 void CProgressDialog::EnableErrorsControls(bool enable)
333 {
334 ShowItem_Bool(IDT_PROGRESS_ERRORS, enable);
335 ShowItem_Bool(IDT_PROGRESS_ERRORS_VAL, enable);
336 ShowItem_Bool(IDL_PROGRESS_MESSAGES, enable);
337 }
338
OnInit()339 bool CProgressDialog::OnInit()
340 {
341 _hwndForTaskbar = MainWindow;
342 if (!_hwndForTaskbar)
343 _hwndForTaskbar = GetParent();
344 if (!_hwndForTaskbar)
345 _hwndForTaskbar = *this;
346
347 INIT_AS_UNDEFINED(_progressBar_Range)
348 INIT_AS_UNDEFINED(_progressBar_Pos)
349
350 INIT_AS_UNDEFINED(_prevPercentValue)
351 INIT_AS_UNDEFINED(_prevElapsedSec)
352 INIT_AS_UNDEFINED(_prevRemainingSec)
353
354 INIT_AS_UNDEFINED(_prevSpeed)
355 _prevSpeed_MoveBits = 0;
356
357 _prevTime = ::GetTickCount();
358 _elapsedTime = 0;
359
360 INIT_AS_UNDEFINED(_totalBytes_Prev)
361 INIT_AS_UNDEFINED(_processed_Prev)
362 INIT_AS_UNDEFINED(_packed_Prev)
363 INIT_AS_UNDEFINED(_ratio_Prev)
364
365 _filesStr_Prev.Empty();
366 _filesTotStr_Prev.Empty();
367
368 m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));
369 _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES));
370 _messageList.SetUnicodeFormat();
371 _messageList.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
372
373 _wasCreated = true;
374 _dialogCreatedEvent.Set();
375
376 #ifdef Z7_LANG
377 LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
378 LangSetDlgItems_Colon(*this, kLangIDs_Colon, Z7_ARRAY_SIZE(kLangIDs_Colon));
379 #endif
380
381 CWindow window(GetItem(IDB_PROGRESS_BACKGROUND));
382 window.GetText(_background_String);
383 _backgrounded_String = _background_String;
384 _backgrounded_String.RemoveChar(L'&');
385
386 window = GetItem(IDB_PAUSE);
387 window.GetText(_pause_String);
388
389 LangString(IDS_PROGRESS_FOREGROUND, _foreground_String);
390 LangString(IDS_CONTINUE, _continue_String);
391 LangString(IDS_PROGRESS_PAUSED, _paused_String);
392
393 SetText(_title);
394 SetPauseText();
395 SetPriorityText();
396
397 _messageList.InsertColumn(0, L"", 40);
398 _messageList.InsertColumn(1, L"", 460);
399 _messageList.SetColumnWidthAuto(0);
400 _messageList.SetColumnWidthAuto(1);
401
402 EnableErrorsControls(false);
403
404 GetItemSizes(IDCANCEL, _buttonSizeX, _buttonSizeY);
405 _numReduceSymbols = kCurrentFileNameSizeLimit;
406 NormalizeSize(true);
407
408 if (!ShowCompressionInfo)
409 {
410 HideItem(IDT_PROGRESS_PACKED);
411 HideItem(IDT_PROGRESS_PACKED_VAL);
412 HideItem(IDT_PROGRESS_RATIO);
413 HideItem(IDT_PROGRESS_RATIO_VAL);
414 }
415
416 if (IconID >= 0)
417 {
418 HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID));
419 // SetIcon(ICON_SMALL, icon);
420 SetIcon(ICON_BIG, icon);
421 }
422 _timer = SetTimer(kTimerID, kTimerElapse);
423 #ifdef UNDER_CE
424 Foreground();
425 #endif
426
427 CheckNeedClose();
428
429 SetTaskbarProgressState();
430
431 return CModalDialog::OnInit();
432 }
433
434 static const UINT kIDs[] =
435 {
436 IDT_PROGRESS_ELAPSED, IDT_PROGRESS_ELAPSED_VAL,
437 IDT_PROGRESS_REMAINING, IDT_PROGRESS_REMAINING_VAL,
438 IDT_PROGRESS_FILES, IDT_PROGRESS_FILES_VAL,
439 0, IDT_PROGRESS_FILES_TOTAL,
440 IDT_PROGRESS_ERRORS, IDT_PROGRESS_ERRORS_VAL,
441
442 IDT_PROGRESS_TOTAL, IDT_PROGRESS_TOTAL_VAL,
443 IDT_PROGRESS_SPEED, IDT_PROGRESS_SPEED_VAL,
444 IDT_PROGRESS_PROCESSED, IDT_PROGRESS_PROCESSED_VAL,
445 IDT_PROGRESS_PACKED, IDT_PROGRESS_PACKED_VAL,
446 IDT_PROGRESS_RATIO, IDT_PROGRESS_RATIO_VAL
447 };
448
OnSize(WPARAM,int xSize,int ySize)449 bool CProgressDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
450 {
451 int sY;
452 int sStep;
453 int mx, my;
454 {
455 RECT r;
456 GetClientRectOfItem(IDT_PROGRESS_ELAPSED, r);
457 mx = r.left;
458 my = r.top;
459 sY = RECT_SIZE_Y(r);
460 GetClientRectOfItem(IDT_PROGRESS_REMAINING, r);
461 sStep = r.top - my;
462 }
463
464 InvalidateRect(NULL);
465
466 const int xSizeClient = xSize - mx * 2;
467
468 {
469 unsigned i;
470 for (i = 800; i > 40; i = i * 9 / 10)
471 if (Units_To_Pixels_X((int)i) <= xSizeClient)
472 break;
473 _numReduceSymbols = i / 4;
474 }
475
476 int yPos = ySize - my - _buttonSizeY;
477
478 ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_STATUS), xSize - mx * 2);
479 ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_FILE_NAME), xSize - mx * 2);
480 ChangeSubWindowSizeX(GetItem(IDC_PROGRESS1), xSize - mx * 2);
481
482 int bSizeX = _buttonSizeX;
483 int mx2 = mx;
484 for (;; mx2--)
485 {
486 const int bSize2 = bSizeX * 3 + mx2 * 2;
487 if (bSize2 <= xSizeClient)
488 break;
489 if (mx2 < 5)
490 {
491 bSizeX = (xSizeClient - mx2 * 2) / 3;
492 break;
493 }
494 }
495 if (bSizeX < 2)
496 bSizeX = 2;
497
498 {
499 RECT r;
500 GetClientRectOfItem(IDL_PROGRESS_MESSAGES, r);
501 const int y = r.top;
502 int ySize2 = yPos - my - y;
503 const int kMinYSize = _buttonSizeY + _buttonSizeY * 3 / 4;
504 int xx = xSize - mx * 2;
505 if (ySize2 < kMinYSize)
506 {
507 ySize2 = kMinYSize;
508 if (xx > bSizeX * 2)
509 xx -= bSizeX;
510 }
511
512 _messageList.Move(mx, y, xx, ySize2);
513 }
514
515 {
516 int xPos = xSize - mx;
517 xPos -= bSizeX;
518 MoveItem(IDCANCEL, xPos, yPos, bSizeX, _buttonSizeY);
519 xPos -= (mx2 + bSizeX);
520 MoveItem(IDB_PAUSE, xPos, yPos, bSizeX, _buttonSizeY);
521 xPos -= (mx2 + bSizeX);
522 MoveItem(IDB_PROGRESS_BACKGROUND, xPos, yPos, bSizeX, _buttonSizeY);
523 }
524
525 int valueSize;
526 int labelSize;
527 int padSize;
528
529 labelSize = Units_To_Pixels_X(MY_PROGRESS_LABEL_UNITS_MIN);
530 valueSize = Units_To_Pixels_X(MY_PROGRESS_VAL_UNITS);
531 padSize = Units_To_Pixels_X(MY_PROGRESS_PAD_UNITS);
532 const int requiredSize = (labelSize + valueSize) * 2 + padSize;
533
534 int gSize;
535 {
536 if (requiredSize < xSizeClient)
537 {
538 const int incr = (xSizeClient - requiredSize) / 3;
539 labelSize += incr;
540 }
541 else
542 labelSize = (xSizeClient - valueSize * 2 - padSize) / 2;
543 if (labelSize < 0)
544 labelSize = 0;
545
546 gSize = labelSize + valueSize;
547 padSize = xSizeClient - gSize * 2;
548 }
549
550 labelSize = gSize - valueSize;
551
552 yPos = my;
553 for (unsigned i = 0; i < Z7_ARRAY_SIZE(kIDs); i += 2)
554 {
555 int x = mx;
556 const unsigned kNumColumn1Items = 5 * 2;
557 if (i >= kNumColumn1Items)
558 {
559 if (i == kNumColumn1Items)
560 yPos = my;
561 x = mx + gSize + padSize;
562 }
563 if (kIDs[i] != 0)
564 MoveItem(kIDs[i], x, yPos, labelSize, sY);
565 MoveItem(kIDs[i + 1], x + labelSize, yPos, valueSize, sY);
566 yPos += sStep;
567 }
568 return false;
569 }
570
OnCancel()571 void CProgressDialog::OnCancel() { Sync.Set_Stopped(true); }
OnOK()572 void CProgressDialog::OnOK() { }
573
SetProgressRange(UInt64 range)574 void CProgressDialog::SetProgressRange(UInt64 range)
575 {
576 if (range == _progressBar_Range)
577 return;
578 _progressBar_Range = range;
579 INIT_AS_UNDEFINED(_progressBar_Pos)
580 _progressConv.Init(range);
581 m_ProgressBar.SetRange32(0, _progressConv.Count(range));
582 }
583
SetProgressPos(UInt64 pos)584 void CProgressDialog::SetProgressPos(UInt64 pos)
585 {
586 if (pos >= _progressBar_Range ||
587 pos <= _progressBar_Pos ||
588 pos - _progressBar_Pos >= (_progressBar_Range >> 10))
589 {
590 m_ProgressBar.SetPos(_progressConv.Count(pos));
591 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
592 if (_taskbarList && _hwndForTaskbar)
593 _taskbarList->SetProgressValue(_hwndForTaskbar, pos, _progressBar_Range);
594 // #endif
595 _progressBar_Pos = pos;
596 }
597 }
598
599 #define UINT_TO_STR_2(val) { s[0] = (wchar_t)('0' + (val) / 10); s[1] = (wchar_t)('0' + (val) % 10); s += 2; }
600
601 void GetTimeString(UInt64 timeValue, wchar_t *s);
GetTimeString(UInt64 timeValue,wchar_t * s)602 void GetTimeString(UInt64 timeValue, wchar_t *s)
603 {
604 UInt64 hours = timeValue / 3600;
605 UInt32 seconds = (UInt32)(timeValue - hours * 3600);
606 UInt32 minutes = seconds / 60;
607 seconds %= 60;
608 if (hours > 99)
609 {
610 ConvertUInt64ToString(hours, s);
611 for (; *s != 0; s++);
612 }
613 else
614 {
615 UInt32 hours32 = (UInt32)hours;
616 UINT_TO_STR_2(hours32)
617 }
618 *s++ = ':'; UINT_TO_STR_2(minutes)
619 *s++ = ':'; UINT_TO_STR_2(seconds)
620 *s = 0;
621 }
622
ConvertSizeToString(UInt64 v,wchar_t * s)623 static void ConvertSizeToString(UInt64 v, wchar_t *s)
624 {
625 Byte c = 0;
626 if (v >= ((UInt64)100000 << 20)) { v >>= 30; c = 'G'; }
627 else if (v >= ((UInt64)100000 << 10)) { v >>= 20; c = 'M'; }
628 else if (v >= ((UInt64)100000 << 0)) { v >>= 10; c = 'K'; }
629 ConvertUInt64ToString(v, s);
630 if (c != 0)
631 {
632 s += MyStringLen(s);
633 *s++ = ' ';
634 *s++ = c;
635 *s++ = 'B';
636 *s++ = 0;
637 }
638 }
639
ShowSize(unsigned id,UInt64 val,UInt64 & prev)640 void CProgressDialog::ShowSize(unsigned id, UInt64 val, UInt64 &prev)
641 {
642 if (val == prev)
643 return;
644 prev = val;
645 wchar_t s[40];
646 s[0] = 0;
647 if (IS_DEFINED_VAL(val))
648 ConvertSizeToString(val, s);
649 SetItemText(id, s);
650 }
651
GetChangedString(const UString & newStr,UString & prevStr,bool & hasChanged)652 static void GetChangedString(const UString &newStr, UString &prevStr, bool &hasChanged)
653 {
654 hasChanged = !(prevStr == newStr);
655 if (hasChanged)
656 prevStr = newStr;
657 }
658
GetPower32(UInt32 val)659 static unsigned GetPower32(UInt32 val)
660 {
661 const unsigned kStart = 32;
662 UInt32 mask = ((UInt32)1 << (kStart - 1));
663 for (unsigned i = kStart;; i--)
664 {
665 if (i == 0 || (val & mask) != 0)
666 return i;
667 mask >>= 1;
668 }
669 }
670
GetPower64(UInt64 val)671 static unsigned GetPower64(UInt64 val)
672 {
673 UInt32 high = (UInt32)(val >> 32);
674 if (high == 0)
675 return GetPower32((UInt32)val);
676 return GetPower32(high) + 32;
677 }
678
MyMultAndDiv(UInt64 mult1,UInt64 mult2,UInt64 divider)679 static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider)
680 {
681 unsigned pow1 = GetPower64(mult1);
682 unsigned pow2 = GetPower64(mult2);
683 while (pow1 + pow2 > 64)
684 {
685 if (pow1 > pow2) { pow1--; mult1 >>= 1; }
686 else { pow2--; mult2 >>= 1; }
687 divider >>= 1;
688 }
689 UInt64 res = mult1 * mult2;
690 if (divider != 0)
691 res /= divider;
692 return res;
693 }
694
UpdateStatInfo(bool showAll)695 void CProgressDialog::UpdateStatInfo(bool showAll)
696 {
697 UInt64 total, completed, totalFiles, completedFiles, inSize, outSize;
698 bool filesProgressMode;
699
700 bool titleFileName_Changed;
701 bool curFilePath_Changed;
702 bool status_Changed;
703 unsigned numErrors;
704 {
705 NSynchronization::CCriticalSectionLock lock(Sync._cs);
706 total = Sync._totalBytes;
707 completed = Sync._completedBytes;
708 totalFiles = Sync._totalFiles;
709 completedFiles = Sync._curFiles;
710 inSize = Sync._inSize;
711 outSize = Sync._outSize;
712 filesProgressMode = Sync._filesProgressMode;
713
714 GetChangedString(Sync._titleFileName, _titleFileName, titleFileName_Changed);
715 GetChangedString(Sync._filePath, _filePath, curFilePath_Changed);
716 GetChangedString(Sync._status, _status, status_Changed);
717 if (_isDir != Sync._isDir)
718 {
719 curFilePath_Changed = true;
720 _isDir = Sync._isDir;
721 }
722 numErrors = Sync.Messages.Size();
723 }
724
725 UInt32 curTime = ::GetTickCount();
726
727 const UInt64 progressTotal = filesProgressMode ? totalFiles : total;
728 const UInt64 progressCompleted = filesProgressMode ? completedFiles : completed;
729 {
730 if (IS_UNDEFINED_VAL(progressTotal))
731 {
732 // SetPos(0);
733 // SetRange(progressCompleted);
734 }
735 else
736 {
737 if (_progressBar_Pos != 0 || progressCompleted != 0 ||
738 (_progressBar_Range == 0 && progressTotal != 0))
739 {
740 SetProgressRange(progressTotal);
741 SetProgressPos(progressCompleted);
742 }
743 }
744 }
745
746 ShowSize(IDT_PROGRESS_TOTAL_VAL, total, _totalBytes_Prev);
747
748 _elapsedTime += (curTime - _prevTime);
749 _prevTime = curTime;
750 UInt64 elapsedSec = _elapsedTime / 1000;
751 bool elapsedChanged = false;
752 if (elapsedSec != _prevElapsedSec)
753 {
754 _prevElapsedSec = elapsedSec;
755 elapsedChanged = true;
756 wchar_t s[40];
757 GetTimeString(elapsedSec, s);
758 SetItemText(IDT_PROGRESS_ELAPSED_VAL, s);
759 }
760
761 bool needSetTitle = false;
762 if (elapsedChanged || showAll)
763 {
764 if (numErrors > _numPostedMessages)
765 {
766 UpdateMessagesDialog();
767 wchar_t s[32];
768 ConvertUInt64ToString(numErrors, s);
769 SetItemText(IDT_PROGRESS_ERRORS_VAL, s);
770 if (!_errorsWereDisplayed)
771 {
772 _errorsWereDisplayed = true;
773 EnableErrorsControls(true);
774 SetTaskbarProgressState();
775 }
776 }
777
778 if (progressCompleted != 0)
779 {
780 if (IS_UNDEFINED_VAL(progressTotal))
781 {
782 if (IS_DEFINED_VAL(_prevRemainingSec))
783 {
784 INIT_AS_UNDEFINED(_prevRemainingSec)
785 SetItemText(IDT_PROGRESS_REMAINING_VAL, L"");
786 }
787 }
788 else
789 {
790 UInt64 remainingTime = 0;
791 if (progressCompleted < progressTotal)
792 remainingTime = MyMultAndDiv(_elapsedTime, progressTotal - progressCompleted, progressCompleted);
793 UInt64 remainingSec = remainingTime / 1000;
794 if (remainingSec != _prevRemainingSec)
795 {
796 _prevRemainingSec = remainingSec;
797 wchar_t s[40];
798 GetTimeString(remainingSec, s);
799 SetItemText(IDT_PROGRESS_REMAINING_VAL, s);
800 }
801 }
802 {
803 const UInt64 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime;
804 // 22.02: progressCompleted can be for number of files
805 UInt64 v = (completed * 1000) / elapsedTime;
806 Byte c = 0;
807 unsigned moveBits = 0;
808 if (v >= ((UInt64)10000 << 10)) { moveBits = 20; c = 'M'; }
809 else if (v >= ((UInt64)10000 << 0)) { moveBits = 10; c = 'K'; }
810 v >>= moveBits;
811 if (moveBits != _prevSpeed_MoveBits || v != _prevSpeed)
812 {
813 _prevSpeed_MoveBits = moveBits;
814 _prevSpeed = v;
815 wchar_t s[40];
816 ConvertUInt64ToString(v, s);
817 unsigned pos = MyStringLen(s);
818 s[pos++] = ' ';
819 if (moveBits != 0)
820 s[pos++] = c;
821 s[pos++] = 'B';
822 s[pos++] = '/';
823 s[pos++] = 's';
824 s[pos++] = 0;
825 SetItemText(IDT_PROGRESS_SPEED_VAL, s);
826 }
827 }
828 }
829
830 {
831 UInt64 percent = 0;
832 {
833 if (IS_DEFINED_VAL(progressTotal))
834 {
835 percent = progressCompleted * 100;
836 if (progressTotal != 0)
837 percent /= progressTotal;
838 }
839 }
840 if (percent != _prevPercentValue)
841 {
842 _prevPercentValue = percent;
843 needSetTitle = true;
844 }
845 }
846
847 {
848 wchar_t s[64];
849
850 ConvertUInt64ToString(completedFiles, s);
851 if (_filesStr_Prev != s)
852 {
853 _filesStr_Prev = s;
854 SetItemText(IDT_PROGRESS_FILES_VAL, s);
855 }
856
857 s[0] = 0;
858 if (IS_DEFINED_VAL(totalFiles))
859 {
860 MyStringCopy(s, L" / ");
861 ConvertUInt64ToString(totalFiles, s + MyStringLen(s));
862 }
863 if (_filesTotStr_Prev != s)
864 {
865 _filesTotStr_Prev = s;
866 SetItemText(IDT_PROGRESS_FILES_TOTAL, s);
867 }
868 }
869
870 const UInt64 packSize = CompressingMode ? outSize : inSize;
871 const UInt64 unpackSize = CompressingMode ? inSize : outSize;
872
873 if (IS_UNDEFINED_VAL(unpackSize) &&
874 IS_UNDEFINED_VAL(packSize))
875 {
876 ShowSize(IDT_PROGRESS_PROCESSED_VAL, completed, _processed_Prev);
877 ShowSize(IDT_PROGRESS_PACKED_VAL, UNDEFINED_VAL, _packed_Prev);
878 }
879 else
880 {
881 ShowSize(IDT_PROGRESS_PROCESSED_VAL, unpackSize, _processed_Prev);
882 ShowSize(IDT_PROGRESS_PACKED_VAL, packSize, _packed_Prev);
883
884 if (IS_DEFINED_VAL(packSize) &&
885 IS_DEFINED_VAL(unpackSize) &&
886 unpackSize != 0)
887 {
888 wchar_t s[32];
889 UInt64 ratio = packSize * 100 / unpackSize;
890 if (_ratio_Prev != ratio)
891 {
892 _ratio_Prev = ratio;
893 ConvertUInt64ToString(ratio, s);
894 MyStringCat(s, L"%");
895 SetItemText(IDT_PROGRESS_RATIO_VAL, s);
896 }
897 }
898 }
899 }
900
901 if (needSetTitle || titleFileName_Changed)
902 SetTitleText();
903
904 if (status_Changed)
905 {
906 UString s = _status;
907 ReduceString(s, _numReduceSymbols);
908 SetItemText(IDT_PROGRESS_STATUS, s);
909 }
910
911 if (curFilePath_Changed)
912 {
913 UString s1, s2;
914 if (_isDir)
915 s1 = _filePath;
916 else
917 {
918 int slashPos = _filePath.ReverseFind_PathSepar();
919 if (slashPos >= 0)
920 {
921 s1.SetFrom(_filePath, (unsigned)(slashPos + 1));
922 s2 = _filePath.Ptr((unsigned)(slashPos + 1));
923 }
924 else
925 s2 = _filePath;
926 }
927 ReduceString(s1, _numReduceSymbols);
928 ReduceString(s2, _numReduceSymbols);
929 s1.Add_LF();
930 s1 += s2;
931 SetItemText(IDT_PROGRESS_FILE_NAME, s1);
932 }
933 }
934
OnTimer(WPARAM,LPARAM)935 bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
936 {
937 if (Sync.Get_Paused())
938 return true;
939 CheckNeedClose();
940 UpdateStatInfo(false);
941 return true;
942 }
943
944 struct CWaitCursor
945 {
946 HCURSOR _waitCursor;
947 HCURSOR _oldCursor;
CWaitCursorCWaitCursor948 CWaitCursor()
949 {
950 _waitCursor = LoadCursor(NULL, IDC_WAIT);
951 if (_waitCursor != NULL)
952 _oldCursor = SetCursor(_waitCursor);
953 }
~CWaitCursorCWaitCursor954 ~CWaitCursor()
955 {
956 if (_waitCursor != NULL)
957 SetCursor(_oldCursor);
958 }
959 };
960
Create(const UString & title,NWindows::CThread & thread,HWND wndParent)961 INT_PTR CProgressDialog::Create(const UString &title, NWindows::CThread &thread, HWND wndParent)
962 {
963 INT_PTR res = 0;
964 try
965 {
966 if (WaitMode)
967 {
968 CWaitCursor waitCursor;
969 HANDLE h[] = { thread, _createDialogEvent };
970
971 const DWORD res2 = WaitForMultipleObjects(Z7_ARRAY_SIZE(h), h, FALSE, kCreateDelay);
972 if (res2 == WAIT_OBJECT_0 && !Sync.ThereIsMessage())
973 return 0;
974 }
975 _title = title;
976 BIG_DIALOG_SIZE(360, 192);
977 res = CModalDialog::Create(SIZED_DIALOG(IDD_PROGRESS), wndParent);
978 }
979 catch(...)
980 {
981 _wasCreated = true;
982 _dialogCreatedEvent.Set();
983 }
984 thread.Wait_Close();
985 if (!MessagesDisplayed)
986 if (!g_DisableUserQuestions)
987 MessageBoxW(wndParent, L"Progress Error", L"7-Zip", MB_ICONERROR);
988 return res;
989 }
990
OnExternalCloseMessage()991 bool CProgressDialog::OnExternalCloseMessage()
992 {
993 // it doesn't work if there is MessageBox.
994 // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
995 SetTaskbarProgressState(TBPF_NOPROGRESS);
996 // #endif
997 // AddToTitle(L"Finished ");
998 // SetText(L"Finished2 ");
999
1000 UpdateStatInfo(true);
1001
1002 SetItemText(IDCANCEL, LangString(IDS_CLOSE));
1003 ::SendMessage(GetItem(IDCANCEL), BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0));
1004 HideItem(IDB_PROGRESS_BACKGROUND);
1005 HideItem(IDB_PAUSE);
1006
1007 ProcessWasFinished_GuiVirt();
1008
1009 bool thereAreMessages;
1010 CProgressFinalMessage fm;
1011 {
1012 NSynchronization::CCriticalSectionLock lock(Sync._cs);
1013 thereAreMessages = !Sync.Messages.IsEmpty();
1014 fm = Sync.FinalMessage;
1015 }
1016
1017 if (!fm.ErrorMessage.Message.IsEmpty())
1018 {
1019 MessagesDisplayed = true;
1020 if (fm.ErrorMessage.Title.IsEmpty())
1021 fm.ErrorMessage.Title = "7-Zip";
1022 if (!g_DisableUserQuestions)
1023 MessageBoxW(*this, fm.ErrorMessage.Message, fm.ErrorMessage.Title, MB_ICONERROR);
1024 }
1025 else if (!thereAreMessages)
1026 {
1027 MessagesDisplayed = true;
1028
1029 if (!fm.OkMessage.Message.IsEmpty())
1030 {
1031 if (fm.OkMessage.Title.IsEmpty())
1032 fm.OkMessage.Title = "7-Zip";
1033 if (!g_DisableUserQuestions)
1034 MessageBoxW(*this, fm.OkMessage.Message, fm.OkMessage.Title, MB_OK);
1035 }
1036 }
1037
1038 if (!g_DisableUserQuestions)
1039 if (thereAreMessages && !_cancelWasPressed)
1040 {
1041 _waitCloseByCancelButton = true;
1042 UpdateMessagesDialog();
1043 return true;
1044 }
1045
1046 End(0);
1047 return true;
1048 }
1049
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)1050 bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
1051 {
1052 switch (message)
1053 {
1054 case kCloseMessage:
1055 {
1056 if (_timer)
1057 {
1058 /* 21.03 : KillTimer(kTimerID) instead of KillTimer(_timer).
1059 But (_timer == kTimerID) in Win10. So it worked too */
1060 KillTimer(kTimerID);
1061 _timer = 0;
1062 }
1063 if (_inCancelMessageBox)
1064 {
1065 /* if user is in MessageBox(), we will call OnExternalCloseMessage()
1066 later, when MessageBox() will be closed */
1067 _externalCloseMessageWasReceived = true;
1068 break;
1069 }
1070 return OnExternalCloseMessage();
1071 }
1072 /*
1073 case WM_SETTEXT:
1074 {
1075 if (_timer == 0)
1076 return true;
1077 break;
1078 }
1079 */
1080 }
1081 return CModalDialog::OnMessage(message, wParam, lParam);
1082 }
1083
SetTitleText()1084 void CProgressDialog::SetTitleText()
1085 {
1086 UString s;
1087 if (Sync.Get_Paused())
1088 {
1089 s += _paused_String;
1090 s.Add_Space();
1091 }
1092 if (IS_DEFINED_VAL(_prevPercentValue))
1093 {
1094 s.Add_UInt64(_prevPercentValue);
1095 s.Add_Char('%');
1096 }
1097 if (_background)
1098 {
1099 s.Add_Space();
1100 s += _backgrounded_String;
1101 }
1102
1103 s.Add_Space();
1104 #ifndef Z7_SFX
1105 {
1106 unsigned len = s.Len();
1107 s += MainAddTitle;
1108 AddToTitle(s);
1109 s.DeleteFrom(len);
1110 }
1111 #endif
1112
1113 s += _title;
1114 if (!_titleFileName.IsEmpty())
1115 {
1116 UString fileName = _titleFileName;
1117 ReduceString(fileName, kTitleFileNameSizeLimit);
1118 s.Add_Space();
1119 s += fileName;
1120 }
1121 SetText(s);
1122 }
1123
SetPauseText()1124 void CProgressDialog::SetPauseText()
1125 {
1126 SetItemText(IDB_PAUSE, Sync.Get_Paused() ? _continue_String : _pause_String);
1127 SetTitleText();
1128 }
1129
OnPauseButton()1130 void CProgressDialog::OnPauseButton()
1131 {
1132 bool paused = !Sync.Get_Paused();
1133 Sync.Set_Paused(paused);
1134 UInt32 curTime = ::GetTickCount();
1135 if (paused)
1136 _elapsedTime += (curTime - _prevTime);
1137 SetTaskbarProgressState();
1138 _prevTime = curTime;
1139 SetPauseText();
1140 }
1141
SetPriorityText()1142 void CProgressDialog::SetPriorityText()
1143 {
1144 SetItemText(IDB_PROGRESS_BACKGROUND, _background ?
1145 _foreground_String :
1146 _background_String);
1147 SetTitleText();
1148 }
1149
OnPriorityButton()1150 void CProgressDialog::OnPriorityButton()
1151 {
1152 _background = !_background;
1153 #ifndef UNDER_CE
1154 SetPriorityClass(GetCurrentProcess(), _background ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS);
1155 #endif
1156 SetPriorityText();
1157 }
1158
AddMessageDirect(LPCWSTR message,bool needNumber)1159 void CProgressDialog::AddMessageDirect(LPCWSTR message, bool needNumber)
1160 {
1161 wchar_t sz[16];
1162 sz[0] = 0;
1163 if (needNumber)
1164 ConvertUInt32ToString(_numMessages + 1, sz);
1165 const unsigned itemIndex = _messageStrings.Size(); // _messageList.GetItemCount();
1166 if (_messageList.InsertItem(itemIndex, sz) == (int)itemIndex)
1167 {
1168 _messageList.SetSubItem(itemIndex, 1, message);
1169 _messageStrings.Add(message);
1170 }
1171 }
1172
AddMessage(LPCWSTR message)1173 void CProgressDialog::AddMessage(LPCWSTR message)
1174 {
1175 UString s = message;
1176 bool needNumber = true;
1177 while (!s.IsEmpty())
1178 {
1179 const int pos = s.Find(L'\n');
1180 if (pos < 0)
1181 break;
1182 AddMessageDirect(s.Left((unsigned)pos), needNumber);
1183 needNumber = false;
1184 s.DeleteFrontal((unsigned)pos + 1);
1185 }
1186 AddMessageDirect(s, needNumber);
1187 _numMessages++;
1188 }
1189
GetNumDigits(unsigned val)1190 static unsigned GetNumDigits(unsigned val)
1191 {
1192 unsigned i = 0;
1193 for (;;)
1194 {
1195 i++;
1196 val /= 10;
1197 if (val == 0)
1198 return i;
1199 }
1200 }
1201
UpdateMessagesDialog()1202 void CProgressDialog::UpdateMessagesDialog()
1203 {
1204 UStringVector messages;
1205 {
1206 NSynchronization::CCriticalSectionLock lock(Sync._cs);
1207 const unsigned num = Sync.Messages.Size();
1208 if (num > _numPostedMessages)
1209 {
1210 messages.ClearAndReserve(num - _numPostedMessages);
1211 for (unsigned i = _numPostedMessages; i < num; i++)
1212 messages.AddInReserved(Sync.Messages[i]);
1213 _numPostedMessages = num;
1214 }
1215 }
1216 if (!messages.IsEmpty())
1217 {
1218 FOR_VECTOR (i, messages)
1219 AddMessage(messages[i]);
1220 // SetColumnWidthAuto() can be slow for big number of files.
1221 if (_numPostedMessages < 1000000 || _numAutoSizeMessages < 100)
1222 if (_numAutoSizeMessages < 100 ||
1223 GetNumDigits(_numPostedMessages) >
1224 GetNumDigits(_numAutoSizeMessages))
1225 {
1226 _messageList.SetColumnWidthAuto(0);
1227 _messageList.SetColumnWidthAuto(1);
1228 _numAutoSizeMessages = _numPostedMessages;
1229 }
1230 }
1231 }
1232
1233
OnButtonClicked(unsigned buttonID,HWND buttonHWND)1234 bool CProgressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
1235 {
1236 switch (buttonID)
1237 {
1238 // case IDOK: // if IDCANCEL is not DEFPUSHBUTTON
1239 case IDCANCEL:
1240 {
1241 if (_waitCloseByCancelButton)
1242 {
1243 MessagesDisplayed = true;
1244 End(IDCLOSE);
1245 break;
1246 }
1247
1248 if (_cancelWasPressed)
1249 return true;
1250
1251 const bool paused = Sync.Get_Paused();
1252
1253 if (!paused)
1254 {
1255 OnPauseButton();
1256 }
1257
1258 _inCancelMessageBox = true;
1259 const int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL);
1260 _inCancelMessageBox = false;
1261 if (res == IDYES)
1262 _cancelWasPressed = true;
1263
1264 if (!paused)
1265 {
1266 OnPauseButton();
1267 }
1268
1269 if (_externalCloseMessageWasReceived)
1270 {
1271 /* we have received kCloseMessage while we were in MessageBoxW().
1272 so we call OnExternalCloseMessage() here.
1273 it can show MessageBox and it can close dialog */
1274 OnExternalCloseMessage();
1275 return true;
1276 }
1277
1278 if (!_cancelWasPressed)
1279 return true;
1280
1281 MessagesDisplayed = true;
1282 // we will call Sync.Set_Stopped(true) in OnButtonClicked() : OnCancel()
1283 break;
1284 }
1285
1286 case IDB_PAUSE:
1287 OnPauseButton();
1288 return true;
1289 case IDB_PROGRESS_BACKGROUND:
1290 OnPriorityButton();
1291 return true;
1292 }
1293 return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
1294 }
1295
CheckNeedClose()1296 void CProgressDialog::CheckNeedClose()
1297 {
1298 if (_needClose)
1299 {
1300 PostMsg(kCloseMessage);
1301 _needClose = false;
1302 }
1303 }
1304
ProcessWasFinished()1305 void CProgressDialog::ProcessWasFinished()
1306 {
1307 // Set Window title here.
1308 if (!WaitMode)
1309 WaitCreating();
1310
1311 if (_wasCreated)
1312 PostMsg(kCloseMessage);
1313 else
1314 _needClose = true;
1315 }
1316
1317
OnNotify(UINT,LPNMHDR header)1318 bool CProgressDialog::OnNotify(UINT /* controlID */, LPNMHDR header)
1319 {
1320 if (header->hwndFrom != _messageList)
1321 return false;
1322 switch (header->code)
1323 {
1324 case LVN_KEYDOWN:
1325 {
1326 LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header);
1327 switch (keyDownInfo->wVKey)
1328 {
1329 case 'A':
1330 {
1331 if (IsKeyDown(VK_CONTROL))
1332 {
1333 _messageList.SelectAll();
1334 return true;
1335 }
1336 break;
1337 }
1338 case VK_INSERT:
1339 case 'C':
1340 {
1341 if (IsKeyDown(VK_CONTROL))
1342 {
1343 CopyToClipboard();
1344 return true;
1345 }
1346 break;
1347 }
1348 }
1349 }
1350 }
1351 return false;
1352 }
1353
1354
ListView_GetSelected(NControl::CListView & listView,CUIntVector & vector)1355 static void ListView_GetSelected(NControl::CListView &listView, CUIntVector &vector)
1356 {
1357 vector.Clear();
1358 int index = -1;
1359 for (;;)
1360 {
1361 index = listView.GetNextSelectedItem(index);
1362 if (index < 0)
1363 break;
1364 vector.Add((unsigned)index);
1365 }
1366 }
1367
1368
CopyToClipboard()1369 void CProgressDialog::CopyToClipboard()
1370 {
1371 CUIntVector indexes;
1372 ListView_GetSelected(_messageList, indexes);
1373 UString s;
1374 unsigned numIndexes = indexes.Size();
1375 if (numIndexes == 0)
1376 numIndexes = (unsigned)_messageList.GetItemCount();
1377
1378 for (unsigned i = 0; i < numIndexes; i++)
1379 {
1380 const unsigned index = (i < indexes.Size() ? indexes[i] : i);
1381 // s.Add_UInt32(index);
1382 // s += ": ";
1383 s += _messageStrings[index];
1384 {
1385 s +=
1386 #ifdef _WIN32
1387 "\r\n"
1388 #else
1389 "\n"
1390 #endif
1391 ;
1392 }
1393 }
1394
1395 ClipboardSetText(*this, s);
1396 }
1397
1398
MyThreadFunction(void * param)1399 static THREAD_FUNC_DECL MyThreadFunction(void *param)
1400 {
1401 CProgressThreadVirt *p = (CProgressThreadVirt *)param;
1402 try
1403 {
1404 p->Process();
1405 p->ThreadFinishedOK = true;
1406 }
1407 catch (...) { p->Result = E_FAIL; }
1408 return 0;
1409 }
1410
1411
Create(const UString & title,HWND parentWindow)1412 HRESULT CProgressThreadVirt::Create(const UString &title, HWND parentWindow)
1413 {
1414 NWindows::CThread thread;
1415 const WRes wres = thread.Create(MyThreadFunction, this);
1416 if (wres != 0)
1417 return HRESULT_FROM_WIN32(wres);
1418 CProgressDialog::Create(title, thread, parentWindow);
1419 return S_OK;
1420 }
1421
AddMessageToString(UString & dest,const UString & src)1422 static void AddMessageToString(UString &dest, const UString &src)
1423 {
1424 if (!src.IsEmpty())
1425 {
1426 if (!dest.IsEmpty())
1427 dest.Add_LF();
1428 dest += src;
1429 }
1430 }
1431
Process()1432 void CProgressThreadVirt::Process()
1433 {
1434 CProgressCloser closer(*this);
1435 UString m;
1436 try { Result = ProcessVirt(); }
1437 catch(const wchar_t *s) { m = s; }
1438 catch(const UString &s) { m = s; }
1439 catch(const char *s) { m = GetUnicodeString(s); }
1440 catch(int v)
1441 {
1442 m = "Error #";
1443 m.Add_UInt32((unsigned)v);
1444 }
1445 catch(...) { m = "Error"; }
1446 if (Result != E_ABORT)
1447 {
1448 if (m.IsEmpty() && Result != S_OK)
1449 m = HResultToMessage(Result);
1450 }
1451 AddMessageToString(m, FinalMessage.ErrorMessage.Message);
1452
1453 {
1454 FOR_VECTOR(i, ErrorPaths)
1455 {
1456 if (i >= 32)
1457 break;
1458 AddMessageToString(m, fs2us(ErrorPaths[i]));
1459 }
1460 }
1461
1462 CProgressSync &sync = Sync;
1463 NSynchronization::CCriticalSectionLock lock(sync._cs);
1464 if (m.IsEmpty())
1465 {
1466 if (!FinalMessage.OkMessage.Message.IsEmpty())
1467 sync.FinalMessage.OkMessage = FinalMessage.OkMessage;
1468 }
1469 else
1470 {
1471 sync.FinalMessage.ErrorMessage.Message = m;
1472 if (Result == S_OK)
1473 Result = E_FAIL;
1474 }
1475 }
1476
HResultToMessage(HRESULT errorCode)1477 UString HResultToMessage(HRESULT errorCode)
1478 {
1479 if (errorCode == E_OUTOFMEMORY)
1480 return LangString(IDS_MEM_ERROR);
1481 else
1482 return NError::MyFormatMessage(errorCode);
1483 }
1484