清空回收站,可调用SHEmptyRecycleBin 函数,在shell32.dll,dwFlags参数指定清空回收站时,是否显示提示操作的对话框?显示删除过程的进度条? 静音操作?
注意:SHEmptyRecycleBin 函数必须在标识为STA的线程里才能成功调用
调用SHQueryRecycleBin 函数查询 指定目录(或者整个回收站,当pszRootPath参数为null时),有多少个被删除到回收站的项,以及它们占用多大的空间
在客户端的代码实现处不能确定调用SHEmptyRecycleBin 函数的线程是否是一个STA线程,或许它就是一个MTA线程,并且线程一旦在运行,就不能改变它的单位状态,也就是:不能调用Thread.SetApartmentState来设置已经在运行的线程的单位状态。.net默认的线程为MTA单位.因此想要成功调用SHEmptyRecycleBin 必须在STA的线程里;或者开启一个新的STA线程来操作:只有这样才能在不影响其他代码在实现的限制。
RecycleBinInfo类是对SHEmptyRecycleBin 函数和SHQueryRecycleBin 这两个函数的封装,如果用户调用RecycleBinInfo.SHEmptyRecycleBin 的任何一个重载都会在内部开启一个STA单位的线程,这样,在不影响外部线程单位状态的前提下实现清空回收站。
这里是代码实现,可导出为DLL
namespace RecycleBinMgr { /* * * 注意:使用此类必须将项目的目标平台改成x86,编译那边也选择x86 * */ namespace RecycleBinHelper { using System; using System.Threading; using System.Runtime.InteropServices; [Flags] public enum SHERB : uint { /* #define SHERB_NOCONFIRMATION 0x00000001 #define SHERB_NOPROGRESSUI 0x00000002 #define SHERB_NOSOUND 0x00000004*/ /// <summary> /// 不选择其他的三个项,不可与其他选项同时使用 /// </summary> SHERB_GENNERAL = 0x00000000, /// <summary> /// 不显示确认删除的对话框 /// </summary> SHERB_NOCONFIRMATION = 0x00000001, /// <summary> /// 不显示删除过程的进度条 /// </summary> SHERB_NOPROGRESSUI = 0x00000002, /// <summary> /// 当删除完成时,不播放声音 /// </summary> SHERB_NOSOUND = 0x00000004 }; [StructLayout(LayoutKind.Explicit, Pack = 2)] public struct SHQUERYRBINFO { //这个结构必须是用户显示编写偏移量才能准确获取数值 [FieldOffset(0)] public int cbsize; [FieldOffset(4)] public long i64Size; [FieldOffset(12)] public long i64NumItems; }; public static class LibWarp { /// <summary> /// 清空指定磁盘或目录的回收站的内容 /// </summary> /// <param name="hwnd">对话框的句柄,通常应当设为NULL</param> /// <param name="RootPath">磁盘路径,如果要清空所有磁盘,设置为null值或空值</param> /// <param name="flags">SHERB枚举的值,一个或多个的组合</param> /// <returns>成功返回0,S_OK值,失败为其他的OLE定义值</returns> [DllImport("shell32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] // [PreserveSig()] public static extern uint SHEmptyRecycleBinW( IntPtr hwnd, [In()] [MarshalAs(UnmanagedType.LPWStr,SizeConst=260)] string rootpath, SHERB flags); /// <summary> ///API的SHQueryRecycleBinW /// </summary> [DllImport("shell32.dll", CharSet = CharSet.Unicode)] public static extern uint SHQueryRecycleBinW( [In()] [MarshalAs(UnmanagedType.LPWStr,SizeConst=260)] string RootPath , ref SHQUERYRBINFO queyRBInfo); }; internal class _rbState { private IntPtr _hwnd; private string _rootpath; private SHERB _sherb; private uint _rv; internal _rbState(IntPtr hwnd, string rootpath, SHERB sherb) { this._hwnd = hwnd; this._rootpath = rootpath; this._sherb = sherb; _rv = 0; } internal _rbState() { this._hwnd = IntPtr.Zero; this._rootpath = null; this._sherb = SHERB.SHERB_GENNERAL; } internal IntPtr Hwnd { get { return this._hwnd; } set { this._hwnd = value; } } internal string Rootpath { get { return this._rootpath; } set { this._rootpath = value; } } internal SHERB Sherb { get { return this._sherb; } set { this._sherb = value; } } internal uint Revalue { set { this._rv = value; } get { return this._rv; } } internal void ReSetState(IntPtr hwnd, string rootpath, SHERB sherb) { this._hwnd = hwnd; this._rootpath = rootpath; this._sherb = sherb; } }; //回收站相关 //解决不能删除的原因:调用线程必须是STA线程 /// <summary> /// 查询回收站的大小和个数,以及从回收站清空文件 /// 这个类是对SHQueryRecycleBinW函数和SHEmptyRecycleBinW函数的封装 /// 调用EmptyRecycleBin方法,删除回收站的内容;调用QuerySizeRecycleBin,查询 /// 回收站的大小和文件的个数 /// </summary> public class RecycleBinInfo { /* * 注意:多个对象实例(不同引用的),如果调用EmptyRecycleBin方法的任何重载, * 它们的调用是顺序的,(就好象在单个线程里的调用是一样的)*/ //-------------- /*这个类的实现是,在内部创建一个线程调用wrokThread,这样做的原因是将对象完全封装起来, * 因为并不能确定用户调用SHEmptyRecycleBin函数的线程模式是否为STA模式, * SHEmptyRecycleBin函数必须在STA模式下才能正确调用,这个类采用一个折衷的方法来实现。 * 当调用EmptyRecycleBin方法之一的重载,都在内部创建一个线程,将线程模式设置为STAThread * */ private void wrokThread(object state) { //state对象转换_rbState lock (state) { /*同步*/ _rbState temp = (_rbState)state; temp.Revalue = LibWarp.SHEmptyRecycleBinW( temp.Hwnd, temp.Rootpath, temp.Sherb); ((_rbState)state).Revalue = temp.Revalue; } this.ewh.Set(); } /// <summary> /// 实例化一个RecycleBinInfo对象 /// </summary> public RecycleBinInfo() { /*初始化对象*/ this.ewh = new EventWaitHandle( false, EventResetMode.AutoReset, Guid.NewGuid().ToString()); } /// <summary> /// 清空回收站,这个方法同SHEmptyRecycleBin函数一样调用 /// </summary> /// <param name="hwnd">在调用SHEmptyRecycleBin期间,指向用来显示的对话框的父窗体的句柄 /// 可为NULL值 /// </param> /// <param name="rootpath">最大长度为260个字符的字符串,指定磁盘根目录或文件夹目录,可为null,则清空整个回收站的内容</param> /// <param name="dwFlags">SHERB枚举,可组合使用</param> /// <returns>成功返回0,否则为OLE定义的错误值</returns> public uint EmptyRecycleBin(IntPtr hwnd, string rootpath, SHERB dwFlags) { _rbState rvs = new _rbState(hwnd, rootpath, dwFlags); rvs.Revalue = 0x8000FFFF; long size, items; this.QuerySizeRecycleBin(out size, out items); if (size == 0) return rvs.Revalue; lock (rvs) { Thread t = new Thread( new ParameterizedThreadStart(this.wrokThread)); t.SetApartmentState(ApartmentState.STA); t.Start(rvs); } /* Console.WriteLine("aaa");测试了,同一个对象实例,依次调用EmptyRecycleBin 的任何一个重载,其顺序总是:先被调用的,总是先运行,后面的--排队等待 * 这样的原因是ewh是AUTO的,set之后,同样命名的对象就不会wait了 */ this.ewh.WaitOne(); this.ewh.Reset(); return rvs.Revalue; } /// <summary> /// 清空整个回收站的内容 /// </summary> /// <returns>成功返回0,否则为OLE定义的错误值</returns> public uint EmptyRecycleBin() { _rbState rvs = new _rbState(); rvs.Revalue = 0x8000FFFF; long size, items; this.QuerySizeRecycleBin(out size, out items); if (size == 0) return rvs.Revalue; lock (rvs) { Thread t = new Thread( new ParameterizedThreadStart(this.wrokThread)); t.SetApartmentState(ApartmentState.STA);//将线程设置为STA t.Start(rvs); } this.ewh.WaitOne(); this.ewh.Reset(); return rvs.Revalue; } /// <summary> /// 查询回收站的大小和文件个数。 /// </summary> /// <param name="RBsize">总大小(以字节为单位)。</param> /// <param name="RBNumItems">删除的项目数量。</param> /// <returns>如果函数成功,返回0;否则返回OLE定义的错误值。</returns> public uint QuerySizeRecycleBin(out long RBsize, out long RBNumItems) { // 将初始值设置为-1,以便在查询失败时表示错误。 RBsize = -1; RBNumItems = -1; SHQUERYRBINFO rbinfo = new SHQUERYRBINFO(); rbinfo.cbsize = Marshal.SizeOf(rbinfo); // 使用null作为根路径调用SHQueryRecycleBinW函数,以获取回收站的信息。 uint rv = LibWarp.SHQueryRecycleBinW(null, ref rbinfo); // 检查函数调用是否成功。 if (rv == 0) { // 函数调用成功,从rbinfo结构中获取大小和文件数量。 RBsize = rbinfo.i64Size; RBNumItems = rbinfo.i64NumItems; } return rv; } /// <summary> /// 查询指定目录或磁盘下被删除到回收站的文件的总大小和个数。 /// 如果设置为null,效果跟 QuerySizeRecycleBin(out long RBsize,out long RBNumItems )一样 /// </summary> /// <param name="rootpath">指定的磁盘和目录</param> /// <param name="RBsize">总大小,按字节计算</param> /// <param name="RBNumItems">文件的个数</param> /// <returns>如果函数成功返回0,错误为其他OLE定义的错误值</returns> public uint QuerySizeRecycleBin(string rootpath, out long RBsize, out long RBNumItems) { RBsize = -1; RBNumItems = -1; SHQUERYRBINFO rbinfo = new SHQUERYRBINFO(); rbinfo.cbsize = Marshal.SizeOf(rbinfo); uint rv = LibWarp.SHQueryRecycleBinW(rootpath, ref rbinfo); RBsize = rbinfo.i64Size; RBNumItems = rbinfo.i64NumItems; return rv; } #region 字段 private EventWaitHandle ewh; /// <summary> /// HRSULT的E_UNEXCEPTED值 /// </summary> public static readonly uint E_UNEXCEPTED = 0x8000FFFF; #endregion 字段 }; } }
//main 调用
Feng.WinShellApi.RecycleBinInfo rb=new Feng.WinShellApi.RecycleBinInfo(); ; long size,items; rb.QuerySizeRecycleBin(out size,out items); Console.WriteLine(size);//单位为字节 Console.WriteLine(items);//个数 rb.EmptyRecycleBin( IntPtr.Zero, @"C:/Users/Feng/Desktop", Feng.WinShellApi.SHERB.SHERB_GENNERAL);//只清空C:/Users/Feng/Desktop目录下的项 // rb.EmptyRecycleBin();//清空所有 Console.ReadKey(true);
Austin Liu 刘恒辉
Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com 欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。 |