• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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