Index: /trunk/eraser/Eraser/Program.cs
===================================================================
--- /trunk/eraser/Eraser/Program.cs	(revision 2014)
+++ /trunk/eraser/Eraser/Program.cs	(revision 2015)
@@ -101,4 +101,37 @@
 		}
 
+		class ShellArguments : ConsoleArguments
+		{
+			/// <summary>
+			/// The action which the shell extension has requested.
+			/// </summary>
+			[Arg("action", "The action selected by the user", typeof(string), true, null, null)]
+			public ShellActions ShellAction { get; set; }
+
+			/// <summary>
+			/// Whether the recycle bin was specified on the command line.
+			/// </summary>
+			[Arg("recycleBin", "The recycle bin as an erasure target", typeof(string), false, null, null)]
+			public bool RecycleBin { get; set; }
+		}
+
+		public enum ShellActions
+		{
+			/// <summary>
+			/// Erase the selected items now.
+			/// </summary>
+			EraseNow,
+
+			/// <summary>
+			/// Erase the selected items on restart.
+			/// </summary>
+			EraseOnRestart,
+
+			/// <summary>
+			/// Erase the unused space on the drive.
+			/// </summary>
+			EraseUnusedSpace
+		}
+
 		/// <summary>
 		/// The main entry point for the application.
@@ -154,4 +187,44 @@
 		#region Console Program code
 		/// <summary>
+		/// Connects to the running Eraser instance for erasures.
+		/// </summary>
+		/// <returns>The connectin with the remote instance.</returns>
+		private static RemoteExecutorClient CommandConnect()
+		{
+			try
+			{
+				RemoteExecutorClient result = new RemoteExecutorClient();
+				result.Run();
+				if (!result.IsConnected)
+				{
+					//The client cannot connect to the server. This probably means
+					//that the server process isn't running. Start an instance.
+					Process eraserInstance = Process.Start(
+						Assembly.GetExecutingAssembly().Location, "/quiet");
+					Thread.Sleep(0);
+					eraserInstance.WaitForInputIdle();
+
+					result.Run();
+					if (!result.IsConnected)
+						throw new IOException("Eraser cannot connect to the running " +
+							"instance for erasures.");
+				}
+
+				return result;
+			}
+			catch (UnauthorizedAccessException e)
+			{
+				//We can't connect to the pipe because the other instance of Eraser
+				//is running with higher privileges than this instance.
+				throw new UnauthorizedAccessException("Another instance of Eraser " +
+					"is already running but it is running with higher privileges than " +
+					"this instance of Eraser. Tasks cannot be added in this manner.\n\n" +
+					"Close the running instance of Eraser and start it again without " +
+					"administrator privileges, or run the command again as an " +
+					"administrator.", e);
+			}
+		}
+
+		/// <summary>
 		/// Runs Eraser as a command-line application.
 		/// </summary>
@@ -171,4 +244,6 @@
 					program.Handlers.Add("importtasklist",
 						new ConsoleActionData(CommandImportTaskList, new ConsoleArguments()));
+					program.Handlers.Add("shell",
+						new ConsoleActionData(CommandShell, new ShellArguments()));
 					program.Run();
 					return 0;
@@ -408,38 +483,6 @@
 
 			//Send the task out.
-			try
-			{
-				using (RemoteExecutorClient client = new RemoteExecutorClient())
-				{
-					client.Run();
-					if (!client.IsConnected)
-					{
-						//The client cannot connect to the server. This probably means
-						//that the server process isn't running. Start an instance.
-						Process eraserInstance = Process.Start(
-							Assembly.GetExecutingAssembly().Location, "/quiet");
-						Thread.Sleep(0);
-						eraserInstance.WaitForInputIdle();
-
-						client.Run();
-						if (!client.IsConnected)
-							throw new IOException("Eraser cannot connect to the running " +
-								"instance for erasures.");
-					}
-
-					client.Tasks.Add(task);
-				}
-			}
-			catch (UnauthorizedAccessException e)
-			{
-				//We can't connect to the pipe because the other instance of Eraser
-				//is running with higher privileges than this instance.
-				throw new UnauthorizedAccessException("Another instance of Eraser " +
-					"is already running but it is running with higher privileges than " +
-					"this instance of Eraser. Tasks cannot be added in this manner.\n\n" +
-					"Close the running instance of Eraser and start it again without " +
-					"administrator privileges, or run the command again as an " +
-					"administrator.", e);
-			}
+			using (eraserClient = CommandConnect())
+				eraserClient.Tasks.Add(task);
 		}
 
