Beispiel #1
0
        /// <summary>
        /// Attempts to find the specified XML scenario description file, either at its original
        /// location or below <see cref="ScenarioFolder"/>.</summary>
        /// <param name="file">
        /// An absolute or relative file path to an XML scenario description file.</param>
        /// <returns>
        /// A <see cref="RootedPath"/> wrapping the absolute path at which the specified <paramref
        /// name="file"/> was found.</returns>
        /// <exception cref="FileNotFoundException">
        /// The specified scenario <paramref name="file"/> could not be found anywhere.</exception>
        /// <exception cref="ArgumentNullOrEmptyException">
        /// <paramref name="file"/> is a null reference or an empty string.</exception>
        /// <remarks>
        /// <b>SearchScenarioTree</b> prepends <see cref="ScenarioFolder"/> to the specified
        /// <paramref name="file"/> if it contains a relative path. If no file exists at the
        /// resulting absolute path, <b>SearchScenarioTree</b> then attempts to find the file name
        /// anywhere in the subdirectory tree below <see cref="ScenarioFolder"/>.</remarks>

        public static RootedPath SearchScenarioTree(string file)
        {
            if (String.IsNullOrEmpty(file))
            {
                ThrowHelper.ThrowArgumentNullOrEmptyException("file");
            }

            // prepend default scenario path to relative paths
            RootedPath path = CreateCommonPath(ScenarioFolder, file);

            // check if file exists at specified location
            if (!File.Exists(path.AbsolutePath))
            {
                // look for file name in scenario directory tree
                string search = IOUtility.SearchDirectoryTree(ScenarioFolder, path.FileName);
                path = path.Change(search);

                // file not found anywhere, abort operation
                if (path.IsEmpty)
                {
                    ThrowHelper.ThrowFileNotFoundException(file, Strings.ErrorGameScenario);
                }
            }

            Debug.Assert(File.Exists(path.AbsolutePath));
            return(path);
        }
Beispiel #2
0
        /// <summary>
        /// Updates the "Subsection Locations" display for the specified <see
        /// cref="ScenarioSection"/>, which must be a subsection.</summary>
        /// <param name="section">
        /// A <see cref="ScenarioSection"/> value indicating the scenario subsection to update.
        /// </param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="section"/> equals <see cref="ScenarioSection.Master"/>.</exception>
        /// <exception cref="InvalidEnumArgumentException">
        /// <paramref name="section"/> is not a valid <see cref="ScenarioSection"/> value.
        /// </exception>
        /// <remarks>
        /// <b>UpdatePath</b> updates the "Subsection Locations" line corresponding to the specified
        /// <paramref name="section"/> to reflect its <see cref="SectionTabItem.DataChanged"/> flag
        /// and its file path within the current <see cref="MasterSection"/>.</remarks>

        public void UpdateSubsection(ScenarioSection section)
        {
            switch (section)
            {
            case ScenarioSection.Master:
                ThrowHelper.ThrowArgumentOutOfRangeExceptionWithFormat("section",
                                                                       section, Tektosyne.Strings.ArgumentEquals, ScenarioSection.Master);
                break;

            case ScenarioSection.Images:
            case ScenarioSection.Variables:
            case ScenarioSection.Entities:
            case ScenarioSection.Factions:
            case ScenarioSection.Areas:

                // show or hide change marker for section
                int index   = (int)section;
                var tabPage = MainWindow.Instance.GetTabPage(section);
                this._dataChangedLabels[index].Visibility =
                    (tabPage.DataChanged ? Visibility.Visible : Visibility.Hidden);

                // show file path or "(inline)" for section
                RootedPath path = MasterSection.Instance.SectionPaths.GetPath(section);
                this._sectionPathBoxes[index].Text =
                    (path.IsEmpty ? Global.Strings.LabelInline : path.RelativePath);
                break;

            default:
                ThrowHelper.ThrowInvalidEnumArgumentException(
                    "section", (int)section, typeof(ScenarioSection));
                break;
            }
        }
