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