@@ -451,39 +494,68 @@
 		{
 			//Import the task list
-			try
-			{
-				using (RemoteExecutorClient client = new RemoteExecutorClient())
-				{
-					client.Run();
-					if (!client.IsConnected)
+			using (eraserClient = CommandConnect())
+				foreach (string path in args.PositionalArguments)
+					using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
+						eraserClient.Tasks.LoadFromStream(stream);
+		}
+
+		/// <summary>
+		/// Handles the files from the Shell extension.
+		/// </summary>
+		/// <param name="args">The command line parameters passed to the program.</param>
+		private static void CommandShell(ConsoleArguments args)
+		{
+			//Construct a draft task.
+			Task task = new Task();
+			switch (((ShellArguments)args).ShellAction)
+			{
+				case ShellActions.EraseOnRestart:
+					task.Schedule = Schedule.RunOnRestart;
+					goto case ShellActions.EraseNow;
+
+				case ShellActions.EraseNow:
+					foreach (string path in args.PositionalArguments)
 					{
-						//The client cannot connect to the server. This probably means
-						//that the server process isn't running. Start an instance.
-						Process eraserInstance = Process.Start(
-							Assembly.GetExecutingAssembly().Location, "/quiet");
-						eraserInstance.WaitForInputIdle();
-
-						client.Run();
-						if (!client.IsConnected)
-							throw new IOException("Eraser cannot connect to the running " +
-								"instance for erasures.");
+						FileSystemObjectTarget target = null;
+						if (Directory.Exists(path))
+						{
+							target = new FolderTarget();
+							target.Path = path;
+						} 
+						else
+						{
+							target = new FileTarget();
+							target.Path = path;
+						}
+
+						task.Targets.Add(target);
 					}
 
+					//Was the recycle bin specified?
+					if (((ShellArguments)args).RecycleBin)
+						task.Targets.Add(new RecycleBinTarget());
+					break;
+
+				case ShellActions.EraseUnusedSpace:
 					foreach (string path in args.PositionalArguments)
-						using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
-							client.Tasks.LoadFromStream(stream);
-				}
-			}
-			catch (UnauthorizedAccessException e)
-			{
-				//We can't connect to the pipe because the other instance of Eraser
-				//is running with higher privileges than this instance.
-				throw new UnauthorizedAccessException("Another instance of Eraser " +
-					"is already running but it is running with higher privileges than " +
-					"this instance of Eraser. Tasks cannot be added in this manner.\n\n" +
-					"Close the running instance of Eraser and start it again without " +
-					"administrator privileges, or run the command again as an " +
-					"administrator.", e);
-			}
+					{
+						UnusedSpaceTarget target = new UnusedSpaceTarget();
+						target.Drive = path;
+						task.Targets.Add(target);
+					}
+					break;
+			}
+
+			//Confirm that the user wants the erase.
+			Application.EnableVisualStyles();
+			using (Form dialog = new ShellConfirmationDialog(task))
+			{
+				if (dialog.ShowDialog() != DialogResult.Yes)
+					return;
+			}
+
+			//Then queue for erasure.
+			using (eraserClient = CommandConnect())
+				eraserClient.Tasks.Add(task);
 		}
 		#endregion
Index: /trunk/eraser/Eraser/Eraser.csproj
===================================================================
--- /trunk/eraser/Eraser/Eraser.csproj	(revision 2014)
+++ /trunk/eraser/Eraser/Eraser.csproj	(revision 2015)
@@ -212,4 +212,7 @@
       <DependentUpon>SettingsPanel.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="ShellConfirmationDialog.resx">
+      <DependentUpon>ShellConfirmationDialog.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="Strings.en.resx">
       <SubType>Designer</SubType>
@@ -333,4 +336,10 @@
   <ItemGroup>
     <Compile Include="Program.ConsoleProgram.cs" />
+    <Compile Include="ShellConfirmationDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="ShellConfirmationDialog.Designer.cs">
+      <DependentUpon>ShellConfirmationDialog.cs</DependentUpon>
+    </Compile>
     <None Include="Resources\AboutDialog.png" />
     <CodeAnalysisDictionary Include="..\CustomDictionary.xml">
