source: trunk/eraser/Eraser/Program.cs @ 2538

Revision 2538, 24.5 KB checked in by lowjoel, 2 years ago (diff)

Move the call to Application.EnableVisualStyles? to the start of the program so that if a console window creates a WinForm?, it would have the correct behaviour.
Fixing this bug also fixes the drawing problems associated with the display of the shell erase confirmation dialog.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Rev URL
Line 
1/*
2 * $Id$
3 * Copyright 2008-2012 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Windows.Forms;
25
26using System.IO;
27using System.Threading;
28using System.Globalization;
29using System.ComponentModel;
30using System.Runtime.Serialization;
31using System.Security.Principal;
32using System.Text.RegularExpressions;
33using System.Text;
34
35using System.Reflection;
36using System.Diagnostics;
37
38using ComLib.Arguments;
39
40using Eraser.Manager;
41using Eraser.Util;
42using Eraser.Plugins;
43using Eraser.Plugins.ExtensionPoints;
44using Eraser.Plugins.Registrars;
45
46namespace Eraser
47{
48    internal static partial class Program
49    {
50        /// <summary>
51        /// The common program arguments shared between the GUI and console programs.
52        /// </summary>
53        class Arguments
54        {
55            /// <summary>
56            /// True if the program should not be started with any user-visible interfaces.
57            /// </summary>
58            /// <remarks>Errors will also be silently ignored.</remarks>
59            [Arg("quiet", "q", "The program should not be started with any user-visible " +
60                "interfaces. Errors will be silently ignored.", typeof(bool), false, false)]
61            public bool Quiet { get; set; }
62        }
63
64        /// <summary>
65        /// Program arguments which only apply to the GUI program.
66        /// </summary>
67        class GuiArguments : Arguments
68        {
69            /// <summary>
70            /// True if the command line specified atRestart, which should result in the
71            /// queueing of tasks meant for running at restart.
72            /// </summary>
73            [Arg("atRestart",  "r", "The program should queue all tasks scheduled for " +
74                "running at the system restart.", typeof(bool), false, false)]
75            public bool AtRestart { get; set; }
76        }
77
78        class ConsoleArguments : Arguments
79        {
80            /// <summary>
81            /// Constructor.
82            /// </summary>
83            public ConsoleArguments()
84            {
85            }
86
87            /// <summary>
88            /// Copy constructor.
89            /// </summary>
90            /// <param name="arguments">The <see cref="ConsoleArguments"/> to use as a template
91            /// for this instance.</param>
92            protected ConsoleArguments(ConsoleArguments arguments)
93            {
94                Action = arguments.Action;
95                PositionalArguments = arguments.PositionalArguments;
96            }
97
98            /// <summary>
99            /// The Action which this handler is in charge of.
100            /// </summary>
101            [Arg(0, "The action this command line is stating.", typeof(string), true, null)]
102            public string Action { get; set; }
103
104            /// <summary>
105            /// The list of command line parameters not placed in a switch.
106            /// </summary>
107            public List<string> PositionalArguments { get; set; }
108        }
109       
110        class EraseArguments : ConsoleArguments
111        {
112            /// <summary>
113            /// Constructor.
114            /// </summary>
115            public EraseArguments()
116            {
117            }
118
119            /// <summary>
120            /// Copy constructor.
121            /// </summary>
122            /// <param name="arguments">The <see cref="EraseArguments"/> to use as a template
123            /// for this instance.</param>
124            protected EraseArguments(EraseArguments arguments)
125                : base(arguments)
126            {
127                ErasureMethod = arguments.ErasureMethod;
128            }
129
130            /// <summary>
131            /// The erasure method which the user specified on the command line.
132            /// </summary>
133            [Arg("method", "m", "The erasure method to use", typeof(string), false, null)]
134            public string ErasureMethod { get; set; }
135        }
136       
137        class TaskArguments : EraseArguments
138        {
139            /// <summary>
140            /// Constructor.
141            /// </summary>
142            public TaskArguments()
143            {
144            }
145
146            /// <summary>
147            /// Constructs Task arguments from Erase arguments.
148            /// </summary>
149            /// <param name="arguments">The <see cref="EraseArguments"/> to use as a template
150            /// for this instance.</param>
151            internal TaskArguments(EraseArguments arguments)
152                : base(arguments)
153            {
154            }
155
156            /// <summary>
157            /// The schedule for the current set of targets.
158            /// </summary>
159            [Arg("schedule", "s", "The schedule to use", typeof(Schedule), false, null)]
160            public string Schedule { get; set; }
161        }
162       
163        class ShellArguments : TaskArguments
164        {
165            /// <summary>
166            /// The parent HWND which can be used as a parent to display dialogs.
167            /// </summary>
168            [Arg("parent", "p", "The parent HWND which can be used as a parent to display " +
169                "dialogues", typeof(string), false, null)]
170            public string Parent { get; set; }
171
172            /// <summary>
173            /// Whether we should display a confirmation dialog.
174            /// </summary>
175            [Arg("confirm", "c", "Whether a confirmation dialog should be shown", typeof(bool),
176                false, true)]
177            public bool Confirm { get; set; }
178        }
179
180        public enum ShellActions
181        {
182            /// <summary>
183            /// Erase the selected items now.
184            /// </summary>
185            EraseNow,
186
187            /// <summary>
188            /// Erase the selected items on restart.
189            /// </summary>
190            EraseOnRestart,
191
192            /// <summary>
193            /// Erase the unused space on the drive.
194            /// </summary>
195            EraseUnusedSpace,
196
197            /// <summary>
198            /// Securely moves a file from one drive to another (simple rename if the source and
199            /// destination drives are the same)
200            /// </summary>
201            SecureMove
202        }
203
204        /// <summary>
205        /// The main entry point for the application.
206        /// </summary>
207        [STAThread]
208        static int Main(string[] rawCommandLine)
209        {
210            //Immediately parse command line arguments. Start by substituting all
211            //response files ("@filename") arguments with the arguments found in the
212            //file
213            List<string> commandLine = new List<string>(rawCommandLine.Length);
214            foreach (string argument in rawCommandLine)
215            {
216                if (argument[0] == '@' && File.Exists(argument.Substring(1)))
217                {
218                    //The current parameter is a response file, parse the file
219                    //for arguments and substitute it.
220                    using (TextReader reader = new StreamReader(argument.Substring(1)))
221                    {
222                        commandLine.AddRange(Shell.ParseCommandLine(reader.ReadToEnd()));
223                    }
224                }
225                else
226                    commandLine.Add(argument);
227            }
228
229            string[] finalCommandLine = commandLine.ToArray();
230            ComLib.BoolMessageItem argumentParser = Args.Parse(finalCommandLine,
231                CommandLinePrefixes, CommandLineSeparators);
232            Args parsedArguments = (Args)argumentParser.Item;
233
234            //Set application defaults for consistent behaviour across GUI and
235            //Console instances
236            Application.EnableVisualStyles();
237            Application.SetCompatibleTextRenderingDefault(false);
238
239            //Load the Eraser.Manager library
240            using (ManagerLibrary library = new ManagerLibrary(Settings.Get()))
241            {
242                //Set our UI language
243                EraserSettings settings = EraserSettings.Get();
244                Thread.CurrentThread.CurrentUICulture = new CultureInfo(settings.Language);
245
246                //We default to a GUI if:
247                // - The parser did not succeed.
248                // - The parser resulted in an empty arguments list
249                // - The parser's argument at index 0 is not equal to the first argument
250                //   (this is when the user is passing GUI options -- command line options
251                //   always start with the action, e.g. Eraser help, or Eraser addtask
252                if (!argumentParser.Success || parsedArguments.IsEmpty ||
253                    parsedArguments.Positional.Count == 0 ||
254                    parsedArguments.Positional[0] != parsedArguments.Raw[0])
255                {
256                    GUIMain(finalCommandLine);
257                }
258                else
259                {
260                    return CommandMain(finalCommandLine);
261                }
262            }
263
264            //Return zero to signify success
265            return 0;
266        }
267
268        #region Console Program code
269        /// <summary>
270        /// Connects to the running Eraser instance for erasures.
271        /// </summary>
272        /// <returns>The connectin with the remote instance.</returns>
273        private static RemoteExecutorClient CommandConnect()
274        {
275            try
276            {
277                RemoteExecutorClient result = new RemoteExecutorClient();
278                result.Run();
279                if (!result.IsConnected)
280                {
281                    //The client cannot connect to the server. This probably means
282                    //that the server process isn't running. Start an instance.
283                    Process eraserInstance = Process.Start(
284                        Assembly.GetExecutingAssembly().Location, "/quiet");
285                    eraserInstance.WaitForInputIdle();
286
287                    //Wait for the server to be initialised.
288                    for (int i = 0; !result.IsConnected; ++i)
289                    {
290                        Thread.Sleep(100);
291                        result.Run();
292
293                        //After 10s, we should probably give up.
294                        if (i > 100)
295                            throw new IOException(S._("Eraser cannot connect to the running " +
296                                "instance for erasures."));
297                    }
298                }
299
300                return result;
301            }
302            catch (UnauthorizedAccessException e)
303            {
304                //We can't connect to the pipe because the other instance of Eraser
305                //is running with higher privileges than this instance.
306                throw new UnauthorizedAccessException(S._("Another instance of Eraser " +
307                    "is already running but it is running with higher privileges than " +
308                    "this instance of Eraser. Tasks cannot be added in this manner.\n\n" +
309                    "Close the running instance of Eraser and start it again without " +
310                    "administrator privileges, or run the command again as an " +
311                    "administrator.", e));
312            }
313        }
314
315        /// <summary>
316        /// Runs Eraser as a command-line application.
317        /// </summary>
318        /// <param name="commandLine">The command line parameters passed to Eraser.</param>
319        private static int CommandMain(string[] commandLine)
320        {
321            using (ConsoleProgram program = new ConsoleProgram(commandLine))
322                try
323                {
324                    program.Handlers.Add("help",
325                        new ConsoleActionData(CommandHelp, new ConsoleArguments()));
326                    program.Handlers.Add("erase",
327                        new ConsoleActionData(CommandErase, new EraseArguments())); 
328                    program.Handlers.Add("addtask",
329                        new ConsoleActionData(CommandAddTask, new TaskArguments()));
330                    program.Handlers.Add("importtasklist",
331                        new ConsoleActionData(CommandImportTaskList, new ConsoleArguments()));
332                    program.Handlers.Add("shell",
333                        new ConsoleActionData(CommandShell, new ShellArguments()));
334                    program.Run();
335                    return 0;
336                }
337                catch (UnauthorizedAccessException)
338                {
339                    return Win32ErrorCode.AccessDenied;
340                }
341                catch (Win32Exception e)
342                {
343                    Console.WriteLine(e.Message);
344                    return e.ErrorCode;
345                }
346                catch (Exception e)
347                {
348                    Console.WriteLine(e.Message);
349                    throw;
350                }
351        }
352
353        /// <summary>
354        /// Prints the command line help for Eraser.
355        /// </summary>
356        private static void PrintCommandHelp()
357        {
358            //Get the command-line help for every erasure target
359            StringBuilder targets = new StringBuilder();
360            foreach (IErasureTarget target in Host.Instance.ErasureTargetFactories)
361            {
362                //Replace all \r\n with \n, and split into lines
363                string[] helpText = target.Configurer.Help().Replace("\r\n", "\n").Split('\r', '\n');
364
365                //Pad the start of each line with spaces
366                foreach (string line in helpText)
367                    targets.AppendLine(line.Insert(0, "    "));
368            }
369
370            //Get the list of registered Erasure Methods. First, output the header.
371            const string methodFormat = "    {0,-2} {1,-35} {2}\n";
372            StringBuilder methods = new StringBuilder();
373            methods.AppendFormat(methodFormat, "", "Erasure Method", "GUID");
374            methods.AppendLine("    " + new string('-', 75));
375
376            //Generate the list of erasure methods.
377            foreach (IErasureMethod method in Host.Instance.ErasureTargetFactories)
378            {
379                methods.AppendFormat(methodFormat, (method is IUnusedSpaceErasureMethod) ?
380                    "U" : "", method.Name, method.Guid);
381            }
382
383            //Print the message
384            Console.WriteLine(S._(@"usage: Eraser <action> <arguments>
385where action is
386  help                Show this help message.
387  erase               Erases items specified on the command line. This is
388                      equivalent to addtask, with the schedule set to ""now"".
389  addtask             Adds a task to the current task list.
390  importtasklist      Imports an Eraser Task list to the current user's Task
391                      List.
392
393global parameters:
394  /quiet              Do not create a Console window to display progress.
395
396parameters for help:
397  eraser help
398
399  no parameters to set.
400
401parameters for erase and addtask:
402  eraser erase [/method=(<methodGUID>|<methodName>)] <target> [target [...]]
403  eraser addtask [/method=(<methodGUID>|<methodName>)] [/schedule=(now|manually|restart)] <target> [target [...]]
404
405  /method             The Erasure method to use.
406    methodGUID and methodName can be any GUID/Name from the following list:
407{0}
408    Only erasure methods labelled ""U"" can be used to erase unused disk space.
409
410  /schedule           The schedule the task will follow. The value must be one
411                      of:
412    now               The task will be queued for immediate execution.
413    manually          The task will be created but not queued for execution.
414    restart           The task will be queued for execution when the computer
415                      is next restarted.
416
417                      This parameter is only valid for use with ""addtask"".
418
419  target is one or more of:
420{1}
421parameters for importtasklist:
422  eraser importtasklist <file>[...]
423
424    file               A list of one or more files to import.
425
426All arguments are case sensitive.
427
428Response files can be used for very long command lines (generally, anything
429involving more than 32,000 characters.) Response files are used by prepending
430""@"" to the path to the file, and passing it into the command line. The
431contents of the response files' will be substituted at the same position into
432the command line.", methods, targets));
433
434            Console.Out.Flush();
435        }
436
437        /// <summary>
438        /// Prints the help text for Eraser (with copyright)
439        /// </summary>
440        /// <param name="arguments">Not used.</param>
441        private static void CommandHelp(ConsoleArguments arguments)
442        {
443            Console.WriteLine(S._(@"Eraser {0}
444(c) 2008-2012 The Eraser Project
445Eraser is Open-Source Software: see http://eraser.heidi.ie/ for details.
446", BuildInfo.AssemblyFileVersion));
447
448            PrintCommandHelp();
449        }
450
451        /// <summary>
452        /// Parses the command line for tasks and adds them to run immediately
453        /// using the <see cref="RemoveExecutor"/> class.
454        /// </summary>
455        /// <param name="arg">The command line parameters passed to the program.</param>
456        private static void CommandErase(ConsoleArguments arg)
457        {
458            TaskArguments arguments = new TaskArguments((EraseArguments)arg);
459            arguments.Schedule = "NOW";
460
461            CommandAddTask(arguments);
462        }
463
464        /// <summary>
465        /// Parses the command line for tasks and adds them using the
466        /// <see cref="RemoteExecutor"/> class.
467        /// </summary>
468        /// <param name="arg">The command line parameters passed to the program.</param>
469        private static void CommandAddTask(ConsoleArguments arg)
470        {
471            TaskArguments arguments = (TaskArguments)arg;
472            Task task = TaskFromCommandLine(arguments);
473
474            //Send the task out.
475            using (eraserClient = CommandConnect())
476                eraserClient.Tasks.Add(task);
477        }
478
479        /// <summary>
480        /// Parses the command line for erasure targets and returns them as
481        /// a Task object.
482        /// </summary>
483        /// <param name="arguments">The arguments specified on the command line.</param>
484        /// <returns>The task represented on the command line.</returns>
485        private static Task TaskFromCommandLine(TaskArguments arguments)
486        {
487            //Create the task
488            Task task = new Task();
489
490            //Get the erasure method the user wants to use
491            IErasureMethod method = string.IsNullOrEmpty(arguments.ErasureMethod) ?
492                ErasureMethodRegistrar.Default :
493                ErasureMethodFromNameOrGuid(arguments.ErasureMethod);
494
495            //Define the schedule
496            switch (arguments.Schedule.ToUpperInvariant())
497            {
498                case "":
499                case "NOW":
500                    task.Schedule = Schedule.RunNow;
501                    break;
502                case "MANUALLY":
503                    task.Schedule = Schedule.RunManually;
504                    break;
505                case "RESTART":
506                    task.Schedule = Schedule.RunOnRestart;
507                    break;
508                default:
509                    throw new ArgumentException(
510                        S._("Unknown schedule type: {0}", arguments.Schedule), "/schedule");
511            }
512
513            //Parse the rest of the command line parameters as target expressions.
514            foreach (string argument in arguments.PositionalArguments)
515            {
516                IErasureTarget selectedTarget = null;
517
518                //Iterate over every defined erasure target
519                foreach (IErasureTarget target in Host.Instance.ErasureTargetFactories)
520                {
521                    //See if this argument can be handled by the target's configurer
522                    IErasureTargetConfigurer configurer = target.Configurer;
523                    if (configurer.ProcessArgument(argument))
524                    {
525                        //Check whether a target has been set (implicitly: check whether two
526                        //configurers can process the argument)
527                        if (selectedTarget == null)
528                        {
529                            configurer.SaveTo(target);
530                            selectedTarget = target;
531                        }
532                        else
533                        {
534                            //Yes, it is an ambiguity. Throw an error.
535                            throw new ArgumentException(S._("Ambiguous argument: {0} can be " +
536                                "handled by more than one erasure target.", argument));
537                        }
538                    }
539                }
540
541                //Check whether a target has been made from parsing the entry.
542                if (selectedTarget == null)
543                {
544                    Console.WriteLine(S._("Unknown argument: {0}, skipped.", argument));
545                }
546                else
547                {
548                    selectedTarget.Method = method;
549                    task.Targets.Add(selectedTarget);
550                }
551            }
552
553            //Check the number of tasks in the task.
554            if (task.Targets.Count == 0)
555                throw new ArgumentException(S._("Tasks must contain at least one erasure target."));
556
557            return task;
558        }
559
560        private static IErasureMethod ErasureMethodFromNameOrGuid(string param)
561        {
562            try
563            {
564                return Host.Instance.ErasureMethods[new Guid(param)];
565            }
566            catch (FormatException)
567            {
568                //Invalid GUID. Check every registered erasure method for the name
569                string upperParam = param.ToUpperInvariant();
570                IErasureMethod result = null;
571                foreach (IErasureMethod method in Host.Instance.ErasureMethods)
572                {
573                    if (method.Name.ToUpperInvariant() == upperParam)
574                        if (result == null)
575                            result = method;
576                        else
577                            throw new ArgumentException(S._("Ambiguous erasure method name: {0} " +
578                                "identifies more than one erasure method.", param));
579                }
580            }
581
582            throw new ArgumentException(S._("The provided Erasure Method '{0}' does not exist.",
583                param));
584        }
585
586        /// <summary>
587        /// Imports the given tasklists and adds them to the global Eraser instance.
588        /// </summary>
589        /// <param name="args">The list of files specified on the command line.</param>
590        private static void CommandImportTaskList(ConsoleArguments args)
591        {
592            //Import the task list
593            using (eraserClient = CommandConnect())
594                foreach (string path in args.PositionalArguments)
595                    using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
596                        eraserClient.Tasks.LoadFromStream(stream);
597        }
598
599        /// <summary>
600        /// Handles the files from the Shell extension.
601        /// </summary>
602        /// <param name="args">The command line parameters passed to the program.</param>
603        private static void CommandShell(ConsoleArguments args)
604        {
605            ShellArguments arguments = (ShellArguments)args;
606            Task task = TaskFromCommandLine(arguments);
607
608            //Confirm that the user wants the erase.
609            if (arguments.Confirm)
610            {
611                //Do we have a parent dialog?
612                IWin32Window parent = null;
613                if (!string.IsNullOrEmpty(arguments.Parent))
614                {
615                    parent = new Win32Window((IntPtr)(ulong)
616                        Convert.ChangeType(arguments.Parent, typeof(ulong)));
617                }
618
619                using (Form dialog = new ShellConfirmationDialog(task))
620                {
621                    if (dialog.ShowDialog(parent) != DialogResult.Yes)
622                        return;
623                }
624            }
625
626            //Then queue for erasure.
627            using (eraserClient = CommandConnect())
628                eraserClient.Tasks.Add(task);
629        }
630        #endregion
631
632        #region GUI Program code
633        /// <summary>
634        /// Runs Eraser as a GUI application.
635        /// </summary>
636        /// <param name="commandLine">The command line parameters passed to Eraser.</param>
637        private static void GUIMain(string[] commandLine)
638        {
639            //Create a unique program instance ID for this user.
640            string instanceId = "Eraser-BAD0DAC6-C9EE-4acc-8701-C9B3C64BC65E-GUI-" +
641                WindowsIdentity.GetCurrent().User.ToString();
642
643            //Then initialise the instance and initialise the Manager library.
644            using (GuiProgram program = new GuiProgram(commandLine, instanceId))
645            {
646                program.InitInstance += OnGUIInitInstance;
647                program.NextInstance += OnGUINextInstance;
648                program.ExitInstance += OnGUIExitInstance;
649                program.Run();
650            }
651        }
652
653        /// <summary>
654        /// Triggered when the Program is started for the first time.
655        /// </summary>
656        /// <param name="sender">The sender of the object.</param>
657        /// <param name="e">Event arguments.</param>
658        private static void OnGUIInitInstance(object sender, InitInstanceEventArgs e)
659        {
660            GuiProgram program = (GuiProgram)sender;
661            eraserClient = new RemoteExecutorServer();
662            Application.SafeTopLevelCaptionFormat = S._("Eraser");
663
664            //Load the task list
665            try
666            {
667                if (File.Exists(TaskListPath))
668                {
669                    using (FileStream stream = new FileStream(TaskListPath, FileMode.Open,
670                        FileAccess.Read, FileShare.Read))
671                    {
672                        eraserClient.Tasks.LoadFromStream(stream);
673                    }
674                }
675            }
676            catch (InvalidDataException ex)
677            {
678                File.Delete(TaskListPath);
679                MessageBox.Show(S._("Could not load task list. All task entries have " +
680                    "been lost. The error returned was: {0}", ex.Message), S._("Eraser"),
681                    MessageBoxButtons.OK, MessageBoxIcon.Error,
682                    MessageBoxDefaultButton.Button1,
683                    Localisation.IsRightToLeft(null) ?
684                        MessageBoxOptions.RtlReading | MessageBoxOptions.RightAlign : 0);
685            }
686
687            //Decide whether to display any UI.
688            GuiArguments arguments = new GuiArguments();
689            Args.Parse(program.CommandLine, CommandLinePrefixes, CommandLineSeparators, arguments);
690            e.ShowMainForm = !arguments.AtRestart && !arguments.Quiet;
691
692            //Queue tasks meant for running at restart if we are given that command line.
693            if (arguments.AtRestart)
694                eraserClient.QueueRestartTasks();
695
696            //Run the eraser client.
697            eraserClient.Run();
698
699            //Create the main form.
700            program.MainForm = new MainForm();
701        }
702
703        /// <summary>
704        /// Triggered when a second instance of Eraser is started.
705        /// </summary>
706        /// <param name="sender">The sender of the event.</param>
707        /// <param name="e">Event argument.</param>
708        private static void OnGUINextInstance(object sender, NextInstanceEventArgs e)
709        {
710            //Another instance of the GUI Program has been started: show the main window
711            //now as we still do not have a facility to handle the command line arguments.
712            GuiProgram program = (GuiProgram)sender;
713
714            //Invoke the function if we aren't on the main thread
715            if (program.MainForm.InvokeRequired)
716            {
717                program.MainForm.Invoke(
718                    (GuiProgram.NextInstanceEventHandler)OnGUINextInstance,
719                    sender, e);
720                return;
721            }
722
723            program.MainForm.Show();
724        }
725
726        /// <summary>
727        /// Triggered when the first instance of Eraser is exited.
728        /// </summary>
729        /// <param name="sender">The sender of the event.</param>
730        /// <param name="e">Event argument.</param>
731        private static void OnGUIExitInstance(object sender, EventArgs e)
732        {
733            //Save the task list
734            if (!Directory.Exists(Program.AppDataPath))
735                Directory.CreateDirectory(Program.AppDataPath);
736            using (FileStream stream = new FileStream(TaskListPath, FileMode.Create,
737                FileAccess.Write, FileShare.None))
738            {
739                eraserClient.Tasks.SaveToStream(stream);
740            }
741
742            //Dispose the eraser executor instance
743            eraserClient.Dispose();
744        }
745        #endregion
746
747        /// <summary>
748        /// The acceptable list of command line prefixes we will accept.
749        /// </summary>
750        public const string CommandLinePrefixes = "^(/|-|--)";
751
752        /// <summary>
753        /// The acceptable list of command line separators we will accept.
754        /// </summary>
755        public const string CommandLineSeparators = "(:|=)";
756
757        /// <summary>
758        /// The global Executor instance.
759        /// </summary>
760        public static Executor eraserClient;
761
762        /// <summary>
763        /// Path to the Eraser application data path.
764        /// </summary>
765        public static readonly string AppDataPath = Path.Combine(Environment.GetFolderPath(
766            Environment.SpecialFolder.LocalApplicationData), @"Eraser 6");
767
768        /// <summary>
769        /// File name of the Eraser task list.
770        /// </summary>
771        private const string TaskListFileName = @"Task List.ersx";
772
773        /// <summary>
774        /// Path to the Eraser task list.
775        /// </summary>
776        public static readonly string TaskListPath = Path.Combine(AppDataPath, TaskListFileName);
777
778        /// <summary>
779        /// Path to the Eraser settings key (relative to HKCU)
780        /// </summary>
781        public const string SettingsPath = @"SOFTWARE\Eraser\Eraser 6";
782
783        public static IEnumerable<IErasureTarget> ErasureTargetRegistrar { get; set; }
784    }
785
786    class Win32Window : IWin32Window
787    {
788        public Win32Window(IntPtr hwnd)
789        {
790            Hwnd = hwnd;
791        }
792
793        #region IWin32Window Members
794
795        public IntPtr Handle
796        {
797            get { return Hwnd; }
798        }
799
800        #endregion
801
802        private IntPtr Hwnd;
803    }
804}
Note: See TracBrowser for help on using the repository browser.