Beispiel #3
0
        /// <summary>
        /// Shows a <see cref="FileDialogs.SaveSectionDialog"/> allowing the user to enter or select
        /// an <see cref="AreaSection"/> file to save the current <see cref="WorldState"/> to.
        /// </summary>
        /// <param name="file">
        /// The file initially selected in the dialog.</param>
        /// <remarks><para>
        /// The specified <paramref name="file"/> may be a null reference or an empty string to
        /// indicate that no file should be initially selected. Otherwise, any directory prefix it
        /// contains overrides the specified <paramref name="file"/>. Files without an absolute path
        /// are interpreted as relative to the <see cref="ScenarioSection.Areas"/> section folder.
        /// </para><para>
        /// <b>SaveAreas</b> attempts to create a new <see cref="AreaSection"/> object from the <see
        /// cref="WorldState"/> of the current session, using the latter's <see
        /// cref="WorldState.CreateAreaSection"/> method, and then invokes <see
        /// cref="ScenarioElement.Save"/> on the new <see cref="AreaSection"/> object. If either
        /// operation fails, an error message is shown but no exception is thrown.</para></remarks>

        public static void SaveAreas(string file)
        {
            // abort if no world state to save
            if (Session.Instance == null)
            {
                return;
            }

            // let user select file path for Areas section
            RootedPath path = FilePaths.GetSectionFile(ScenarioSection.Areas, file);

            path = FileDialogs.SaveSectionDialog(ScenarioSection.Areas, path.AbsolutePath);
            if (path.IsEmpty)
            {
                return;
            }

            try {
                // create Areas section from world state
                AreaSection areas = Session.Instance.WorldState.CreateAreaSection(0, 0, 0, 0);
                areas.Save(path.AbsolutePath);
            }
            catch (Exception e) {
                string message = String.Format(ApplicationInfo.Culture,
                                               Global.Strings.DialogSectionSaveError, path.AbsolutePath);

                MessageDialog.Show(MainWindow.Instance, message,
                                   Global.Strings.TitleSectionError, e, MessageBoxButton.OK, Images.Error);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Handles the <see cref="ButtonBase.Click"/> event for the "Browse…" <see cref="Button"/>.
        /// </summary>
        /// <param name="sender">
        /// The <see cref="Object"/> where the event handler is attached.</param>
        /// <param name="args">
        /// An <see cref="EventArgs"/> or <see cref="RoutedEventArgs"/> object containing event
        /// data.</param>
        /// <remarks><para>
        /// <b>OnPathBrowse</b> automatically calls <see cref="Load"/> if the user specifies an
        /// existing file, and <see cref="Save"/> if the user specifies a non-existent file.
        /// </para><para>
        /// <b>OnPathBrowse</b> does nothing if the user cancels the dialog, or enters an empty path
        /// or the current <see cref="Path"/>.</para></remarks>

        private void OnPathBrowse(object sender, EventArgs args)
        {
            RoutedEventArgs routedArgs = args as RoutedEventArgs;

            if (routedArgs != null)
            {
                routedArgs.Handled = true;
            }

            // ask user to enter an existing or new file
            RootedPath path = FileDialogs.OpenSectionDialog(Section, Path, true);

            // quit if user cancelled or entered old path
            if (path == null || path.IsEmpty || path.Equals(this._path))
            {
                return;
            }

            // save to or load from new path
            if (!File.Exists(path.AbsolutePath))
            {
                Save(path.AbsolutePath);
            }
            else
            {
                // ask for confirmation to load file
                if (MainWindow.Instance.ClearData(Section))
                {
                    Load(path.AbsolutePath);
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Handles the <see cref="ButtonBase.Click"/> event for the "Browse…" <see cref="Button"/>.
        /// </summary>
        /// <param name="sender">
        /// The <see cref="Object"/> where the event handler is attached.</param>
        /// <param name="args">
        /// A <see cref="RoutedEventArgs"/> object containing event data.</param>
        /// <remarks>
        /// <b>OnPathBrowse</b> shows an <see cref="FileDialogs.OpenImageDialog"/> allowing the user
        /// to select a new <see cref="OverlayImage.Path"/>, and sets the <see cref="DataChanged"/>
        /// flag if the user selects a valid new file path.</remarks>

        private void OnPathBrowse(object sender, RoutedEventArgs args)
        {
            args.Handled = true;

            // ask user to enter an existing image
            RootedPath path = FileDialogs.OpenImageDialog(this._overlay.Path);

            // quit if user cancelled, or entered old or invalid path
            if (path == null || path.IsEmpty || path.Equals(this._overlay.Path) ||
                !File.Exists(path.AbsolutePath))
            {
                return;
            }

            // disable dialog while image loads
            IsEnabled = false;
            Dispatcher.DoEvents();

            // try loading overlay image
            this._overlay.Path = path.AbsolutePath;
            if (!AreasTabContent.MapView.ShowOverlay(this, this._editing))
            {
                path.Clear();
            }

            // broadcast data changes
            ShowImagePath();
            ShowImageSize();
            DataChanged = true;

            IsEnabled = true; // reenable dialog
        }
Beispiel #6
0
        public void Clone()
        {
            RootedPath path  = new RootedPath(@"C:\Windows", "win.ini");
            RootedPath clone = (RootedPath)path.Clone();

            Assert.AreNotSame(path, clone);
            Assert.AreEqual(path, clone);
            Assert.AreEqual(@"C:\Windows\win.ini", clone.AbsolutePath);
        }
Beispiel #7
0
        public void EquivalentPath()
        {
            RootedPath path = new RootedPath(@"C:\Windows\", @"C:/Windows");

            Assert.AreEqual(@"C:\Windows\", path.AbsolutePath);

            Assert.AreEqual("", path.RelativePath);
            Assert.IsTrue(path.IsEmpty);
            Assert.AreEqual(@"C:\Windows", path.DirectoryName);
            Assert.AreEqual("", path.FileName);
        }
Beispiel #8
0
        public void DifferentPath()
        {
            RootedPath path = new RootedPath(@"C:\Windows", @"C:\Temp\win.ini");

            Assert.AreEqual(@"C:\Windows\", path.RootFolder);
            Assert.AreEqual(@"C:\Temp\win.ini", path.AbsolutePath);

            Assert.AreEqual(@"C:\Temp\win.ini", path.RelativePath);
            Assert.IsFalse(path.IsEmpty);
            Assert.AreEqual(@"C:\Temp", path.DirectoryName);
            Assert.AreEqual("win.ini", path.FileName);
        }
Beispiel #9
0
        /// <summary>
        /// Handles the <see cref="ButtonBase.Click"/> event for the "Browse" <see cref="Button"/>
        /// next to the "Rule Script" text box.</summary>
        /// <param name="sender">
        /// The <see cref="Object"/> where the event handler is attached.</param>
        /// <param name="args">
        /// A <see cref="RoutedEventArgs"/> object containing event data.</param>
        /// <remarks><para>
        /// <b>OnRulesBrowse</b> displays an <see cref="FileDialogs.OpenRulesDialog"/> with the
        /// current contents of the "Rule Script" text box.
        /// </para><para>
        /// If the user selects a new path, <b>OnRulesBrowse</b> updates the "Rule Script" text box
        /// and the <see cref="RuleScript.Path"/> of the current <see cref="MasterSection.Rules"/>,
        /// and sets the <see cref="SectionTabItem.DataChanged"/> flag.</para></remarks>

        private void OnRulesBrowse(object sender, RoutedEventArgs args)
        {
            args.Handled = true;

            // ask user to select an existing file
            RootedPath path = FileDialogs.OpenRulesDialog(RulesPathBox.Text);

            // set new path (triggers OnRulesChanged)
            if (!path.IsEmpty)
            {
                RulesPathBox.Text = path.RelativePath;
            }
        }
Beispiel #10
0
        public void Equals()
        {
            Assert.IsTrue(RootedPath.Equals(null, null));

            RootedPath path = new RootedPath(@"C:\Windows", "win.ini");

            Assert.AreEqual(new RootedPath(@"C:\Windows"), new RootedPath(@"C:\Windows"));
            Assert.AreEqual(path, new RootedPath(@"C:\Windows", "win.ini"));

            Assert.AreNotEqual(path, null);
            Assert.AreNotEqual(path, new RootedPath(@"C:\Temp", "win.ini"));
            Assert.AreNotEqual(path, new RootedPath(@"C:\Windows", "system.ini"));
            Assert.AreNotEqual(path, new RootedPath(@"C:\", @"Windows\win.ini"));
        }
Beispiel #11
0
        /// <summary>
        /// Handles the <see cref="ButtonBase.Click"/> event for the "Add File" <see
        /// cref="Button"/>.</summary>
        /// <param name="sender">
        /// The <see cref="Object"/> where the event handler is attached.</param>
        /// <param name="args">
        /// A <see cref="RoutedEventArgs"/> object containing event data.</param>
        /// <remarks><para>
        /// <b>OnFileAdd</b> displays a <see cref="Dialog.ChangeIdentifier"/> dialog, followed by an
        /// <see cref="FileDialogs.OpenImageDialog"/>, allowing the user to define a new image file.
        /// </para><para>
        /// If the user confirmed both dialogs, <b>OnFileAdd</b> adds the new image file to the
        /// "Image File" list view and to the current <see cref="ImageSection"/>, redisplays all
        /// images, and sets the <see cref="SectionTabItem.DataChanged"/> flag.</para></remarks>

        private void OnFileAdd(object sender, RoutedEventArgs args)
        {
            args.Handled = true;

            // ask user for new image file ID
            var files  = MasterSection.Instance.Images.ImageFiles;
            var dialog = new Dialog.ChangeIdentifier("file-id",
                                                     Global.Strings.TitleImageFileIdEnter, files.ContainsKey, false);

            dialog.Owner = MainWindow.Instance;
            if (dialog.ShowDialog() != true)
            {
                return;
            }

            // retrieve new image file ID
            string id = String.Intern(dialog.Identifier);

            // ask user to select an existing image file
            RootedPath path = FileDialogs.OpenImageDialog(null);

            // return immediately if user cancelled
            if (path.IsEmpty)
            {
                return;
            }

            // construct new image file
            ImageFile file = new ImageFile(id, path.AbsolutePath);

            // try to load image file from disk
            if (!LoadImageFile(file, MasterSection.Instance.Images.MaskColor))
            {
                return;
            }

            // add image file to section table
            files.Add(id, file);

            // update list view and select new item
            FileList.Items.Refresh();
            FileList.SelectAndShow(file);

            // broadcast data changes
            ImageList.Redraw();
            EnableListButtons();
            SectionTab.DataChanged = true;
        }
Beispiel #12
0
        /// <summary>
        /// Handles the <see cref="ButtonBase.Click"/> event for the "Change Path" <see
        /// cref="Button"/>.</summary>
        /// <param name="sender">
        /// The <see cref="Object"/> where the event handler is attached.</param>
        /// <param name="args">
        /// A <see cref="RoutedEventArgs"/> object containing event data.</param>
        /// <remarks><para>
        /// <b>OnFileChange</b> displays an <see cref="FileDialogs.OpenImageDialog"/> for the first
        /// selected item in the "Image File" list view.
        /// </para><para>
        /// If the user made any changes, <b>OnFileChange</b> propagates them to the current <see
        /// cref="ImageSection"/>, redisplays all class images, and sets the <see
        /// cref="SectionTabItem.DataChanged"/> flag.</para></remarks>

        private void OnFileChange(object sender, RoutedEventArgs args)
        {
            args.Handled = true;

            // retrieve selected image, if any
            ImageFile file = FileList.SelectedItem as ImageFile;

            if (file == null)
            {
                return;
            }

            // ask user to select an existing image file
            RootedPath path = FileDialogs.OpenImageDialog(file.Path);

            // return immediately if user cancelled
            if (path.IsEmpty)
            {
                return;
            }

            // construct new image file object
            ImageFile newFile = new ImageFile(file.Id, path.AbsolutePath);

            // try to load image file from disk
            var imageSection = MasterSection.Instance.Images;

            if (!LoadImageFile(newFile, imageSection.MaskColor))
            {
                return;
            }

            // replace image file in scenario
            file.Unload();
            Debug.Assert(file.Id == newFile.Id);
            imageSection.ImageFiles[newFile.Id] = newFile;

            // broadcast data changes
            FileList.Items.Refresh();
            ImageList.Redraw();
            SectionTab.DataChanged = true;
        }
Beispiel #13
0
        /// <summary>
        /// Shows an <see cref="SaveFileDialog"/> allowing the user to enter or select a file to
        /// save.</summary>
        /// <param name="title">
        /// The title bar text for the <see cref="SaveFileDialog"/>.</param>
        /// <param name="filter">
        /// The file type filter for displayed files.</param>
        /// <param name="index">
        /// The index of the initially selected file type filter.</param>
        /// <param name="extension">
        /// The default extension for files entered by the user.</param>
        /// <param name="path">
        /// A <see cref="RootedPath"/> wrapping the absolute file path initially selected in the
        /// dialog.</param>
        /// <param name="directory">
        /// The directory initially shown in the dialog if <paramref name="path"/> is empty.</param>
        /// <returns>
        /// A <see cref="RootedPath"/> wrapping the absolute file path selected by the user, or an
        /// empty path if the user cancelled the dialog.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="path"/> is a null reference.</exception>
        /// <remarks>
        /// The specified <paramref name="path"/> may be empty to indicate that no file should be
        /// initially selected. In this case, the dialog initially shows the specified <paramref
        /// name="directory"/>, which is otherwise ignored.</remarks>

        private static RootedPath SaveDialog(string title, string filter,
                                             int index, string extension, RootedPath path, string directory)
        {
            if (path == null)
            {
                ThrowHelper.ThrowArgumentNullException("path");
            }

            SaveFileDialog dialog = new SaveFileDialog();

            dialog.DefaultExt       = extension;
            dialog.Filter           = filter;
            dialog.FilterIndex      = index;
            dialog.InitialDirectory = directory ?? "";
            dialog.RestoreDirectory = true;
            dialog.Title            = title;
            dialog.ValidateNames    = true;

            // pre-select specified file path, if any
            if (!path.IsEmpty)
            {
                dialog.InitialDirectory = path.DirectoryName;
                dialog.FileName         = path.FileName;
            }

            // allow creation of new files
            dialog.CheckFileExists = false;
            dialog.CheckPathExists = false;

            // return empty path if user cancels
            var owner = System.Windows.Application.Current.MainWindow;

            if (dialog.ShowDialog(owner) != true)
            {
                return(path.Clear());
            }

            // return selected file path
            return(path.Change(dialog.FileName));
        }
Beispiel #14
0
        /// <summary>
        /// Handles the <see cref="Application.DispatcherUnhandledException"/> event.</summary>
        /// <param name="information">
        /// Information about the <see cref="Exception"/> and the current application state, or a
        /// null reference for no available information.</param>
        /// <param name="rulesFile">
        /// The file path to the current scenario rule script, or a null reference if no such file
        /// exists.</param>
        /// <param name="saveScenario">
        /// An optional <see cref="Action{String}"/> delegate that is invoked to save the current
        /// scenario data to an XML file.</param>
        /// <param name="saveSession">
        /// An optional <see cref="Action{String}"/> delegate that is invoked to save the current
        /// session data to an XML file.</param>
        /// <remarks><para>
        /// <b>OnUnhandledException</b> creates a text file describing the error which includes the
        /// specified <paramref name="information"/>. Additionally, up to two debug XML files
        /// containing scenario and session data are created by invoking any of the supplied <see
        /// cref="Action{String}"/> delegates that are not null references.
        /// </para><para>
        /// The user is also asked to e-mail all created files, plus the specified <paramref
        /// name="rulesFile"/> if it exists, to the e-mail address specified by the <see
        /// cref="ApplicationInfo.Email"/> property via Simple MAPI, or if this fails, to send basic
        /// error information to the same address using the Explorer "mailto" method.
        /// </para><para>
        /// Finally, <b>OnUnhandledException</b> terminates the application using <see
        /// cref="Environment.Exit"/> and returns an error code of -1.</para></remarks>

        public static void OnUnhandledException(string information, string rulesFile,
                                                Action <String> saveScenario, Action <String> saveSession)
        {
            // check for original distribution package
            bool original = ApplicationInfo.IsSigned;

            // determine error and debug file names
            string errorFile    = FilePaths.CreateUserPath("FatalError.txt").AbsolutePath;
            string scenarioFile = FilePaths.GetScenarioFile(ScenarioFileType.Debug).AbsolutePath;
            string sessionFile  = FilePaths.GetSessionFile(SessionFileType.Debug).AbsolutePath;

            // create an error e-mail?
            bool wantEmail = false;

            if (original)
            {
                // ask user to create e-mail with attachments
                string message = String.Format(ApplicationInfo.Culture,
                                               Strings.DialogFatalErrorOriginal, errorFile, scenarioFile, sessionFile);

                wantEmail = ShowFatalError(message, null, true);
            }
            else
            {
                // just notify user that files are being saved
                string message = String.Format(ApplicationInfo.Culture,
                                               Strings.DialogFatalErrorModified, errorFile, scenarioFile, sessionFile);

                ShowFatalError(message, null, false);
            }

            // create state information string
            StringBuilder info = new StringBuilder();

            info.AppendFormat("{0} ", ApplicationInfo.Signature);
            info.Append(Environment.NewLine);
            info.AppendFormat("Kynosarges Signature: {0}", original);
            info.Append(Environment.NewLine);
            info.AppendFormat("Public Key Token: {0}",
                              StringUtility.Validate(ApplicationInfo.PublicKeyToken));
            info.Append(Environment.NewLine);
            info.AppendFormat("Home: \"{0}\" ", FilePaths.ApplicationFolder);
            info.Append(Environment.NewLine);
            info.Append(Environment.NewLine);
            info.AppendFormat("{0} ", Environment.OSVersion);
            info.Append(Environment.NewLine);
            info.AppendFormat("{0} ", WindowsUtility.GetMemoryStatus());
            info.Append(Environment.NewLine);
            info.Append(Environment.NewLine);

            // append additional information if specified
            if (!String.IsNullOrEmpty(information))
            {
                info.AppendFormat("{0} ", information);
                info.Append(Environment.NewLine);
            }

            // create subject for e-mail message
            string subject = String.Concat(ApplicationInfo.Signature, " ", Strings.LabelError);

            // collection to hold file attachment data
            List <MapiAddress> files = new List <MapiAddress>();

            try {
                try {
                    // always create error information file
                    files.Add(new MapiAddress(Path.GetFileName(errorFile), errorFile));
                    using (StreamWriter writer = new StreamWriter(errorFile, false, Encoding.UTF8))
                        writer.WriteLine(info.ToString());

                    // attach rule script file if specified
                    RootedPath rulesPath = FilePaths.CreateCommonPath(rulesFile);
                    if (!rulesPath.IsEmpty && File.Exists(rulesPath.AbsolutePath))
                    {
                        files.Add(new MapiAddress(rulesPath.FileName, rulesPath.AbsolutePath));
                    }

                    // create scenario debug file if possible
                    if (saveScenario != null)
                    {
                        saveScenario(scenarioFile);
                        files.Add(new MapiAddress(Path.GetFileName(scenarioFile), scenarioFile));
                    }

                    // create session debug file if possible
                    if (saveSession != null)
                    {
                        saveSession(sessionFile);
                        files.Add(new MapiAddress(Path.GetFileName(sessionFile), sessionFile));
                    }
                }
                catch (Exception e) {
                    // only proceed if user wanted e-mail
                    if (wantEmail)
                    {
                        // ask user to try simpler e-mail format
                        wantEmail = ShowFatalError(Strings.DialogFatalErrorSaveMail, e, true);
                        throw; // rethrow to try mailto:
                    }

                    // user declined e-mail, just show error
                    ShowFatalError(Strings.DialogFatalErrorSave, e, false);
                    return; // quit, nothing else to do
                }

                // quit now if user declined e-mail
                if (!wantEmail)
                {
                    return;
                }

                try {
                    // address e-mail to application author
                    MapiAddress recipient = new MapiAddress(
                        ApplicationInfo.Company, ApplicationInfo.Email);

                    // try sending e-mail with attached files
                    MapiMail.SendMail(subject, "", new[] { recipient }, files.ToArray());
                }
                catch (Exception e) {
                    // quit if user cancelled MAPI session
                    MapiException me = e as MapiException;
                    if (me != null && me.Code == MapiException.Abort)
                    {
                        return;
                    }

                    // ask user to try simpler e-mail format
                    wantEmail = ShowFatalError(Strings.DialogFatalErrorMail, e, true);
                    throw; // rethrow to try mailto:
                }
            }
            catch {
                // quit now if user declined e-mail
                if (!wantEmail)
                {
                    return;
                }

                // construct shell command to create e-mail
                string mailto = String.Format(CultureInfo.InvariantCulture,
                                              "mailto:{0}?subject={1}&body={2}", ApplicationInfo.Email, subject, info);

                try {
                    // request default e-mail client
                    Process.Start(mailto);
                }
                catch (Exception e) {
                    ShowExplorerError(null, Strings.DialogExplorerMailError, e);
                }
            }
            finally {
                // quit application upon return
                Environment.Exit(-1);
            }
        }
Beispiel #15
0
 public void ConstructorFailed()
 {
     RootedPath path = new RootedPath("Windows", "win.ini");
 }