Index: /trunk/eraser/Eraser/ShellConfirmationDialog.resx
===================================================================
--- /trunk/eraser/Eraser/ShellConfirmationDialog.resx	(revision 2015)
+++ /trunk/eraser/Eraser/ShellConfirmationDialog.resx	(revision 2015)
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="Image.Location" type="System.Drawing.Point, System.Drawing">
+    <value>12, 9</value>
+  </data>
+  <data name="Image.Size" type="System.Drawing.Size, System.Drawing">
+    <value>40, 40</value>
+  </data>
+  <assembly alias="mscorlib" name="mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="Image.TabIndex" type="System.Int32, mscorlib">
+    <value>0</value>
+  </data>
+  <data name="&gt;&gt;Image.Name" xml:space="preserve">
+    <value>Image</value>
+  </data>
+  <data name="&gt;&gt;Image.Type" xml:space="preserve">
+    <value>System.Windows.Forms.PictureBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;Image.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;Image.ZOrder" xml:space="preserve">
+    <value>4</value>
+  </data>
+  <data name="Message.AutoSize" type="System.Boolean, mscorlib">
+    <value>True</value>
+  </data>
+  <data name="Message.Font" type="System.Drawing.Font, System.Drawing">
+    <value>Segoe UI, 9pt</value>
+  </data>
+  <data name="Message.Location" type="System.Drawing.Point, System.Drawing">
+    <value>58, 9</value>
+  </data>
+  <data name="Message.Size" type="System.Drawing.Size, System.Drawing">
+    <value>272, 15</value>
+  </data>
+  <data name="Message.TabIndex" type="System.Int32, mscorlib">
+    <value>1</value>
+  </data>
+  <data name="Message.Text" xml:space="preserve">
+    <value>Are you sure you want to erase the selected items?</value>
+  </data>
+  <data name="&gt;&gt;Message.Name" xml:space="preserve">
+    <value>Message</value>
+  </data>
+  <data name="&gt;&gt;Message.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;Message.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;Message.ZOrder" xml:space="preserve">
+    <value>3</value>
+  </data>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="YesBtn.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+    <value>Bottom, Right</value>
+  </data>
+  <data name="YesBtn.Location" type="System.Drawing.Point, System.Drawing">
+    <value>275, 70</value>
+  </data>
+  <data name="YesBtn.Size" type="System.Drawing.Size, System.Drawing">
+    <value>90, 27</value>
+  </data>
+  <data name="YesBtn.TabIndex" type="System.Int32, mscorlib">
+    <value>3</value>
+  </data>
+  <data name="YesBtn.Text" xml:space="preserve">
+    <value>Yes</value>
+  </data>
+  <data name="&gt;&gt;YesBtn.Name" xml:space="preserve">
+    <value>YesBtn</value>
+  </data>
+  <data name="&gt;&gt;YesBtn.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;YesBtn.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;YesBtn.ZOrder" xml:space="preserve">
+    <value>2</value>
+  </data>
+  <data name="NoBtn.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
+    <value>Bottom, Right</value>
+  </data>
+  <data name="NoBtn.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
+    <value>NoControl</value>
+  </data>
+  <data name="NoBtn.Location" type="System.Drawing.Point, System.Drawing">
+    <value>377, 70</value>
+  </data>
+  <data name="NoBtn.Size" type="System.Drawing.Size, System.Drawing">
+    <value>90, 27</value>
+  </data>
+  <data name="NoBtn.TabIndex" type="System.Int32, mscorlib">
+    <value>4</value>
+  </data>
+  <data name="NoBtn.Text" xml:space="preserve">
+    <value>No</value>
+  </data>
+  <data name="&gt;&gt;NoBtn.Name" xml:space="preserve">
+    <value>NoBtn</value>
+  </data>
+  <data name="&gt;&gt;NoBtn.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;NoBtn.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;NoBtn.ZOrder" xml:space="preserve">
+    <value>1</value>
+  </data>
+  <data name="OptionsButton.Location" type="System.Drawing.Point, System.Drawing">
+    <value>12, 70</value>
+  </data>
+  <data name="OptionsButton.Size" type="System.Drawing.Size, System.Drawing">
+    <value>90, 27</value>
+  </data>
+  <data name="OptionsButton.TabIndex" type="System.Int32, mscorlib">
+    <value>2</value>
+  </data>
+  <data name="OptionsButton.Text" xml:space="preserve">
+    <value>Options...</value>
+  </data>
+  <data name="&gt;&gt;OptionsButton.Name" xml:space="preserve">
+    <value>OptionsButton</value>
+  </data>
+  <data name="&gt;&gt;OptionsButton.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+  <data name="&gt;&gt;OptionsButton.Parent" xml:space="preserve">
+    <value>$this</value>
+  </data>
+  <data name="&gt;&gt;OptionsButton.ZOrder" xml:space="preserve">
+    <value>0</value>
+  </data>
+  <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
+    <value>7, 15</value>
+  </data>
+  <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
+    <value>479, 107</value>
+  </data>
+  <data name="$this.Font" type="System.Drawing.Font, System.Drawing">
+    <value>Segoe UI, 9pt</value>
+  </data>
+  <data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
+    <value>2, 5, 2, 5</value>
+  </data>
+  <data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
+    <value>CenterScreen</value>
+  </data>
+  <data name="$this.Text" xml:space="preserve">
+    <value>Erase Items</value>
+  </data>
+  <data name="&gt;&gt;$this.Name" xml:space="preserve">
+    <value>ShellConfirmationDialog</value>
+  </data>
+  <data name="&gt;&gt;$this.Type" xml:space="preserve">
+    <value>System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
+</root>
Index: /trunk/eraser/Eraser/ShellConfirmationDialog.cs
===================================================================
--- /trunk/eraser/Eraser/ShellConfirmationDialog.cs	(revision 2015)
+++ /trunk/eraser/Eraser/ShellConfirmationDialog.cs	(revision 2015)
@@ -0,0 +1,51 @@
+﻿using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+using Eraser.Manager;
+using Eraser.Util;
+
+namespace Eraser
+{
+	public partial class ShellConfirmationDialog : Form
+	{
+		public ShellConfirmationDialog(Task task)
+		{
+			Task = task;
+			InitializeComponent();
+			Theming.ApplyTheme(this);
+
+			//Set the icon of the dialog
+			Bitmap bitmap = new Bitmap(Image.Width, Image.Height);
+			using (Graphics g = Graphics.FromImage(bitmap))
+			{
+				g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
+				g.DrawIcon(SystemIcons.Exclamation, new Rectangle(Point.Empty, Image.Size));
+			}
+			Image.Image = bitmap;
+
+			//Focus on the No button
+			NoBtn.Focus();
+		}
+
+		/// <summary>
+		/// The task which is being confirmed.
+		/// </summary>
+		private Task Task;
+
+		private void OptionsButton_Click(object sender, EventArgs e)
+		{
+			using (TaskPropertiesForm form = new TaskPropertiesForm())
+			{
+				form.Task = Task;
+				if (form.ShowDialog(this) == DialogResult.OK)
+					Task = form.Task;
+			}
+		}
+	}
+}
Index: /trunk/eraser/Eraser/ShellConfirmationDialog.Designer.cs
===================================================================
--- /trunk/eraser/Eraser/ShellConfirmationDialog.Designer.cs	(revision 2015)
+++ /trunk/eraser/Eraser/ShellConfirmationDialog.Designer.cs	(revision 2015)
@@ -0,0 +1,102 @@
+﻿namespace Eraser
+{
+	partial class ShellConfirmationDialog
+	{
+		/// <summary>
+		/// Required designer variable.
+		/// </summary>
+		private System.ComponentModel.IContainer components = null;
+
+		/// <summary>
+		/// Clean up any resources being used.
+		/// </summary>
+		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+		protected override void Dispose(bool disposing)
+		{
+			if (disposing && (components != null))
+			{
+				components.Dispose();
+			}
+			base.Dispose(disposing);
+		}
+
+		#region Windows Form Designer generated code
+
+		/// <summary>
+		/// Required method for Designer support - do not modify
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ShellConfirmationDialog));
+			this.Image = new System.Windows.Forms.PictureBox();
+			this.Message = new System.Windows.Forms.Label();
+			this.YesBtn = new System.Windows.Forms.Button();
+			this.NoBtn = new System.Windows.Forms.Button();
+			this.OptionsButton = new System.Windows.Forms.Button();
+			((System.ComponentModel.ISupportInitialize)(this.Image)).BeginInit();
+			this.SuspendLayout();
+			// 
+			// Image
+			// 
+			resources.ApplyResources(this.Image, "Image");
+			this.Image.Name = "Image";
+			this.Image.TabStop = false;
+			// 
+			// Message
+			// 
+			resources.ApplyResources(this.Message, "Message");
+			this.Message.Name = "Message";
+			// 
+			// YesBtn
+			// 
+			resources.ApplyResources(this.YesBtn, "YesBtn");
+			this.YesBtn.DialogResult = System.Windows.Forms.DialogResult.Yes;
+			this.YesBtn.Name = "YesBtn";
+			this.YesBtn.UseVisualStyleBackColor = true;
+			// 
+			// NoBtn
+			// 
+			resources.ApplyResources(this.NoBtn, "NoBtn");
+			this.NoBtn.DialogResult = System.Windows.Forms.DialogResult.No;
+			this.NoBtn.Name = "NoBtn";
+			this.NoBtn.UseVisualStyleBackColor = true;
+			// 
+			// OptionsButton
+			// 
+			resources.ApplyResources(this.OptionsButton, "OptionsButton");
+			this.OptionsButton.Name = "OptionsButton";
+			this.OptionsButton.UseVisualStyleBackColor = true;
+			this.OptionsButton.Click += new System.EventHandler(this.OptionsButton_Click);
+			// 
+			// ShellConfirmationDialog
+			// 
+			this.AcceptButton = this.NoBtn;
+			resources.ApplyResources(this, "$this");
+			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+			this.CancelButton = this.YesBtn;
+			this.Controls.Add(this.OptionsButton);
+			this.Controls.Add(this.NoBtn);
+			this.Controls.Add(this.YesBtn);
+			this.Controls.Add(this.Message);
+			this.Controls.Add(this.Image);
+			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+			this.MaximizeBox = false;
+			this.MinimizeBox = false;
+			this.Name = "ShellConfirmationDialog";
+			this.ShowInTaskbar = false;
+			((System.ComponentModel.ISupportInitialize)(this.Image)).EndInit();
+			this.ResumeLayout(false);
+			this.PerformLayout();
+
+		}
+
+		#endregion
+
+		private System.Windows.Forms.PictureBox Image;
+		private System.Windows.Forms.Label Message;
+		private System.Windows.Forms.Button YesBtn;
+		private System.Windows.Forms.Button NoBtn;
+		private System.Windows.Forms.Button OptionsButton;
+	}
+}
Index: /trunk/eraser/Eraser.Shell/CtxMenu.cpp
===================================================================
--- /trunk/eraser/Eraser.Shell/CtxMenu.cpp	(revision 2014)
+++ /trunk/eraser/Eraser.Shell/CtxMenu.cpp	(revision 2015)
@@ -491,65 +491,23 @@
 
 		//Build the command line
