private void PrepMsi(string msiPath, string dstDir, PaintDotNet.SystemLayer.ProcessorArchitecture platform, Hashtable msiProperties) { string dstMsiExt = "." + platform.ToString().ToLower() + ".msi"; string dstMsiName = Path.ChangeExtension(msiPath, dstMsiExt); if (!Directory.Exists(dstDir)) { Directory.CreateDirectory(dstDir); } string dstMsiPath = Path.Combine(dstDir, dstMsiName); this.statusText.Text = dstMsiName; WizardHost.Update(); File.Copy(msiPath, dstMsiPath, true); ++this.progressBar.Value; Msi.SetMsiTargetPlatform(dstMsiPath, platform); ++this.progressBar.Value; foreach (string key in msiProperties.Keys) { string value = (string)msiProperties[key]; Msi.SetMsiProperties(dstMsiPath, Msi.PropertyTable, new string[1] { key }, new string[1] { value }); ++this.progressBar.Value; } ++this.progressBar.Value; }
private void DoInstallation() { WizardHost.SetNextEnabled(false); WizardHost.SetBackEnabled(false); WizardHost.SetCancelEnabled(false); IntPtr hWnd = this.Handle; uint result = NativeMethods.MsiSetInternalUI( NativeConstants.INSTALLUILEVEL_BASIC | NativeConstants.INSTALLUILEVEL_HIDECANCEL, ref hWnd); // value of result is discarded string ourDir = PdnInfo.GetApplicationDir(); string originalPackagePath = Path.Combine(ourDir, msiName); string targetDir = WizardHost.GetMsiProperty(PropertyNames.TargetDir, null); string stagingDir = Path.Combine(targetDir, stagingDirName); // The 'old' target dir is read from the registry. // This way if they are reinstalling to a new directory, we will propertly uninstall and cleanup // from the old directory. // The 'old' target dir defaults to the 'new' target dir (in case of new installation) string oldTargetDir = WizardHost.GetMsiProperty(PropertyNames.TargetDir, targetDir, true); string oldStagingDir = Path.Combine(oldTargetDir, stagingDirName); // Uninstallers should skip certain parts of cleanup when we're going to turn around // and install a newer version right away WizardHost.SetMsiProperty(PropertyNames.SkipCleanup, "0"); // Uninstall anything already in the staging directory (should only be the previous version) if (Directory.Exists(oldStagingDir)) { this.infoText.Text = this.uninstallingText; WizardHost.SetMsiProperty(PropertyNames.SkipCleanup, "1"); foreach (string filePath in Directory.GetFiles(oldStagingDir, "*.msi")) { uint result2 = NativeMethods.MsiInstallProduct( filePath, "REMOVE=ALL " + PropertyNames.SkipCleanup + "=1 " + PropertyNames.DesktopShortcut + "=" + WizardHost.GetMsiProperty(PropertyNames.DesktopShortcut, "1")); } } // Proceed with installation this.infoText.Text = this.installingText; Directory.CreateDirectory(stagingDir); string msiPath = Path.Combine(stagingDir, msiName); string dstPackagePath = GetOriginalMsiName(msiPath); // Copy the MSI to the Staging directory before installing. This way it will always // be available when Windows Installer needs to refer to it. FileInfo info = new FileInfo(originalPackagePath); info.CopyTo(dstPackagePath, true); // Keep an open file handle so that setupngen.exe cannot delete the file. // This happens if the current installation of Paint.NET // We need to set the Target Platform property of the MSI before we install it. // This way if the user types "C:\Program Files\Whatever" on an x64 system, it will // not get redirected over to "C:\Program Files (x86)\Whatever" Msi.SetMsiTargetPlatform(dstPackagePath, PaintDotNet.SystemLayer.Processor.NativeArchitecture); string commandLine1 = WizardHost.GetMsiCommandLine(); string commandLine = commandLine1; if (commandLine.Length > 0) { commandLine += " "; } commandLine += PropertyNames.QueueNgen + "=1"; // Install newest package result = NativeMethods.MsiInstallProduct(dstPackagePath, commandLine); if (result == NativeConstants.ERROR_SUCCESS || result == NativeConstants.ERROR_SUCCESS_REBOOT_INITIATED || result == NativeConstants.ERROR_SUCCESS_REBOOT_REQUIRED) { ShowBanners(); WizardHost.SaveMsiProperties(); // clean up staging dir string msiFileName = Path.GetFileName(dstPackagePath); foreach (string filePath in Directory.GetFiles(stagingDir, "*.msi")) { string fileName = Path.GetFileName(filePath); if (0 != string.Compare(msiFileName, fileName, true, CultureInfo.InvariantCulture)) { File.Delete(filePath); } } // Run "ngen.exe executeQueuedItems", aka "Optimizing performance for your system..." if (Application.VisualStyleState == VisualStyleState.ClientAreaEnabled || Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled) { this.progressBar.Style = ProgressBarStyle.Marquee; this.progressBar.Visible = true; } string ngenExe = PdnInfo.GetNgenPath(); const string ngenArg = "executeQueuedItems"; try { this.infoText.Text = this.optimizingText; ProcessStartInfo psi = new ProcessStartInfo(ngenExe, ngenArg); psi.UseShellExecute = false; psi.CreateNoWindow = true; Process process = Process.Start(psi); while (!process.HasExited) { System.Threading.Thread.Sleep(10); Application.DoEvents(); } } catch { // If this fails, do not fail the installation } // Try to write locale setting to registry try { Settings.SystemWide.SetString("LanguageName", CultureInfo.CurrentUICulture.Name); } catch (Exception) { // Ignore errors, however } SystemSounds.Beep.Play(); WizardHost.SetFinished(true); this.progressBar.Visible = false; // set text to indicate success WizardHost.HeaderText = PdnResources.GetString("SetupWizard.InstallingPage.HeaderText.Success"); string infoFormat; if (result == NativeConstants.ERROR_SUCCESS) { WizardHost.RebootRequired = false; infoFormat = PdnResources.GetString("SetupWizard.InstallingPage.InfoText.Text.Success.Format"); } else { WizardHost.RebootRequired = true; infoFormat = PdnResources.GetString("SetupWizard.InstallingPage.InfoText.Text.Success.RebootRequired.Format"); } this.infoText.Text = string.Format(infoFormat, this.appName); WizardHost.SetBackEnabled(false); } else { WizardHost.SetFinished(true); this.progressBar.Visible = false; // set text to indicate failure WizardHost.HeaderText = PdnResources.GetString("SetupWizard.InstallingPage.HeaderText.Failure"); string infoFormat = PdnResources.GetString("SetupWizard.InstallingPage.InfoText.Text.Failure.Format"); string errorString = NativeMethods.FormatMessageW(result); this.errorLabel.Font = WizardHost.NormalTextFont; this.errorLabel.Visible = true; this.errorLabel.Text = errorString; this.infoText.Text = string.Format(infoFormat, this.appName) + " (" + result.ToString() + ")"; WizardHost.SetBackEnabled(false); } }