"Fossies" - the Fresh Open Source Software Archive

Member "UXP-2019.06.08/other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog2.cpp" (8 Jun 2019, 31886 Bytes) of package /linux/www/UXP-2019.06.08.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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