Index: /trunk/eraser/Eraser.Util/NativeMethods/Kernel.cs
===================================================================
--- /trunk/eraser/Eraser.Util/NativeMethods/Kernel.cs	(revision 2001)
+++ /trunk/eraser/Eraser.Util/NativeMethods/Kernel.cs	(revision 2002)
@@ -899,4 +899,36 @@
 			out WindowsEditions pdwReturnedProductType);
 
+		/// <summary>
+		/// Frees the specified local memory object and invalidates its handle.
+		/// </summary>
+		/// <param name="hMem">A handle to the local memory object. This handle is
+		/// returned by either the LocalAlloc or LocalReAlloc function. It is not
+		/// safe to free memory allocated with GlobalAlloc.</param>
+		/// <returns>If the function succeeds, the return value is NULL.
+		/// 
+		/// If the function fails, the return value is equal to a handle to the
+		/// local memory object. To get extended error information, call
+		/// GetLastError.</returns>
+		/// <remarks>If the process tries to examine or modify the memory after
+		/// it has been freed, heap corruption may occur or an access violation
+		/// exception (EXCEPTION_ACCESS_VIOLATION) may be generated.
+		/// 
+		/// If the hMem parameter is NULL, LocalFree ignores the parameter and
+		/// returns NULL.
+		/// 
+		/// The LocalFree function will free a locked memory object. A locked
+		/// memory object has a lock count greater than zero. The LocalLock
+		/// function locks a local memory object and increments the lock count
+		/// by one. The LocalUnlock function unlocks it and decrements the lock
+		/// count by one. To get the lock count of a local memory object, use
+		/// the LocalFlags function.
+		/// 
+		/// If an application is running under a debug version of the system,
+		/// LocalFree will issue a message that tells you that a locked object
+		/// is being freed. If you are debugging the application, LocalFree will
+		/// enter a breakpoint just before freeing a locked object. This allows
+		/// you to verify the intended behavior, then continue execution.</remarks>
+		[DllImport("Kernel32.dll", SetLastError = true)]
+		public static extern IntPtr LocalFree(IntPtr hMem);
 	}
 }
