Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for deltrash.cs

(view source code of deltrash.cs as plain text)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using Shell32;
  6.  
  7.  
  8. namespace RobvanderWoude
  9. {
  10. 	class DelTrash
  11. 	{
  12. 		static string progver = "1.02";
  13.  
  14.  
  15. 		static int Main( string[] args )
  16. 		{
  17. 			#region Initialize Variables
  18.  
  19. 			int rc = 0;
  20. 			long totalsize = 0;
  21. 			int deleteditems = 0;
  22. 			int accessdenieddirs = 0;
  23. 			bool accessdenied = false;
  24. 			bool confirm = false;
  25. 			bool progress = false;
  26. 			bool quiet = false;
  27. 			bool verbose = false;
  28. 			RecycleFlags flags = RecycleFlags.RecycleNoSound;
  29. 			string drive = null; // default: All drives
  30. 			string windrive = Path.GetPathRoot( Environment.SystemDirectory );
  31.  
  32. 			#endregion Initialize Variables
  33.  
  34.  
  35. 			#region Parse Command Line
  36.  
  37. 			if ( args.Length > 3 )
  38. 			{
  39. 				return ShowHelp( );
  40. 			}
  41.  
  42. 			foreach ( string arg in args )
  43. 			{
  44. 				switch ( arg.ToUpper( ) )
  45. 				{
  46. 					case "/?":
  47. 						return ShowHelp( );
  48. 					case "/C":
  49. 						if ( confirm )
  50. 						{
  51. 							return ShowHelp( "Duplicate command line switch /C" );
  52. 						}
  53. 						confirm = true;
  54. 						break;
  55. 					case "/P":
  56. 						if ( progress )
  57. 						{
  58. 							return ShowHelp( "Duplicate command line switch /P" );
  59. 						}
  60. 						progress = true;
  61. 						break;
  62. 					case "/Q":
  63. 						if ( quiet )
  64. 						{
  65. 							return ShowHelp( "Duplicate command line switch /Q" );
  66. 						}
  67. 						if ( verbose )
  68. 						{
  69. 							return ShowHelp( "Switches /V and /Q are mutually exclusive" );
  70. 						}
  71. 						verbose = true;
  72. 						break;
  73. 					case "/V":
  74. 						if ( verbose )
  75. 						{
  76. 							return ShowHelp( "Duplicate command line switch /V" );
  77. 						}
  78. 						if ( quiet )
  79. 						{
  80. 							return ShowHelp( "Switches /V and /Q are mutually exclusive" );
  81. 						}
  82. 						verbose = true;
  83. 						break;
  84. 					case "/W":
  85. 						if ( drive != null )
  86. 						{
  87. 							if ( drive == windrive )
  88. 							{
  89. 								return ShowHelp( "Either specify a drive letter or use the /W switch, not both" );
  90. 							}
  91. 							else
  92. 							{
  93. 								return ShowHelp( "Duplicate drive specification {0} and {1}", drive, arg.ToUpper( ) );
  94. 							}
  95. 						}
  96. 						drive = windrive;
  97. 						break;
  98. 					default:
  99. 						bool validdrive = false;
  100. 						DriveInfo[] alldrives = DriveInfo.GetDrives( );
  101. 						foreach ( DriveInfo drvinf in alldrives )
  102. 						{
  103. 							if ( drvinf.Name == arg.ToUpper( ) + "\\" )
  104. 							{
  105. 								validdrive = true;
  106. 								drive = arg.ToUpper( );
  107. 							}
  108. 						}
  109. 						if ( !validdrive )
  110. 						{
  111. 							return ShowHelp( "Invalid command line argument \"{0}\"", arg );
  112. 						}
  113. 						break;
  114. 				}
  115. 			}
  116.  
  117. 			if ( !confirm )
  118. 			{
  119. 				flags |= RecycleFlags.RecycleNoConfirmation;
  120. 			}
  121. 			if ( !progress )
  122. 			{
  123. 				flags |= RecycleFlags.RecycleNoProgressUI;
  124. 			}
  125.  
  126. 			#endregion Parse Command Line
  127.  
  128.  
  129. 			#region Verbose Output
  130.  
  131. 			if ( verbose )
  132. 			{
  133. 				foreach ( DriveInfo diskdrive in DriveInfo.GetDrives( ) )
  134. 				{
  135. 					if ( diskdrive.DriveType == DriveType.Fixed ) // local harddisks only
  136. 					{
  137. 						string recyclebin = Path.Combine( diskdrive.Name, "$RECYCLE.BIN" );
  138. 						if ( Directory.Exists( recyclebin ) )
  139. 						{
  140. 							long size = 0;
  141. 							int items = 0;
  142. 							string[] files = new string[0];
  143. 							string[] folders = Directory.GetDirectories( recyclebin );
  144. 							foreach ( string folder in folders )
  145. 							{
  146. 								try
  147. 								{
  148. 									// assuming any access denied will occur on the first directory level
  149. 									files = Directory.GetFiles( folder, "*.*", SearchOption.AllDirectories );
  150. 									foreach ( string file in files )
  151. 									{
  152. 										size += new FileInfo( file ).Length;
  153. 										items++;
  154. 									}
  155. 								}
  156. 								catch ( UnauthorizedAccessException )
  157. 								{
  158. 									accessdenied = true;
  159. 									accessdenieddirs++;
  160. 								}
  161. 							}
  162. 							if ( items == 1 )
  163. 							{
  164. 								Console.WriteLine( "Deleting 1 file ({1}) from drive {2}", items, FormatBytes( size ), diskdrive.Name.Remove( 2 ) );
  165. 								totalsize += size;
  166. 								deleteditems += items;
  167. 							}
  168. 							else if ( items > 1 )
  169. 							{
  170. 								Console.WriteLine( "Deleting {0} files ({1}) from drive {2}", items, FormatBytes( size ), diskdrive.Name.Remove( 2 ) );
  171. 								totalsize += size;
  172. 								deleteditems += items;
  173. 							}
  174. 						}
  175. 					}
  176. 				}
  177. 			}
  178.  
  179. 			#endregion Verbose Output
  180.  
  181.  
  182. 			#region Actual Deletion
  183.  
  184. 			uint result = SHEmptyRecycleBin( IntPtr.Zero, drive, flags );
  185. 			if ( result == 0 )
  186. 			{
  187. 				if ( !quiet )
  188. 				{
  189. 					Console.WriteLine( "{0} items with a total size of {1} have been permanently deleted.", deleteditems, FormatBytes( totalsize ) );
  190. 					if ( accessdenied )
  191. 					{
  192. 						if ( accessdenieddirs == 1 )
  193. 						{
  194. 							Console.WriteLine( "Not all items could be removed permanently because access was denied to 1 directory" );
  195. 						}
  196. 						else
  197. 						{
  198. 							Console.WriteLine( "Not all items could be removed permanently because access was denied to {0} directories", accessdenieddirs );
  199. 						}
  200. 					}
  201. 				}
  202. 				rc = 0;
  203. 			}
  204. 			else
  205. 			{
  206. 				if ( !quiet )
  207. 				{
  208. 					Console.WriteLine( "Not all items could be removed permanently" );
  209. 				}
  210. 				rc = 1;
  211. 			}
  212.  
  213. 			#endregion Actual Deletion
  214.  
  215.  
  216. 			return rc;
  217. 		}
  218.  
  219.  
  220. 		static string FormatBytes( long bytes )
  221. 		{
  222. 			int KB = 1024;
  223. 			int MB = 1024 * KB;
  224. 			int GB = 1024 * MB;
  225. 			if ( bytes < KB )
  226. 			{
  227. 				return bytes.ToString( ) + " B";
  228. 			}
  229. 			else if ( bytes < MB )
  230. 			{
  231. 				return ( bytes / KB ).ToString( ) + " KB";
  232. 			}
  233. 			else if ( bytes < GB )
  234. 			{
  235. 				return ( bytes / MB ).ToString( ) + " MB";
  236. 			}
  237. 			else
  238. 			{
  239. 				return ( bytes / GB ).ToString( ) + " GB";
  240. 			}
  241. 		}
  242.  
  243.  
  244. 		static int ShowHelp( params string[] errmsg )
  245. 		{
  246. 			#region Error Message
  247.  
  248. 			if ( errmsg.Length > 0 )
  249. 			{
  250. 				List<string> errargs = new List<string>( errmsg );
  251. 				errargs.RemoveAt( 0 );
  252. 				Console.Error.WriteLine( );
  253. 				Console.ForegroundColor = ConsoleColor.Red;
  254. 				Console.Error.Write( "ERROR:\t" );
  255. 				Console.ForegroundColor = ConsoleColor.White;
  256. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  257. 				Console.ResetColor( );
  258. 			}
  259.  
  260. 			#endregion Error Message
  261.  
  262.  
  263. 			#region Help Text
  264.  
  265. 			/*
  266. 			DelTrash.exe,  Version 1.01
  267. 			Empty the Recycle Bin
  268.  
  269. 			Usage:   DelTrash.exe  [ drive: | /W ]  [ /C ]  [ /P ]  [ /Q | /V ]
  270.  
  271. 			Where:   drive:  empty recycle bin on this drive only (default: all drives)
  272. 			         /W      empty recycle bin on Windows' drive only (default: all drives)
  273. 			         /C      prompt for Confirmation
  274. 			         /P      show Progress bar
  275. 			         /Q      Quiet mode, no screen output
  276. 			         /V      Verbose mode, show number of files and total size per disk drive
  277.  
  278. 			Notes:   Switches /Q and /V are mutually exclusive.
  279. 			         Return code is 0 if the Recycle Bin was emptied successfully, or 1
  280. 			         if there was nothing to delete or in case of (command line) errors.
  281.  
  282. 			Credits: Based on code by Vinoth Kumar
  283. 			         www.codeproject.com/Articles/20172/Empty-the-Recycle-Bin-using-C
  284. 			         Number of items and size calculation based on 
  285.  
  286. 			Written by Rob van der Woude
  287. 			https://www.robvanderwoude.com
  288. 			*/
  289.  
  290. 			#endregion Help Text
  291.  
  292.  
  293. 			#region Display Help Text
  294.  
  295. 			Console.Error.WriteLine( );
  296.  
  297. 			Console.Error.WriteLine( "DelTrash.exe,  Version {0}", progver );
  298.  
  299. 			Console.Error.WriteLine( "Empty the Recycle Bin" );
  300.  
  301. 			Console.Error.WriteLine( );
  302.  
  303. 			Console.Error.Write( "Usage:   " );
  304. 			Console.ForegroundColor = ConsoleColor.White;
  305. 			Console.Error.WriteLine( "DelTrash.exe  [ drive: | /W ]  [ /C ]  [ /P ]  [ /Q | /V ]" );
  306. 			Console.ResetColor( );
  307.  
  308. 			Console.Error.WriteLine( );
  309.  
  310. 			Console.Error.Write( "Where:   " );
  311. 			Console.ForegroundColor = ConsoleColor.White;
  312. 			Console.Error.Write( "drive:" );
  313. 			Console.ResetColor( );
  314. 			Console.Error.WriteLine( "  empty recycle bin on this drive only (default: all drives)" );
  315.  
  316. 			Console.ForegroundColor = ConsoleColor.White;
  317. 			Console.Error.Write( "         /W" );
  318. 			Console.ResetColor( );
  319. 			Console.Error.Write( "      empty recycle bin on " );
  320. 			Console.ForegroundColor = ConsoleColor.White;
  321. 			Console.Error.Write( "W" );
  322. 			Console.ResetColor( );
  323. 			Console.Error.WriteLine( "indows' drive only (default: all drives)" );
  324.  
  325. 			Console.ForegroundColor = ConsoleColor.White;
  326. 			Console.Error.Write( "         /C" );
  327. 			Console.ResetColor( );
  328. 			Console.Error.Write( "      prompt for " );
  329. 			Console.ForegroundColor = ConsoleColor.White;
  330. 			Console.Error.Write( "C" );
  331. 			Console.ResetColor( );
  332. 			Console.Error.WriteLine( "onfirmation" );
  333.  
  334. 			Console.ForegroundColor = ConsoleColor.White;
  335. 			Console.Error.Write( "         /P" );
  336. 			Console.ResetColor( );
  337. 			Console.Error.Write( "      show " );
  338. 			Console.ForegroundColor = ConsoleColor.White;
  339. 			Console.Error.Write( "P" );
  340. 			Console.ResetColor( );
  341. 			Console.Error.WriteLine( "rogress bar" );
  342.  
  343. 			Console.ForegroundColor = ConsoleColor.White;
  344. 			Console.Error.Write( "         /Q      Q" );
  345. 			Console.ResetColor( );
  346. 			Console.Error.WriteLine( "uiet mode, no screen output" );
  347.  
  348. 			Console.ForegroundColor = ConsoleColor.White;
  349. 			Console.Error.Write( "         /V      V" );
  350. 			Console.ResetColor( );
  351. 			Console.Error.WriteLine( "erbose mode, show number of files and total size per disk drive" );
  352.  
  353. 			Console.Error.WriteLine( );
  354.  
  355. 			Console.Error.Write( "Notes:   Switches " );
  356. 			Console.ForegroundColor = ConsoleColor.White;
  357. 			Console.Error.Write( "/Q" );
  358. 			Console.ResetColor( );
  359. 			Console.Error.Write( " and " );
  360. 			Console.ForegroundColor = ConsoleColor.White;
  361. 			Console.Error.Write( "/V" );
  362. 			Console.ResetColor( );
  363. 			Console.Error.WriteLine( " are mutually exclusive." );
  364.  
  365. 			Console.Error.WriteLine( "         Return code is 0 if the Recycle Bin was emptied successfully, or 1" );
  366.  
  367. 			Console.Error.WriteLine( "         if there was nothing to delete or in case of (command line) errors." );
  368.  
  369. 			Console.Error.WriteLine( );
  370.  
  371. 			Console.Error.WriteLine( "Credits: Based on code by Vinoth Kumar" );
  372.  
  373. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  374. 			Console.Error.WriteLine( "         www.codeproject.com/Articles/20172/Empty-the-Recycle-Bin-using-C" );
  375. 			Console.ResetColor( );
  376.  
  377. 			Console.Error.WriteLine( );
  378.  
  379. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  380.  
  381. 			Console.Error.WriteLine( "https://www.robvanderwoude.com" );
  382.  
  383. 			#endregion Display Help Text
  384.  
  385.  
  386. 			return 1;
  387. 		}
  388.  
  389.  
  390. 		public enum RecycleFlags : uint
  391. 		{
  392. 			RecycleNoConfirmation = 0x00000001,
  393. 			RecycleNoProgressUI = 0x00000002,
  394. 			RecycleNoSound = 0x00000004
  395. 		}
  396.  
  397.  
  398. 		[DllImport( "Shell32.dll", CharSet = CharSet.Unicode )]
  399. 		static extern uint SHEmptyRecycleBin( IntPtr hwnd, string pszRootPath, RecycleFlags dwFlags );
  400. 	}
  401. }

page last modified: 2023-03-10