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