1 /* 2 * PROJECT: ReactOS Zip Shell Extension 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Zip extraction 5 * COPYRIGHT: Copyright 2017-2019 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #include "precomp.h" 9 10 class CZipExtract : 11 public IZip 12 { 13 CStringW m_Filename; 14 CStringW m_Directory; 15 CStringA m_Password; 16 bool m_DirectoryChanged; 17 unzFile uf; 18 public: 19 CZipExtract(PCWSTR Filename) 20 :m_DirectoryChanged(false) 21 ,uf(NULL) 22 { 23 m_Filename = Filename; 24 m_Directory = m_Filename; 25 PWSTR Dir = m_Directory.GetBuffer(); 26 PathRemoveExtensionW(Dir); 27 m_Directory.ReleaseBuffer(); 28 } 29 30 ~CZipExtract() 31 { 32 if (uf) 33 { 34 DPRINT1("WARNING: uf not closed!\n"); 35 Close(); 36 } 37 } 38 39 void Close() 40 { 41 if (uf) 42 unzClose(uf); 43 uf = NULL; 44 } 45 46 // *** IZip methods *** 47 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) 48 { 49 if (riid == IID_IUnknown) 50 { 51 *ppvObject = this; 52 AddRef(); 53 return S_OK; 54 } 55 return E_NOINTERFACE; 56 } 57 STDMETHODIMP_(ULONG) AddRef(void) 58 { 59 return 2; 60 } 61 STDMETHODIMP_(ULONG) Release(void) 62 { 63 return 1; 64 } 65 STDMETHODIMP_(unzFile) getZip() 66 { 67 return uf; 68 } 69 70 class CExtractSettingsPage : public CPropertyPageImpl<CExtractSettingsPage> 71 { 72 private: 73 HANDLE m_hExtractionThread; 74 bool m_bExtractionThreadCancel; 75 76 CZipExtract* m_pExtract; 77 CStringA* m_pPassword; 78 CStringW m_OldStatus; 79 80 public: 81 CExtractSettingsPage(CZipExtract* extract, CStringA* password) 82 :CPropertyPageImpl<CExtractSettingsPage>(MAKEINTRESOURCE(IDS_WIZ_TITLE)) 83 ,m_hExtractionThread(NULL) 84 ,m_bExtractionThreadCancel(false) 85 ,m_pExtract(extract) 86 ,m_pPassword(password) 87 { 88 m_psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_WIZ_DEST_TITLE); 89 m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_WIZ_DEST_SUBTITLE); 90 m_psp.dwFlags |= PSP_USETITLE | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; 91 } 92 93 int OnSetActive() 94 { 95 SetDlgItemTextW(IDC_DIRECTORY, m_pExtract->m_Directory); 96 m_pExtract->m_DirectoryChanged = false; 97 GetParent().CenterWindow(::GetDesktopWindow()); 98 SetWizardButtons(PSWIZB_NEXT); 99 return 0; 100 } 101 102 int OnWizardNext() 103 { 104 if (m_hExtractionThread != NULL) 105 { 106 /* We enter here when extraction has finished, and go to next page if it succeeded */ 107 WaitForSingleObject(m_hExtractionThread, INFINITE); 108 CloseHandle(m_hExtractionThread); 109 m_hExtractionThread = NULL; 110 m_pExtract->Release(); 111 if (!m_bExtractionThreadCancel) 112 { 113 return 0; 114 } 115 else 116 { 117 SetWindowLongPtr(DWLP_MSGRESULT, -1); 118 return TRUE; 119 } 120 } 121 122 /* We end up here if the user manually clicks Next: start extraction */ 123 m_bExtractionThreadCancel = false; 124 125 /* Grey out every control during extraction to prevent user interaction */ 126 ::EnableWindow(GetDlgItem(IDC_BROWSE), FALSE); 127 ::EnableWindow(GetDlgItem(IDC_DIRECTORY), FALSE); 128 ::EnableWindow(GetDlgItem(IDC_PASSWORD), FALSE); 129 SetWizardButtons(0); 130 131 ::GetWindowTextW(GetDlgItem(IDC_STATUSTEXT), m_OldStatus.GetBuffer(MAX_PATH), MAX_PATH); 132 m_OldStatus.ReleaseBuffer(); 133 CStringW strExtracting(MAKEINTRESOURCEW(IDS_EXTRACTING)); 134 SetDlgItemTextW(IDC_STATUSTEXT, strExtracting); 135 136 if (m_pExtract->m_DirectoryChanged) 137 UpdateDirectory(); 138 139 m_pExtract->AddRef(); 140 141 m_hExtractionThread = CreateThread(NULL, 0, 142 &CExtractSettingsPage::ExtractEntry, 143 this, 144 0, NULL); 145 if (!m_hExtractionThread) 146 { 147 /* Extraction thread creation failed, do not go to the next page */ 148 DWORD err = GetLastError(); 149 DPRINT1("ERROR, m_hExtractionThread: CreateThread failed: 0x%x\n", err); 150 m_pExtract->Release(); 151 152 SetWindowLongPtr(DWLP_MSGRESULT, -1); 153 154 ::EnableWindow(GetDlgItem(IDC_BROWSE), TRUE); 155 ::EnableWindow(GetDlgItem(IDC_DIRECTORY), TRUE); 156 ::EnableWindow(GetDlgItem(IDC_PASSWORD), TRUE); 157 SetWizardButtons(PSWIZB_NEXT); 158 } 159 return TRUE; 160 } 161 162 void WizardReset() 163 { 164 SetDlgItemTextW(IDC_STATUSTEXT, m_OldStatus); 165 } 166 167 static DWORD WINAPI ExtractEntry(LPVOID lpParam) 168 { 169 CExtractSettingsPage* pPage = (CExtractSettingsPage*)lpParam; 170 bool res = pPage->m_pExtract->Extract(pPage->m_hWnd, pPage->GetDlgItem(IDC_PROGRESS), &(pPage->m_bExtractionThreadCancel)); 171 /* Failing and cancelling extraction both mean we stay on the same property page */ 172 pPage->m_bExtractionThreadCancel = !res; 173 174 pPage->SetWizardButtons(PSWIZB_NEXT); 175 if (!res) 176 { 177 /* Extraction failed/cancelled: the page becomes interactive again */ 178 ::EnableWindow(pPage->GetDlgItem(IDC_BROWSE), TRUE); 179 ::EnableWindow(pPage->GetDlgItem(IDC_DIRECTORY), TRUE); 180 ::EnableWindow(pPage->GetDlgItem(IDC_PASSWORD), TRUE); 181 182 /* Reset the progress bar's appearance */ 183 CWindow Progress(pPage->GetDlgItem(IDC_PROGRESS)); 184 Progress.SendMessage(PBM_SETRANGE32, 0, 1); 185 Progress.SendMessage(PBM_SETPOS, 0, 0); 186 pPage->WizardReset(); 187 } 188 SendMessageCallback(pPage->GetParent().m_hWnd, PSM_PRESSBUTTON, PSBTN_NEXT, 0, NULL, NULL); 189 190 return 0; 191 } 192 193 BOOL OnQueryCancel() 194 { 195 if (m_hExtractionThread != NULL) 196 { 197 /* Extraction will check the value of m_bExtractionThreadCancel between each file in the archive */ 198 m_bExtractionThreadCancel = true; 199 return TRUE; 200 } 201 return FALSE; 202 } 203 204 struct browse_info 205 { 206 HWND hWnd; 207 LPCWSTR Directory; 208 }; 209 210 static INT CALLBACK s_BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lp, LPARAM pData) 211 { 212 if (uMsg == BFFM_INITIALIZED) 213 { 214 browse_info* info = (browse_info*)pData; 215 CWindow dlg(hWnd); 216 dlg.SendMessage(BFFM_SETSELECTION, TRUE, (LPARAM)info->Directory); 217 dlg.CenterWindow(info->hWnd); 218 } 219 return 0; 220 } 221 222 LRESULT OnBrowse(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) 223 { 224 BROWSEINFOW bi = { m_hWnd }; 225 WCHAR path[MAX_PATH]; 226 bi.pszDisplayName = path; 227 bi.lpfn = s_BrowseCallbackProc; 228 bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS; 229 CStringW title(MAKEINTRESOURCEW(IDS_WIZ_BROWSE_TITLE)); 230 bi.lpszTitle = title; 231 232 if (m_pExtract->m_DirectoryChanged) 233 UpdateDirectory(); 234 235 browse_info info = { m_hWnd, m_pExtract->m_Directory.GetString() }; 236 bi.lParam = (LPARAM)&info; 237 238 CComHeapPtr<ITEMIDLIST> pidl; 239 pidl.Attach(SHBrowseForFolderW(&bi)); 240 241 WCHAR tmpPath[MAX_PATH]; 242 if (pidl && SHGetPathFromIDListW(pidl, tmpPath)) 243 { 244 m_pExtract->m_Directory = tmpPath; 245 SetDlgItemTextW(IDC_DIRECTORY, m_pExtract->m_Directory); 246 m_pExtract->m_DirectoryChanged = false; 247 } 248 return 0; 249 } 250 251 LRESULT OnEnChangeDirectory(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) 252 { 253 m_pExtract->m_DirectoryChanged = true; 254 return 0; 255 } 256 257 LRESULT OnPassword(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) 258 { 259 CStringA Password; 260 if (_CZipAskPassword(m_hWnd, NULL, Password) == eAccept) 261 { 262 *m_pPassword = Password; 263 } 264 return 0; 265 } 266 267 void UpdateDirectory() 268 { 269 GetDlgItemText(IDC_DIRECTORY, m_pExtract->m_Directory); 270 m_pExtract->m_DirectoryChanged = false; 271 } 272 273 public: 274 enum { IDD = IDD_PROPPAGEDESTINATION }; 275 276 BEGIN_MSG_MAP(CCompleteSettingsPage) 277 COMMAND_ID_HANDLER(IDC_BROWSE, OnBrowse) 278 COMMAND_ID_HANDLER(IDC_PASSWORD, OnPassword) 279 COMMAND_HANDLER(IDC_DIRECTORY, EN_CHANGE, OnEnChangeDirectory) 280 CHAIN_MSG_MAP(CPropertyPageImpl<CExtractSettingsPage>) 281 END_MSG_MAP() 282 }; 283 284 285 class CCompleteSettingsPage : public CPropertyPageImpl<CCompleteSettingsPage> 286 { 287 private: 288 CZipExtract* m_pExtract; 289 290 public: 291 CCompleteSettingsPage(CZipExtract* extract) 292 :CPropertyPageImpl<CCompleteSettingsPage>(MAKEINTRESOURCE(IDS_WIZ_TITLE)) 293 , m_pExtract(extract) 294 { 295 m_psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_WIZ_COMPL_TITLE); 296 m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_WIZ_COMPL_SUBTITLE); 297 m_psp.dwFlags |= PSP_USETITLE | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; 298 } 299 300 301 int OnSetActive() 302 { 303 SetWizardButtons(PSWIZB_FINISH); 304 CStringW Path = m_pExtract->m_Directory; 305 PWSTR Ptr = Path.GetBuffer(MAX_PATH); 306 RECT rc; 307 ::GetWindowRect(GetDlgItem(IDC_DESTDIR), &rc); 308 HDC dc = GetDC(); 309 PathCompactPathW(dc, Ptr, rc.right - rc.left); 310 ReleaseDC(dc); 311 Path.ReleaseBuffer(); 312 SetDlgItemTextW(IDC_DESTDIR, Path); 313 CheckDlgButton(IDC_SHOW_EXTRACTED, BST_CHECKED); 314 return 0; 315 } 316 BOOL OnWizardFinish() 317 { 318 if (IsDlgButtonChecked(IDC_SHOW_EXTRACTED) == BST_CHECKED) 319 { 320 ShellExecuteW(NULL, L"explore", m_pExtract->m_Directory, NULL, NULL, SW_SHOW); 321 } 322 return FALSE; 323 } 324 325 public: 326 enum { IDD = IDD_PROPPAGECOMPLETE }; 327 328 BEGIN_MSG_MAP(CCompleteSettingsPage) 329 CHAIN_MSG_MAP(CPropertyPageImpl<CCompleteSettingsPage>) 330 END_MSG_MAP() 331 }; 332 333 334 /* NOTE: This callback is needed to set large icon correctly. */ 335 static INT CALLBACK s_PropSheetCallbackProc(HWND hwndDlg, UINT uMsg, LPARAM lParam) 336 { 337 if (uMsg == PSCB_INITIALIZED) 338 { 339 HICON hIcon = LoadIconW(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDI_ZIPFLDR)); 340 CWindow dlg(hwndDlg); 341 dlg.SetIcon(hIcon, TRUE); 342 } 343 344 return 0; 345 } 346 347 void runWizard() 348 { 349 PROPSHEETHEADERW psh = { sizeof(psh), 0 }; 350 psh.dwFlags = PSH_WIZARD97 | PSH_HEADER | PSH_USEICONID | PSH_USECALLBACK; 351 psh.hInstance = _AtlBaseModule.GetResourceInstance(); 352 353 CExtractSettingsPage extractPage(this, &m_Password); 354 CCompleteSettingsPage completePage(this); 355 HPROPSHEETPAGE hpsp[] = 356 { 357 extractPage.Create(), 358 completePage.Create() 359 }; 360 361 psh.phpage = hpsp; 362 psh.nPages = _countof(hpsp); 363 psh.pszIcon = MAKEINTRESOURCE(IDI_ZIPFLDR); 364 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK); 365 psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER); 366 psh.pfnCallback = s_PropSheetCallbackProc; 367 368 PropertySheetW(&psh); 369 } 370 371 eZipExtractError ExtractSingle( 372 HWND hDlg, 373 LPCSTR FullPath, 374 bool is_dir, 375 unz_file_info64* Info, 376 CStringA Name, 377 CStringA Password, 378 bool* bOverwriteAll, 379 const bool* bCancel, 380 int* ErrorCode 381 ) 382 { 383 int err; 384 BYTE Buffer[2048]; 385 DWORD dwFlags = SHPPFW_DIRCREATE | (is_dir ? SHPPFW_NONE : SHPPFW_IGNOREFILENAME); 386 HRESULT hr = SHPathPrepareForWriteA(hDlg, NULL, FullPath, dwFlags); 387 if (FAILED_UNEXPECTEDLY(hr)) 388 { 389 *ErrorCode = hr; 390 return eDirectoryError; 391 } 392 if (is_dir) 393 return eNoError; 394 395 if (Info->flag & MINIZIP_PASSWORD_FLAG) 396 { 397 eZipPasswordResponse Response = eAccept; 398 do 399 { 400 /* If there is a password set, try it */ 401 if (!Password.IsEmpty()) 402 { 403 err = unzOpenCurrentFilePassword(uf, Password); 404 if (err == UNZ_OK) 405 { 406 /* Try to read some bytes, because unzOpenCurrentFilePassword does not return failure */ 407 char Buf[10]; 408 err = unzReadCurrentFile(uf, Buf, sizeof(Buf)); 409 unzCloseCurrentFile(uf); 410 if (err >= UNZ_OK) 411 { 412 /* 're'-open the file so that we can begin to extract */ 413 err = unzOpenCurrentFilePassword(uf, Password); 414 break; 415 } 416 } 417 } 418 Response = _CZipAskPassword(hDlg, Name, Password); 419 } while (Response == eAccept); 420 421 if (Response == eSkip) 422 { 423 return eNoError; 424 } 425 else if (Response == eAbort) 426 { 427 return eExtractAbort; 428 } 429 } 430 else 431 { 432 err = unzOpenCurrentFile(uf); 433 } 434 435 if (err != UNZ_OK) 436 { 437 DPRINT1("ERROR, unzOpenCurrentFilePassword: 0x%x\n", err); 438 *ErrorCode = err; 439 return eOpenError; 440 } 441 442 HANDLE hFile = CreateFileA(FullPath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 443 if (hFile == INVALID_HANDLE_VALUE) 444 { 445 DWORD dwErr = GetLastError(); 446 if (dwErr == ERROR_FILE_EXISTS) 447 { 448 bool bOverwrite = *bOverwriteAll; 449 if (!*bOverwriteAll) 450 { 451 eZipConfirmResponse Result = _CZipAskReplace(hDlg, FullPath); 452 switch (Result) 453 { 454 case eYesToAll: 455 *bOverwriteAll = true; 456 /* fall through */ 457 case eYes: 458 bOverwrite = true; 459 break; 460 case eNo: 461 break; 462 case eCancel: 463 unzCloseCurrentFile(uf); 464 return eExtractAbort; 465 } 466 } 467 468 if (bOverwrite) 469 { 470 hFile = CreateFileA(FullPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 471 if (hFile == INVALID_HANDLE_VALUE) 472 { 473 dwErr = GetLastError(); 474 } 475 } 476 else 477 { 478 unzCloseCurrentFile(uf); 479 return eNoError; 480 } 481 } 482 if (hFile == INVALID_HANDLE_VALUE) 483 { 484 unzCloseCurrentFile(uf); 485 DPRINT1("ERROR, CreateFileA: 0x%x (%s)\n", dwErr, *bOverwriteAll ? "Y" : "N"); 486 *ErrorCode = dwErr; 487 return eFileError; 488 } 489 } 490 491 do 492 { 493 if (*bCancel) 494 { 495 CloseHandle(hFile); 496 BOOL deleteResult = DeleteFileA(FullPath); 497 if (!deleteResult) 498 DPRINT1("ERROR, DeleteFileA: 0x%x\n", GetLastError()); 499 return eExtractAbort; 500 } 501 502 err = unzReadCurrentFile(uf, Buffer, sizeof(Buffer)); 503 504 if (err < 0) 505 { 506 DPRINT1("ERROR, unzReadCurrentFile: 0x%x\n", err); 507 break; 508 } 509 else if (err > 0) 510 { 511 DWORD dwWritten; 512 if (!WriteFile(hFile, Buffer, err, &dwWritten, NULL)) 513 { 514 DPRINT1("ERROR, WriteFile: 0x%x\n", GetLastError()); 515 break; 516 } 517 if (dwWritten != (DWORD)err) 518 { 519 DPRINT1("ERROR, WriteFile: dwWritten:%d err:%d\n", dwWritten, err); 520 break; 521 } 522 } 523 524 } while (err > 0); 525 526 /* Update Filetime */ 527 FILETIME LocalFileTime; 528 DosDateTimeToFileTime((WORD)(Info->dosDate >> 16), (WORD)Info->dosDate, &LocalFileTime); 529 FILETIME FileTime; 530 LocalFileTimeToFileTime(&LocalFileTime, &FileTime); 531 SetFileTime(hFile, &FileTime, &FileTime, &FileTime); 532 533 /* Done */ 534 CloseHandle(hFile); 535 536 if (err) 537 { 538 unzCloseCurrentFile(uf); 539 DPRINT1("ERROR, unzReadCurrentFile2: 0x%x\n", err); 540 *ErrorCode = err; 541 return eUnpackError; 542 } 543 else 544 { 545 err = unzCloseCurrentFile(uf); 546 if (err != UNZ_OK) 547 { 548 DPRINT1("ERROR(non-fatal), unzCloseCurrentFile: 0x%x\n", err); 549 } 550 } 551 return eNoError; 552 } 553 554 bool Extract(HWND hDlg, HWND hProgress, const bool* bCancel) 555 { 556 unz_global_info64 gi; 557 uf = unzOpen2_64(m_Filename.GetString(), &g_FFunc); 558 int err = unzGetGlobalInfo64(uf, &gi); 559 if (err != UNZ_OK) 560 { 561 DPRINT1("ERROR, unzGetGlobalInfo64: 0x%x\n", err); 562 Close(); 563 return false; 564 } 565 566 CZipEnumerator zipEnum; 567 if (!zipEnum.initialize(this)) 568 { 569 DPRINT1("ERROR, zipEnum.initialize\n"); 570 Close(); 571 return false; 572 } 573 574 CWindow Progress(hProgress); 575 Progress.SendMessage(PBM_SETRANGE32, 0, gi.number_entry); 576 Progress.SendMessage(PBM_SETPOS, 0, 0); 577 578 CStringA BaseDirectory = m_Directory; 579 CStringA Name; 580 CStringA Password = m_Password; 581 unz_file_info64 Info; 582 int CurrentFile = 0; 583 bool bOverwriteAll = false; 584 while (zipEnum.next(Name, Info)) 585 { 586 if (*bCancel) 587 { 588 Close(); 589 return false; 590 } 591 592 bool is_dir = Name.GetLength() > 0 && Name[Name.GetLength()-1] == '/'; 593 594 char CombinedPath[MAX_PATH * 2] = { 0 }; 595 PathCombineA(CombinedPath, BaseDirectory, Name); 596 CStringA FullPath = CombinedPath; 597 FullPath.Replace('/', '\\'); /* SHPathPrepareForWriteA does not handle '/' */ 598 Retry: 599 eZipExtractError Result = ExtractSingle(hDlg, FullPath, is_dir, &Info, Name, Password, &bOverwriteAll, bCancel, &err); 600 if (Result != eDirectoryError) 601 CurrentFile++; 602 switch (Result) 603 { 604 case eNoError: 605 break; 606 607 case eExtractAbort: 608 case eUnpackError: 609 { 610 Close(); 611 return false; 612 } 613 614 case eDirectoryError: 615 { 616 char StrippedPath[MAX_PATH] = { 0 }; 617 618 StrCpyNA(StrippedPath, FullPath, _countof(StrippedPath)); 619 if (!is_dir) 620 PathRemoveFileSpecA(StrippedPath); 621 PathStripPathA(StrippedPath); 622 if (ShowExtractError(hDlg, (LPCSTR)&StrippedPath, err, eDirectoryError) == IDRETRY) 623 goto Retry; 624 Close(); 625 return false; 626 } 627 628 case eFileError: 629 { 630 int Result = ShowExtractError(hDlg, FullPath, err, eFileError); 631 switch (Result) 632 { 633 case IDABORT: 634 Close(); 635 return false; 636 case IDRETRY: 637 CurrentFile--; 638 goto Retry; 639 case IDIGNORE: 640 break; 641 } 642 break; 643 } 644 645 case eOpenError: 646 { 647 if (err == UNZ_BADZIPFILE && 648 Info.compression_method != 0 && 649 Info.compression_method != Z_DEFLATED && 650 Info.compression_method != Z_BZIP2ED) 651 { 652 if (ShowExtractError(hDlg, FullPath, Info.compression_method, eOpenError) == IDYES) 653 break; 654 } 655 Close(); 656 return false; 657 } 658 } 659 if (Result == eNoError && is_dir) 660 continue; 661 Progress.SendMessage(PBM_SETPOS, CurrentFile, 0); 662 } 663 664 Close(); 665 return true; 666 } 667 668 int ShowExtractError(HWND hDlg, LPCSTR path, int Error, eZipExtractError ErrorType) 669 { 670 CStringA strTitle(MAKEINTRESOURCEW(IDS_ERRORTITLE)); 671 CStringA strErr, strText; 672 PSTR Win32ErrorString; 673 674 if (ErrorType == eFileError || ErrorType == eOpenError) 675 strText.LoadString(IDS_CANTEXTRACTFILE); 676 else 677 strText.LoadString(GetModuleHandleA("shell32.dll"), 128); // IDS_CREATEFOLDER_DENIED 678 679 strText.FormatMessage(strText.GetString(), path); 680 681 if (ErrorType == eFileError || HRESULT_FACILITY(Error) == FACILITY_WIN32) 682 { 683 if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 684 NULL, ErrorType == eFileError ? Error : HRESULT_CODE(Error), 0, 685 (PSTR)&Win32ErrorString, 0, NULL) != 0) 686 { 687 strErr.SetString(Win32ErrorString); 688 LocalFree(Win32ErrorString); 689 } 690 } 691 if (ErrorType == eOpenError) 692 strErr.Format(IDS_DECOMPRESSERROR, Error); 693 else if (strErr.GetLength() == 0) 694 strErr.Format(IDS_UNKNOWNERROR, Error); 695 696 strText.Append("\r\n\r\n" + strErr); 697 698 UINT mbFlags = MB_ICONWARNING; 699 if (ErrorType == eDirectoryError) 700 mbFlags |= MB_RETRYCANCEL; 701 else if (ErrorType == eFileError) 702 mbFlags |= MB_ABORTRETRYIGNORE; 703 else if (ErrorType == eOpenError) 704 mbFlags |= MB_YESNO; 705 706 return MessageBoxA(hDlg, strText, strTitle, mbFlags); 707 } 708 }; 709 710 711 void _CZipExtract_runWizard(PCWSTR Filename) 712 { 713 CZipExtract extractor(Filename); 714 extractor.runWizard(); 715 } 716 717