Index: /trunk/eraser/Eraser.Util/NativeMethods/Shell.cs
===================================================================
--- /trunk/eraser/Eraser.Util/NativeMethods/Shell.cs	(revision 2001)
+++ /trunk/eraser/Eraser.Util/NativeMethods/Shell.cs	(revision 2002)
@@ -30,4 +30,47 @@
 	{
 		/// <summary>
+		/// Parses a Unicode command line string and returns an array of pointers to the command
+		/// line arguments, along with a count of such arguments, in a way that is similar to
+		/// the standard C run-time argv and argc values.
+		/// </summary>
+		/// <param name="lpCmdLine">Pointer to a null-terminated Unicode string that contains
+		/// the full command line. If this parameter is an empty string the function returns the
+		/// path to the current executable file.</param>
+		/// <param name="pNumArgs">Pointer to an int that receives the number of array elements
+		/// returned, similar to argc.</param>
+		/// <returns>A pointer to an array of strings, similar to argv.</returns>
+		/// <remarks>The address returned by CommandLineToArgvW is the address of the first
+		/// element in an array of LPWSTR values; the number of pointers in this array is
+		/// indicated by pNumArgs. Each pointer to a null-terminated Unicode string represents
+		/// an individual argument found on the command line.
+		/// 
+		/// CommandLineToArgvW allocates a block of contiguous memory for pointers to the
+		/// argument strings, and for the argument strings themselves; the calling application
+		/// must free the memory used by the argument list when it is no longer needed. To free
+		/// the memory, use a single call to the LocalFree function.
+		/// 
+		/// For more information about the argv and argc argument convention, see Argument
+		/// Definitions and Parsing C++ Command-Line Arguments.
+		/// 
+		/// The GetCommandLineW function can be used to get a command line string that is
+		/// suitable for use as the lpCmdLine parameter.
+		/// 
+		/// This function accepts command lines that contain a program name; the program name
+		/// can be enclosed in quotation marks or not.
+		/// 
+		/// CommandLineToArgvW has a special interpretation of backslash characters when they
+		/// are followed by a quotation mark character ("), as follows:
+		/// 
+		///     * 2n backslashes followed by a quotation mark produce n backslashes
+		///       followed by a quotation mark.
+		///     * (2n) + 1 backslashes followed by a quotation mark again produce n
+		///       backslashes followed by a quotation mark.
+		///     * n backslashes not followed by a quotation mark simply produce n
+		///       backslashes.
+		/// </remarks>
+		[DllImport("Shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+		public static extern IntPtr CommandLineToArgvW(string lpCmdLine, out int pNumArgs);
+
+		/// <summary>
 		/// Truncates a path to fit within a certain number of characters by
 		/// replacing path components with ellipses.
Index: /trunk/eraser/Eraser.Util/Shell.cs
===================================================================
--- /trunk/eraser/Eraser.Util/Shell.cs	(revision 2001)
+++ /trunk/eraser/Eraser.Util/Shell.cs	(revision 2002)
@@ -23,4 +23,6 @@
 using System.Collections.Generic;
 using System.Text;
+
+using System.Runtime.InteropServices;
 using Microsoft.Win32;
 
@@ -64,4 +66,25 @@
 			}
 		}
+
+		/// <summary>
+		/// Parses the provided command line into its constituent arguments.
+		/// </summary>
+		/// <param name="commandLine">The command line to parse.</param>
+		/// <returns>The arguments specified in the command line</returns>
+		public static string[] ParseCommandLine(string commandLine)
+		{
+			int argc = 0;
+			IntPtr argv = NativeMethods.CommandLineToArgvW(commandLine, out argc);
+			string[] result = new string[argc];
+
+			//Get the pointers to the arguments, then read the string.
+			for (int i = 0; i < argc; ++i)
+				result[i] = Marshal.PtrToStringUni(Marshal.ReadIntPtr(argv, i * IntPtr.Size));
+
+			//Free the memory
+			NativeMethods.LocalFree(argv);
+
+			return result;
+		}
 	}
 }
Index: /trunk/eraser/Eraser/Program.cs
===================================================================
--- /trunk/eraser/Eraser/Program.cs	(revision 2001)
+++ /trunk/eraser/Eraser/Program.cs	(revision 2002)
@@ -105,8 +105,25 @@
 		/// </summary>
 		[STAThread]
-		static int Main(string[] commandLine)
-		{
-			//Immediately parse command line arguments
-			ComLib.BoolMessageItem argumentParser = Args.Parse(commandLine,
+		static int Main(string[] rawCommandLine)
+		{
+			//Immediately parse command line arguments. Start by substituting all
+			//response files ("@filename") arguments with the arguments found in the
+			//file
+			List<string> commandLine = new List<string>();
+			foreach (string argument in rawCommandLine)
+			{
+				if (argument[0] == '@' && File.Exists(argument.Substring(1)))
+				{
+					//The current parameter is a response file, parse the file
+					//for arguments and substitute it.
+					using (TextReader reader = new StreamReader(argument.Substring(1)))
+					{
+						commandLine.AddRange(Shell.ParseCommandLine(reader.ReadToEnd()));
+					}
+				}
+			}
+
+			string[] finalCommandLine = commandLine.ToArray();
+			ComLib.BoolMessageItem argumentParser = Args.Parse(finalCommandLine,
 				CommandLinePrefixes, CommandLineSeparators);
 			Args parsedArguments = (Args)argumentParser.Item;
@@ -122,9 +139,9 @@
 				parsedArguments.Positional[0] != parsedArguments.Raw[0])
 			{
-				GUIMain(commandLine);
+				GUIMain(finalCommandLine);
 			}
 			else
 			{
-				return CommandMain(commandLine);
+				return CommandMain(finalCommandLine);
 			}
 