-		std::wstring commandAction;
 		std::wstring commandLine;
 		bool commandElevate = false;
-		HRESULT result = E_INVALIDARG;
 		switch (VerbMenuIndices[LOWORD(pCmdInfo->lpVerb)])
 		{
 		case ACTION_ERASE_ON_RESTART:
-			commandLine += L"/schedule=restart ";
-
 		case ACTION_ERASE:
-			{
-				//Add Task command.
-				commandAction = L"addtask";
-
-				//See the invocation context: if it is executed from the recycle bin
-				//then the list of selected files will be empty.
-				if (InvokeReason == INVOKEREASON_RECYCLEBIN)
-				{
-					commandLine += L"recyclebin";
-				}
-				else
-				{
-					//Okay, we were called from an item right-click; iterate over every
-					//selected file
-					for (std::list<std::wstring>::const_iterator i = SelectedFiles.begin();
-						i != SelectedFiles.end(); ++i)
-					{
-						//Check if the current item is a file or folder.
-						std::wstring item(*i);
-						if (item.length() > 2 && item[item.length() - 1] == '\\')
-							item.erase(item.end() - 1);
-						DWORD attributes = GetFileAttributes(item.c_str());
-
-						//Add the correct command line for the file type.
-						if (attributes & FILE_ATTRIBUTE_DIRECTORY)
-							commandLine += L"\"dir=" + item + L"\" ";
-						else
-							commandLine += L"\"file=" + item + L"\" ";
-					}
-				}
-
-				break;
-			}
+			//See the invocation context: if it is executed from the recycle bin
+			//then the list of selected files will be empty.
+			if (InvokeReason == INVOKEREASON_RECYCLEBIN)
+			{
+				commandLine += L"/recyclebin";
+			}
+
+			break;
 
 		case ACTION_ERASE_UNUSED_SPACE:
-			{
-				//We want to add a new task
-				commandAction = L"addtask";
-
-				//Erasing unused space requires elevation
-				commandElevate = true;
-
-				//Add every item onto the command line
-				for (std::list<std::wstring>::const_iterator i = SelectedFiles.begin();
-					i != SelectedFiles.end(); ++i)
-				{
-					commandLine += L"\"unused=" + *i + L",clusterTips\" ";
-				}
-				
-				break;
-			}
+			//Erasing unused space requires elevation
+			commandElevate = true;
+			break;
 
 		default:
@@ -559,5 +517,13 @@
 					VerbMenuIndices[LOWORD(pCmdInfo->lpVerb)]).c_str(),
 					LoadString(IDS_ERASERSHELLEXT).c_str(), MB_OK | MB_ICONERROR);
