DWORD WINAPI InstallerThread(LPVOID data) { gGlobalData.success = false; if (!CreateInstallationDirectory()) goto Error; ProgressStep(); if (!InstallCopyFiles()) goto Error; if (gGlobalData.registerAsDefault) { // need to sublaunch SumatraPDF.exe instead of replicating the code // because registration uses translated strings ScopedMem<WCHAR> installedExePath(GetInstalledExePath()); CreateProcessHelper(installedExePath, L"-register-for-pdf"); } if (gGlobalData.installBrowserPlugin) InstallBrowserPlugin(); else if (IsBrowserPluginInstalled()) UninstallBrowserPlugin(); if (gGlobalData.installPdfFilter) InstallPdfFilter(); else if (IsPdfFilterInstalled()) UninstallPdfFilter(); if (gGlobalData.installPdfPreviewer) InstallPdfPreviewer(); else if (IsPdfPreviewerInstalled()) UninstallPdfPreviewer(); if (!CreateAppShortcut(true) && !CreateAppShortcut(false)) { NotifyFailed(_TR("Failed to create a shortcut")); goto Error; } // consider installation a success from here on // (still warn, if we've failed to create the uninstaller, though) gGlobalData.success = true; if (!WriteUninstallerRegistryInfo(HKEY_LOCAL_MACHINE) && !WriteUninstallerRegistryInfo(HKEY_CURRENT_USER)) { NotifyFailed(_TR("Failed to write the uninstallation information to the registry")); } if (!WriteExtendedFileExtensionInfo(HKEY_LOCAL_MACHINE) && !WriteExtendedFileExtensionInfo(HKEY_CURRENT_USER)) { NotifyFailed(_TR("Failed to write the extended file extension information to the registry")); } ProgressStep(); Error: // TODO: roll back installation on failure (restore previous installation!) if (gHwndFrame && !gGlobalData.silent) { Sleep(500); // allow a glimpse of the completed progress bar before hiding it PostMessage(gHwndFrame, WM_APP_INSTALLATION_FINISHED, 0, 0); } return 0; }
DWORD WINAPI UninstallerThread(LPVOID data) { // also kill the original uninstaller, if it's just spawned // a DELETE_ON_CLOSE copy from the temp directory WCHAR *exePath = GetUninstallerPath(); if (!path::IsSame(exePath, GetOwnPath())) KillProcess(exePath, TRUE); free(exePath); if (!RemoveUninstallerRegistryInfo(HKEY_LOCAL_MACHINE) && !RemoveUninstallerRegistryInfo(HKEY_CURRENT_USER)) { NotifyFailed(L"Failed to delete uninstaller registry keys"); } if (!RemoveShortcut(true) && !RemoveShortcut(false)) NotifyFailed(L"Couldn't remove the shortcut"); UninstallBrowserPlugin(); UninstallPdfFilter(); UninstallPdfPreviewer(); RemoveOwnRegistryKeys(); if (!RemoveInstalledFiles()) NotifyFailed(L"Couldn't remove installation directory"); // always succeed, even for partial uninstallations gGlobalData.success = true; if (!gGlobalData.silent) PostMessage(gHwndFrame, WM_APP_INSTALLATION_FINISHED, 0, 0); return 0; }
// Try harder getting temporary directory // Caller needs to free() the result. // Returns NULL if fails for any reason. static WCHAR *GetValidTempDir() { ScopedMem<WCHAR> d(path::GetTempPath()); if (!d) { NotifyFailed(_TR("Couldn't obtain temporary directory")); return NULL; } bool ok = dir::Create(d); if (!ok) { LogLastError(); NotifyFailed(_TR("Couldn't create temporary directory")); return NULL; } return d.StealData(); }
static bool InstallCopyFiles() { bool ok; HGLOBAL res = 0; HRSRC resSrc = FindResource(GetModuleHandle(nullptr), MAKEINTRESOURCE(1), RT_RCDATA); if (!resSrc) goto Corrupted; res = LoadResource(nullptr, resSrc); if (!res) goto Corrupted; const char *data = (const char*)LockResource(res); DWORD dataSize = SizeofResource(nullptr, resSrc); lzma::SimpleArchive archive; ok = lzma::ParseSimpleArchive(data, dataSize, &archive); if (!ok) goto Corrupted; // on error, ExtractFiles() shows error message itself ok = ExtractFiles(&archive); Exit: UnlockResource(res); return ok; Corrupted: NotifyFailed(_TR("The installer has been corrupted. Please download it again.\nSorry for the inconvenience!")); ok = false; goto Exit; }
// If this is uninstaller and we're running from installation directory, // copy uninstaller to temp directory and execute from there, exiting // ourselves. This is needed so that uninstaller can delete itself // from installation directory and remove installation directory // If returns TRUE, this is an installer and we sublaunched ourselves, // so the caller needs to exit bool ExecuteUninstallerFromTempDir() { // only need to sublaunch if running from installation dir ScopedMem<WCHAR> ownDir(path::GetDir(GetOwnPath())); ScopedMem<WCHAR> tempPath(GetTempUninstallerPath()); // no temp directory available? if (!tempPath) return false; // not running from the installation directory? // (likely a test uninstaller that shouldn't be removed anyway) if (!path::IsSame(ownDir, gGlobalData.installDir)) return false; // already running from temp directory? if (path::IsSame(GetOwnPath(), tempPath)) return false; if (!CopyFile(GetOwnPath(), tempPath, FALSE)) { NotifyFailed(L"Failed to copy uninstaller to temp directory"); return false; } ScopedMem<WCHAR> args(str::Format(L"/d \"%s\" %s", gGlobalData.installDir, gGlobalData.silent ? L"/s" : L"")); bool ok = CreateProcessHelper(tempPath, args); // mark the uninstaller for removal at shutdown (note: works only for administrators) MoveFileEx(tempPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); return ok; }
// Try harder getting temporary directory // Caller needs to free() the result. // Returns NULL if fails for any reason. static WCHAR *GetValidTempDir() { WCHAR d[MAX_PATH]; DWORD res = GetTempPath(dimof(d), d); if ((0 == res) || (res >= MAX_PATH)) { NotifyFailed(L"Couldn't obtain temporary directory"); return NULL; } BOOL success = CreateDirectory(d, NULL); if (!success && (ERROR_ALREADY_EXISTS != GetLastError())) { LogLastError(); NotifyFailed(L"Couldn't create temporary directory"); return NULL; } return str::Dup(d); }
static bool CreateInstallationDirectory() { bool ok = dir::CreateAll(gGlobalData.installDir); if (!ok) { LogLastError(); NotifyFailed(_TR("Couldn't create the installation directory")); } return ok; }
void Downloader::StoppedHandler (HttpRequest *sender, HttpRequestStoppedEventArgs *args) { SetFilename (sender->GetFilename ()); if (args->IsSuccess ()) { NotifyFinished (); } else { NotifyFailed (args->GetErrorMessage ()); } }
static bool ExtractFiles(lzma::SimpleArchive *archive) { lzma::FileInfo *fi; char *uncompressed; FileTransaction trans; for (int i = 0; gPayloadData[i].fileName; i++) { if (!gPayloadData[i].install) continue; int idx = lzma::GetIdxFromName(archive, gPayloadData[i].fileName); if (-1 == idx) { NotifyFailed(_TR("Some files to be installed are damaged or missing")); return false; } fi = &archive->files[idx]; uncompressed = lzma::GetFileDataByIdx(archive, idx, nullptr); if (!uncompressed) { NotifyFailed(_TR("The installer has been corrupted. Please download it again.\nSorry for the inconvenience!")); return false; } ScopedMem<WCHAR> filePath(str::conv::FromUtf8(fi->name)); ScopedMem<WCHAR> extPath(path::Join(gGlobalData.installDir, filePath)); bool ok = trans.WriteAll(extPath, uncompressed, fi->uncompressedSize); free(uncompressed); if (!ok) { ScopedMem<WCHAR> msg(str::Format(_TR("Couldn't write %s to disk"), filePath)); NotifyFailed(msg); return false; } trans.SetModificationTime(extPath, fi->ftModified); ProgressStep(); } return trans.Commit(); }
static bool InstallCopyFiles() { // extract all payload files one by one (transacted, if possible) ZipFile archive(GetOwnPath()); FileTransaction trans; for (int i = 0; gPayloadData[i].filepath; i++) { // skip files that are only uninstalled if (!gPayloadData[i].install) continue; ScopedMem<WCHAR> filepathT(str::conv::FromUtf8(gPayloadData[i].filepath)); size_t size; ScopedMem<char> data(archive.GetFileData(filepathT, &size)); if (!data) { NotifyFailed(L"Some files to be installed are damaged or missing"); return false; } ScopedMem<WCHAR> extpath(path::Join(gGlobalData.installDir, path::GetBaseName(filepathT))); bool ok = trans.WriteAll(extpath, data, size); if (!ok) { ScopedMem<WCHAR> msg(str::Format(L"Couldn't write %s to disk", filepathT)); NotifyFailed(msg); return false; } // set modification time to original value FILETIME ftModified = archive.GetFileTime(filepathT); trans.SetModificationTime(extpath, ftModified); ProgressStep(); } return trans.Commit(); }
static bool InstallCopyFiles() { FileInfo fileInfos[32]; HRSRC resSrc = FindResource(ghinst, MAKEINTRESOURCE(1), RT_RCDATA); CrashIf(!resSrc); HGLOBAL res = LoadResource(NULL, resSrc); CrashIf(!res); const uint8_t *data = (const uint8_t*)LockResource(res); DWORD dataSize = SizeofResource(NULL, resSrc); // extract all payload files one by one (transacted, if possible) FileTransaction trans; const int32_t *idata = (const int32_t*)data; int32_t fileCount = *idata++; CrashIf(fileCount >= dimof(fileInfos)); int32_t off = 0; for (int32_t i = 0; i < fileCount; i++) { fileInfos[i].off = off; fileInfos[i].sizeUncompressed = *idata++; fileInfos[i].sizeCompressed = *idata++; off += fileInfos[i].sizeCompressed; data = (const uint8_t*)idata; fileInfos[i].name = (const char*)data; while (*data) { ++data; } ++data; idata = (const int32_t*)data; } uint8_t *dst; for (int32_t i = 0; i < fileCount; i++) { ScopedMem<WCHAR> filepathT(str::conv::FromUtf8(fileInfos[i].name)); int32_t srcLen = fileInfos[i].sizeCompressed; off = fileInfos[i].off; const uint8_t *src = data + off; unsigned dstLen; dst = decodeLZMA((uint8_t*)src, (unsigned)srcLen, &dstLen); CrashIf(dstLen != (unsigned)fileInfos[i].sizeUncompressed); ScopedMem<WCHAR> extpath(path::Join(gGlobalData.installDir, path::GetBaseName(filepathT))); bool ok = trans.WriteAll(extpath, dst, dstLen); if (!ok) { ScopedMem<WCHAR> msg(str::Format(_TR("Couldn't write %s to disk"), filepathT)); NotifyFailed(msg); goto Error; } free(dst); // set modification time to original value //FILETIME ftModified = archive.GetFileTime(filepathT); //trans.SetModificationTime(extpath, ftModified); ProgressStep(); } UnlockResource(res); return trans.Commit(); Error: UnlockResource(res); return false; }