internal static void InvokeThroughModalTrampoline(IWin32Window owner, Procedure <IWin32Window> invokeMe) { using (Form modalityFix = new Form()) { modalityFix.ShowInTaskbar = false; modalityFix.TransparencyKey = modalityFix.BackColor; UI.SetFormOpacity(modalityFix, 0); modalityFix.ControlBox = false; modalityFix.FormBorderStyle = FormBorderStyle.None; if (owner is Control ownerAsControl) { Form ownerForm = ownerAsControl.FindForm(); if (ownerForm != null) { Rectangle clientRect = ownerForm.RectangleToScreen(ownerForm.ClientRectangle); modalityFix.Icon = ownerForm.Icon; modalityFix.Location = clientRect.Location; modalityFix.Size = clientRect.Size; modalityFix.StartPosition = FormStartPosition.Manual; } } modalityFix.Shown += delegate(object sender, EventArgs e) { invokeMe(modalityFix); modalityFix.Close(); }; modalityFix.ShowDialog(owner); GC.KeepAlive(modalityFix); } }
/// <summary> /// Repairs the installation of Paint.NET by replacing any files that have gone missing. /// This method should only be called after it has been determined that the files are missing, /// and not as a way to determine which files are missing. /// This is used, for instance, if the resource files, such as PaintDotNet.Strings.3.resources, /// cannot be found. This is actually a top support issue, and by automatically repairing /// this problem we save a lot of people a lot of trouble. /// </summary> /// <param name="missingFiles"> /// Friendly names for the files that are missing. These will not be used as part of the /// repair process but rather as part of any UI presented to the user, or in an exception that /// will be thrown in the case of an error. /// </param> /// <returns> /// true if everything was successful, false if the user cancelled or does not have administrator /// privilege (and cannot elevate). An exception is thrown for errors. /// </returns> /// <remarks> /// Note to implementors: This may be implemented as a no-op. Just return true in this case. /// </remarks> public static bool ReplaceMissingFiles(string[] missingFiles) { // Generate a friendly, comma separated list of the missing file names StringBuilder missingFilesSB = new StringBuilder(); for (int i = 0; i < missingFiles.Length; ++i) { missingFilesSB.Append(missingFiles[i]); if (i != missingFiles.Length - 1) { missingFilesSB.Append(", "); } } try { // If they are not an admin and have no possibility of elevating, such as for a standard User // in XP, then give them an error. Unfortunately we do not know if we can even load text // resources at this point, and so must provide an English-only error message. if (!Security.IsAdministrator && !Security.CanElevateToAdministrator) { MessageBox.Show( null, "Paint.NET has detected that some important installation files are missing. Repairing " + "this requires administrator privilege. Please run the 'PdnRepair.exe' program in the installation " + "directory after logging in with a user that has administrator privilege." + Environment.NewLine + Environment.NewLine + "The missing files are: " + missingFilesSB.ToString(), "Paint.NET", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } const int hMargin = 8; const int vMargin = 8; Form form = new Form(); form.Text = "Paint.NET"; form.ClientSize = new Size(400, 10); form.StartPosition = FormStartPosition.CenterScreen; Label infoLabel = new Label(); form.Controls.Add(infoLabel); infoLabel.Text = "Paint.NET has detected that some important installation files are missing. If you click " + "the Repair button it will attempt to repair this and then continue loading." + Environment.NewLine + Environment.NewLine + "The missing files are: " + missingFilesSB.ToString(); #if DEBUG infoLabel.Text += Environment.NewLine + Environment.NewLine + "*** Since this is a DEBUG build, you should probably add /skipRepairAttempt to the command-line."; #endif infoLabel.Location = new Point(hMargin, vMargin); infoLabel.Width = form.ClientSize.Width - hMargin * 2; infoLabel.Height = infoLabel.GetPreferredSize(new Size(infoLabel.Width, 1)).Height; Button repairButton = new Button(); form.Controls.Add(repairButton); repairButton.Text = "&Repair"; Exception exception = null; repairButton.Click += delegate(object sender, EventArgs e) { form.DialogResult = DialogResult.Yes; repairButton.Enabled = false; try { Shell.Execute(form, "PdnRepair.exe", "/noPause", ExecutePrivilege.AsInvokerOrAsManifest, ExecuteWaitType.WaitForExit); } catch (Exception ex) { exception = ex; } }; repairButton.AutoSize = true; repairButton.PerformLayout(); repairButton.Width += 20; repairButton.Location = new Point((form.ClientSize.Width - repairButton.Width) / 2, infoLabel.Bottom + vMargin * 2); repairButton.FlatStyle = FlatStyle.System; UI.EnableShield(repairButton, true); form.FormBorderStyle = FormBorderStyle.FixedDialog; form.MinimizeBox = false; form.MaximizeBox = false; form.ShowInTaskbar = true; form.Icon = null; form.ClientSize = new Size(form.ClientRectangle.Width, repairButton.Bottom + vMargin); DialogResult result = form.ShowDialog(null); form.Dispose(); form = null; if (result == DialogResult.Yes) { return(true); } else if (exception == null) { return(false); } else { throw new Exception("Error while attempting to repair", exception); } } catch (Exception ex) { throw new Exception("Could not repair installation after it was determined that the following files are missing: " + missingFilesSB.ToString(), ex); } }