-			}
+				return E_INVALIDARG;
+			}
+		}
+
+		//Add the list of items selected.
+		for (std::list<std::wstring>::const_iterator i = SelectedFiles.begin();
+			i != SelectedFiles.end(); ++i)
+		{
+			commandLine += L"\"" + *i + L"\" ";
 		}
 
@@ -565,6 +531,6 @@
 		{
 			BusyCursor cursor;
-			RunEraser(commandAction, commandLine, commandElevate, pCmdInfo->hwnd,
-				pCmdInfo->nShow);
+			RunEraser(VerbMenuIndices[LOWORD(pCmdInfo->lpVerb)], commandLine, commandElevate,
+				pCmdInfo->hwnd, pCmdInfo->nShow);
 		}
 		catch (const std::wstring& e)
@@ -577,5 +543,5 @@
 		}
 
-		return result;
+		return S_OK;
 	}
 
@@ -812,6 +778,6 @@
 	}
 
-	void CCtxMenu::RunEraser(const std::wstring& action, const std::wstring& parameters,
-		bool elevated, HWND parent, int show)
+	void CCtxMenu::RunEraser(Actions action, const std::wstring& parameters, bool elevated,
+		HWND parent, int show)
 	{
 		//Get the path to this DLL so we can look for Eraser.exe
@@ -834,5 +800,24 @@
 		eraserPath += L"Eraser.exe";
 
-		std::wstring finalParameters;
+		//Compile the final set of parameters we are going to pass to Eraser.
+		std::wstring finalParameters(L"shell /quiet ");
+
+		//Set the action selected by the user.
+		switch (action)
+		{
+		case ACTION_ERASE:
+			finalParameters += L"/action=EraseNow ";
+			break;
+		case ACTION_ERASE_ON_RESTART:
+			finalParameters += L"/action=EraseOnRestart ";
+			break;
+		case ACTION_ERASE_UNUSED_SPACE:
+			finalParameters += L"/action=EraseUnusedSpace ";
+			break;
+		default:
+			return;
+		}
+
+		//Then append the rest of the arguments, depending on the length.
 		{
 			//Depending on the length of the argument, we either use a response file
@@ -851,7 +836,7 @@
 
 				std::wofstream stream(buffer);
-				stream << "\"" << action << L"\" /quiet " << parameters;
-
-				finalParameters = L"\"@";
+				stream << parameters;
+
+				finalParameters += L"\"@";
 				finalParameters += buffer;
 				finalParameters += '"';
@@ -860,7 +845,5 @@
 			{
 				//Short command line, pass directly to the program
-				std::wostringstream stream;
-				stream << "\"" << action << L"\" /quiet " << parameters;
-				finalParameters = stream.str();
+				finalParameters += parameters;
 			}
 		}
Index: /trunk/eraser/Eraser.Shell/CtxMenu.h
===================================================================
--- /trunk/eraser/Eraser.Shell/CtxMenu.h	(revision 2014)
+++ /trunk/eraser/Eraser.Shell/CtxMenu.h	(revision 2015)
@@ -54,4 +54,5 @@
 		};
 
+		/// This has the equivalent in Eraser.Program.ShellActions
 		enum Actions
 		{
@@ -86,5 +87,5 @@
 
 		static bool IsUserAdmin();
-		static void RunEraser(const std::wstring& action, const std::wstring& parameters,
+		static void RunEraser(Actions action, const std::wstring& parameters,
 			bool elevated, HWND parent, int show);
 
