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