class CExtractSettingsPage : public CPropertyPageImpl<CExtractSettingsPage>
{
private:
+ HANDLE m_hExtractionThread;
+ bool m_bExtractionThreadCancel;
+
CZipExtract* m_pExtract;
CStringA* m_pPassword;
public:
CExtractSettingsPage(CZipExtract* extract, CStringA* password)
:CPropertyPageImpl<CExtractSettingsPage>(MAKEINTRESOURCE(IDS_WIZ_TITLE))
+ ,m_hExtractionThread(NULL)
+ ,m_bExtractionThreadCancel(false)
,m_pExtract(extract)
,m_pPassword(password)
{
int OnWizardNext()
{
+ if (m_hExtractionThread != NULL)
+ {
+ /* We enter here when extraction has finished, and go to next page if it succeeded */
+ WaitForSingleObject(m_hExtractionThread, INFINITE);
+ CloseHandle(m_hExtractionThread);
+ m_hExtractionThread = NULL;
+ m_pExtract->Release();
+ if (!m_bExtractionThreadCancel)
+ {
+ return 0;
+ }
+ else
+ {
+ SetWindowLongPtr(DWLP_MSGRESULT, -1);
+ return TRUE;
+ }
+ }
+
+ /* We end up here if the user manually clicks Next: start extraction */
+ m_bExtractionThreadCancel = false;
+
+ /* Grey out every control during extraction to prevent user interaction */
::EnableWindow(GetDlgItem(IDC_BROWSE), FALSE);
::EnableWindow(GetDlgItem(IDC_DIRECTORY), FALSE);
::EnableWindow(GetDlgItem(IDC_PASSWORD), FALSE);
SetWizardButtons(0);
+ CStringW strExtracting(MAKEINTRESOURCEW(IDS_EXTRACTING));
+ SetDlgItemTextW(IDC_STATUSTEXT, strExtracting);
+
if (m_pExtract->m_DirectoryChanged)
UpdateDirectory();
- if (!m_pExtract->Extract(m_hWnd, GetDlgItem(IDC_PROGRESS)))
+ m_pExtract->AddRef();
+
+ m_hExtractionThread = CreateThread(NULL, 0,
+ &CExtractSettingsPage::ExtractEntry,
+ this,
+ 0, NULL);
+ if (!m_hExtractionThread)
{
- /* Extraction failed, do not go to the next page */
+ /* Extraction thread creation failed, do not go to the next page */
+ DWORD err = GetLastError();
+ DPRINT1("ERROR, m_hExtractionThread: CreateThread failed: 0x%x\n", err);
+ m_pExtract->Release();
+
SetWindowLongPtr(DWLP_MSGRESULT, -1);
::EnableWindow(GetDlgItem(IDC_BROWSE), TRUE);
::EnableWindow(GetDlgItem(IDC_DIRECTORY), TRUE);
::EnableWindow(GetDlgItem(IDC_PASSWORD), TRUE);
SetWizardButtons(PSWIZB_NEXT);
+ }
+ return TRUE;
+ }
- return TRUE;
+ static DWORD WINAPI ExtractEntry(LPVOID lpParam)
+ {
+ CExtractSettingsPage* pPage = (CExtractSettingsPage*)lpParam;
+ bool res = pPage->m_pExtract->Extract(pPage->m_hWnd, pPage->GetDlgItem(IDC_PROGRESS), &(pPage->m_bExtractionThreadCancel));
+ /* Failing and cancelling extraction both mean we stay on the same property page */
+ pPage->m_bExtractionThreadCancel = !res;
+
+ pPage->SetWizardButtons(PSWIZB_NEXT);
+ if (!res)
+ {
+ /* Extraction failed/cancelled: the page becomes interactive again */
+ ::EnableWindow(pPage->GetDlgItem(IDC_BROWSE), TRUE);
+ ::EnableWindow(pPage->GetDlgItem(IDC_DIRECTORY), TRUE);
+ ::EnableWindow(pPage->GetDlgItem(IDC_PASSWORD), TRUE);
+
+ /* Reset the progress bar's appearance */
+ CWindow Progress(pPage->GetDlgItem(IDC_PROGRESS));
+ Progress.SendMessage(PBM_SETRANGE32, 0, 1);
+ Progress.SendMessage(PBM_SETPOS, 0, 0);
}
+ SendMessageCallback(pPage->GetParent().m_hWnd, PSM_PRESSBUTTON, PSBTN_NEXT, 0, NULL, NULL);
+
return 0;
}
+
+ BOOL OnQueryCancel()
+ {
+ if (m_hExtractionThread != NULL)
+ {
+ /* Extraction will check the value of m_bExtractionThreadCancel between each file in the archive */
+ m_bExtractionThreadCancel = true;
+ return TRUE;
+ }
+ return FALSE;
+ }
struct browse_info
{
PropertySheetW(&psh);
}
- bool Extract(HWND hDlg, HWND hProgress)
+ bool Extract(HWND hDlg, HWND hProgress, const bool* bCancel)
{
unz_global_info64 gi;
uf = unzOpen2_64(m_Filename.GetString(), &g_FFunc);
bool bOverwriteAll = false;
while (zipEnum.next(Name, Info))
{
+ if (*bCancel)
+ {
+ Close();
+ return false;
+ }
+
bool is_dir = Name.GetLength() > 0 && Name[Name.GetLength()-1] == '/';
char CombinedPath[MAX_PATH * 2] = { 0 };
do
{
+ if (*bCancel)
+ {
+ CloseHandle(hFile);
+ BOOL deleteResult = DeleteFileA(FullPath);
+ if (deleteResult == 0)
+ DPRINT1("ERROR, DeleteFileA: 0x%x\n", GetLastError());
+ Close();
+ return false;
+ }
+
err = unzReadCurrentFile(uf, Buffer, sizeof(Buffer));
if (err < 0)
LocalFileTimeToFileTime(&LocalFileTime, &FileTime);
SetFileTime(hFile, &FileTime, &LastAccessTime, &FileTime);
- /* Done.. */
+ /* Done */
CloseHandle(hFile);
if (err)