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