如何通过C#或windows api删除多项目,我已经搜索了很长时间没有解决方案。我在Shell32.dll中使用FolderItemVerb逐个删除文件,但它会同时弹出一个对话框。如果您知道如何解决这个问题,我将不胜感激。谢谢。
答案 0 :(得分:0)
首先将 System.Runtime.InteropService 添加到您的项目中。我们将使用SHEmptyRecycleBin
方法,该方法接受3个参数。
之后,使用DllImport
[DllImport("Shell32.dll")]
static extern int SHEmptyRecycleBin(IntPtr hwnd, string pszRootPath, RecycleFlag dwFlags);
然后为RecycleBin标志(dwFlags)定义一个枚举。值以十六进制表示。
enum RecycleFlag : int
{
SHERB_NOCONFIRMATION = 0x00000001, // No confirmation
SHERB_NOPROGRESSUI = 0x00000001, // No progress tracking window
SHERB_NOSOUND = 0x00000004 // No sound played
}
将以下代码放在空的回收站按钮中,该按钮将Shell32.dll中的系统方法调用为:
SHEmptyRecycleBin(IntPtr.Zero, null, RecycleFlag.SHERB_NOSOUND | RecycleFlag.SHERB_NOCONFIRMATION);
参考:here
答案 1 :(得分:0)
这不适合胆小的人!
与Windows兼容的代码> = Vista,没有XP! XP代码在最后
这是我第一次看看Shell32接口......哇......即使是最简单的东西也很复杂:-)但是,COM总是很复杂......现在......有2.5用于在Shell中操作文件的竞争数据结构/接口... IShellFolder
(旧的COM接口,此示例中未使用),IShellItem
(此示例中使用的新COM接口),{{ 1}}(此处用作IDLIST
,用于“收集”多个文件。我将其视为0.5)。我希望任何地方都没有内存泄漏(总是很复杂)。请注意,.NET将自动释放COM对象。我甚至添加了一些我编写的代码来帮助我调试(比如获得动词列表的代码)。
现在,这里有COM接口和一些 Shell32.dll PInvoke方法。
PIDLIST_ABSOLUTE
最后是一个使用它的小示例程序...它是一个小型控制台方法,它将列出回收站中存在的所有文件,将其中10个放入一个数组中并在一次操作中删除它们(动词)。 [StructLayout(LayoutKind.Sequential)]
public struct PIDLIST_ABSOLUTE
{
public IntPtr Ptr;
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
public interface IShellItem
{
void BindToHandler(
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(int sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
[PreserveSig]
int Compare(IShellItem psi, uint hint, out int piOrder);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("70629033-e363-4a28-a567-0db78006e6d7")]
public interface IEnumShellItems
{
void Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] IShellItem[] rgelt, out int pceltFetched);
void Skip(int celt);
void Reset();
void Clone(out IEnumShellItems ppenum);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b63ea76d-1f85-456f-a19c-48159efa858b")]
public interface IShellItemArray
{
void BindToHandler(
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppvOut);
void GetPropertyStore(
uint flags,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetPropertyDescriptionList(
IntPtr keyType,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetAttributes(uint AttribFlags, uint sfgaoMask, out uint psfgaoAttribs);
void GetCount(out int pdwNumItems);
void GetItemAt(int dwIndex, out IShellItem ppsi);
void EnumItems(out IEnumShellItems ppenumShellItems);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e4-0000-0000-c000-000000000046")]
public interface IContextMenu
{
[PreserveSig]
int QueryContextMenu(IntPtr hMenu, uint indexMenu, int idCmdFirst, int idCmdLast, uint uFlags);
void InvokeCommand([In] ref CMINVOKECOMMANDINFOEX pici);
[PreserveSig]
int GetCommandString(UIntPtr idCmd, uint uType, IntPtr pReserved, IntPtr pszName, int cchMax);
}
[StructLayout(LayoutKind.Sequential)]
public struct CMINVOKECOMMANDINFOEX
{
public int cbSize;
public uint fMask;
public IntPtr hwnd;
// Non-unicode verbs (are there unicode verbs?)
[MarshalAs(UnmanagedType.LPStr)]
public string lpVerb;
[MarshalAs(UnmanagedType.LPStr)]
public string lpParameters;
[MarshalAs(UnmanagedType.LPStr)]
public string lpDirectory;
public int nShow;
public uint dwHotKey;
public IntPtr hIcon;
[MarshalAs(UnmanagedType.LPStr)]
public string lpTitle;
// Use CMIC_MASK_UNICODE
[MarshalAs(UnmanagedType.LPWStr)]
public string lpVerbW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpParametersW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpDirectoryW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpTitleW;
public int ptInvokeX;
public int ptInvokeY;
}
// Windows >= Vista
public static class ShellItemUtilities
{
public static readonly Guid FOLDERID_RecycleBinFolder = new Guid("b7534046-3ecb-4c18-be4e-64cd4cb7d6ac");
public static readonly Guid BHID_EnumItems = new Guid("94f60519-2850-4924-aa5a-d15e84868039");
public static readonly Guid BHID_SFUIObject = new Guid("3981e225-f559-11d3-8e3a-00c04f6837d5");
// From Windows 7
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetKnownFolderItem(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
uint dwFlags,
IntPtr hToken,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
out IShellItem ppv);
// For Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHCreateItemFromIDList(PIDLIST_ABSOLUTE pidl, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);
// For Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetKnownFolderIDList(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
uint dwFlags,
IntPtr hToken,
out PIDLIST_ABSOLUTE ppidl);
// From Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetIDListFromObject([MarshalAs(UnmanagedType.Interface)] object punk, out PIDLIST_ABSOLUTE ppidl);
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHCreateShellItemArrayFromIDLists(int cidl, [In] PIDLIST_ABSOLUTE[] rgpidl, out IShellItemArray ppsiItemArray);
public static IEnumerable<IShellItem> Enumerate(this IShellItem si)
{
object pesiTemp;
si.BindToHandler(IntPtr.Zero, BHID_EnumItems, typeof(IEnumShellItems).GUID, out pesiTemp);
var pesi = (IEnumShellItems)pesiTemp;
var items = new IShellItem[10];
while (true)
{
int fetched;
pesi.Next(1, items, out fetched);
if (fetched == 0)
{
break;
}
yield return items[0];
}
}
}
public static class ContextMenuUtilities
{
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern IntPtr CreateMenu();
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool DestroyMenu(IntPtr hMenu);
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern uint GetMenuItemID(IntPtr hMenu, int nPos);
[DllImport("User32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetMenuStringW", ExactSpelling = true, SetLastError = true)]
public static extern int GetMenuString(IntPtr hMenu, uint uIDItem, [Out] StringBuilder lpString, int nMaxCount, uint uFlag);
public static string[] GetVerbs(IContextMenu cm, bool ansi = true)
{
IntPtr menu = IntPtr.Zero;
try
{
menu = CreateMenu();
// It isn't clear why short.MaxValue, but 0x7FFF is very used around the .NET!
int res = cm.QueryContextMenu(menu, 0, 0, short.MaxValue, 0);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
//var sb = new StringBuilder(128);
int count = GetMenuItemCount(menu);
var verbs = new List<string>(count);
var handle = default(GCHandle);
try
{
var bytes = new byte[ansi ? 128 : 256];
handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
for (int i = 0; i < count; i++)
{
uint id = GetMenuItemID(menu, i);
if (id == uint.MaxValue)
{
continue;
}
//GetMenuString(menu, (uint)i, sb, sb.Capacity, 0x00000400 /* MF_BYPOSITION */);
//string description = sb.ToString();
//sb.Clear();
res = cm.GetCommandString((UIntPtr)id, ansi ? (uint)0x00000002 /* GCS_VALIDATEA */ : 0x00000006 /* GCS_VALIDATEW */, IntPtr.Zero, ptr, bytes.Length);
if (res < 0)
{
continue;
}
if (res == 0)
{
res = cm.GetCommandString((UIntPtr)id, ansi ? (uint)0x00000000 /* GCS_VERBA */ : 0x00000004 /* GCS_VERBW */, IntPtr.Zero, ptr, bytes.Length);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
verbs.Add(ansi ? Marshal.PtrToStringAnsi(ptr) : Marshal.PtrToStringUni(ptr));
}
}
}
finally
{
if (handle.IsAllocated)
{
handle.Free();
}
}
return verbs.ToArray();
}
finally
{
if (menu != IntPtr.Zero)
{
DestroyMenu(menu);
}
}
}
}
来自Windows 7,因此我使用的是来自Windows Vista的SHGetKnownFolderItem
+ SHGetKnownFolderIDList
。
此处的代码列举了回收站中包含的SHCreateItemFromIDList
个文件,将IShellItem
保存在PIDL_ABSOLUTE
中,List<>
创建了List<>
,在IShellItemArray
上绑定IShellItemArray
,因为IContextMenu
执行IContextMenu
动词。显然,通过添加/不添加delete
所有PIDL_ABSOLUTE
,您可以控制哪些文件将被删除。
List<>
Windows XP代码,使用其他版本的代码,您必须采取所需的
它使用private static void TestShellItem()
{
IShellItem recyleBin;
string str;
IntPtr ptr = IntPtr.Zero;
int res;
//// From Windows 7
//res = ShellItemUtilities.SHGetKnownFolderItem(ShellItemUtilities.FOLDERID_RecycleBinFolder, 0, IntPtr.Zero, typeof(IShellItem).GUID, out recyleBin);
//if (res < 0)
//{
// Marshal.ThrowExceptionForHR(res);
//}
// Windows >= Vista equivalent
var pidl = default(PIDLIST_ABSOLUTE);
try
{
res = ShellItemUtilities.SHGetKnownFolderIDList(ShellItemUtilities.FOLDERID_RecycleBinFolder, 0, IntPtr.Zero, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
res = ShellItemUtilities.SHCreateItemFromIDList(pidl, typeof(IShellItem).GUID, out recyleBin);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
}
finally
{
Marshal.FreeCoTaskMem(pidl.Ptr);
}
//// Example of use of GetDisplayName
//try
//{
// recyleBin.GetDisplayName(2, out ptr);
// str = Marshal.PtrToStringUni(ptr);
//}
//finally
//{
// if (ptr != IntPtr.Zero)
// {
// Marshal.FreeCoTaskMem(ptr);
// ptr = IntPtr.Zero;
// }
//}
var pids = new List<PIDLIST_ABSOLUTE>();
try
{
foreach (IShellItem si in recyleBin.Enumerate())
{
try
{
si.GetDisplayName(0, out ptr);
str = Marshal.PtrToStringUni(ptr);
// Some condition to include/exclude...
if (pids.Count < 10)
{
Console.WriteLine(str);
// Remember to free the pidl!
res = ShellItemUtilities.SHGetIDListFromObject(si, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
pids.Add(pidl);
}
}
finally
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(ptr);
ptr = IntPtr.Zero;
}
}
}
var pids2 = pids.ToArray();
IShellItemArray sia;
res = ShellItemUtilities.SHCreateShellItemArrayFromIDLists(pids2.Length, pids2, out sia);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
object cmTemp;
sia.BindToHandler(IntPtr.Zero, ShellItemUtilities.BHID_SFUIObject, typeof(IContextMenu).GUID, out cmTemp);
var cm = (IContextMenu)cmTemp;
// To see verbs
//var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true);
//var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false);
var cmd = new CMINVOKECOMMANDINFOEX
{
cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)),
fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */,
lpVerb = "delete",
};
cm.InvokeCommand(ref cmd);
}
finally
{
foreach (var pid in pids)
{
Marshal.FreeCoTaskMem(pid.Ptr);
}
}
//// Verb executed one by one
//foreach (var item in recyleBin.Enumerate())
//{
// object cmTemp;
// item.BindToHandler(IntPtr.Zero, ShellItemUtilities.BHID_SFUIObject, typeof(IContextMenu).GUID, out cmTemp);
// var cm = (IContextMenu)cmTemp;
////// To see verbs
//// var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true);
//// var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false);
// var cmd = new CMINVOKECOMMANDINFOEX
// {
// cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)),
// fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */,
// lpVerb = "delete",
// };
// cm.InvokeCommand(ref cmd);
//}
}
接口。请注意,IShellFolder
处理完全相同。
IContextMenu
最后是一个使用它的小例子程序......
[StructLayout(LayoutKind.Sequential)]
public struct PIDLIST_RELATIVE
{
public IntPtr Ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct LPITEMIDLIST
{
public IntPtr Ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct PITEMID_CHILD
{
public IntPtr Ptr;
}
public enum STRRET_TYPE
{
WSTR = 0,
OFFSET = 0x1,
CSTR = 0x2
};
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 268)]
public sealed class STRRET : IDisposable
{
public STRRET_TYPE uType;
public IntPtr pOleStr;
[DllImport("Shlwapi.dll", ExactSpelling = true, SetLastError = false)]
private static extern int StrRetToBSTR(STRRET pstr, PITEMID_CHILD pidl, [MarshalAs(UnmanagedType.BStr)] out string pbstr);
~STRRET()
{
Dispose(false);
}
public override string ToString()
{
return ToString(default(PITEMID_CHILD));
}
public string ToString(PITEMID_CHILD pidl)
{
if (uType == STRRET_TYPE.WSTR)
{
if (pOleStr == IntPtr.Zero)
{
return null;
}
string str = Marshal.PtrToStringUni(pOleStr);
return str;
}
else
{
string str;
int res = StrRetToBSTR(this, pidl, out str);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
return str;
}
}
#region IDisposable Support
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
private void Dispose(bool disposing)
{
Marshal.FreeCoTaskMem(pOleStr);
pOleStr = IntPtr.Zero;
}
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e6-0000-0000-c000-000000000046")]
public interface IShellFolder
{
void ParseDisplayName(
IntPtr hwnd,
IntPtr pbc,
[MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
out int pchEaten,
out PIDLIST_RELATIVE ppidl,
ref uint pdwAttributes);
void EnumObjects(IntPtr hwnd, uint grfFlags, out IEnumIDList ppenumIDList);
void BindToObject(
PIDLIST_RELATIVE pidl,
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void BindToStorage(
PIDLIST_RELATIVE pidl,
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
[PreserveSig]
int CompareIDs(IntPtr lParam, PIDLIST_RELATIVE pidl1, PIDLIST_RELATIVE pidl2);
void CreateViewObject(
IntPtr hwndOwner,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetAttributesOf(
int cidl,
[In, MarshalAs(UnmanagedType.LPArray)] LPITEMIDLIST[] apidl,
ref uint rgfInOut);
void GetUIObjectOf(
IntPtr hwndOwner,
int cidl,
[In, MarshalAs(UnmanagedType.LPArray)] PITEMID_CHILD[] apidl,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
IntPtr rgfReserved,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetDisplayNameOf(
PITEMID_CHILD pidl,
uint uFlags,
STRRET pName);
void SetNameOf(
IntPtr hwnd,
PITEMID_CHILD pidl,
[MarshalAs(UnmanagedType.LPWStr)] string pszName,
uint uFlags,
out PITEMID_CHILD ppidlOut);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214f2-0000-0000-c000-000000000046")]
public interface IEnumIDList
{
void Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] PITEMID_CHILD[] rgelt, out int pceltFetched);
void Skip(int celt);
void Reset();
void Clone(out IEnumIDList ppenum);
}
// Windows >= XP
public static class ShellFolderUtilities
{
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, out PIDLIST_ABSOLUTE ppidl);
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetDesktopFolder(out IShellFolder ppshf);
public static readonly int CSIDL_DESKTOP = 0x0000;
public static readonly int CSIDL_BITBUCKET = 0x000a;
// https://blogs.msdn.microsoft.com/oldnewthing/20110830-00/?p=9773
public static void BindToCsidl(int csidl, Guid riid, out object ppv)
{
var pidl = default(PIDLIST_ABSOLUTE);
try
{
int res;
if (csidl != CSIDL_DESKTOP)
{
res = SHGetSpecialFolderLocation(IntPtr.Zero, csidl, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
}
IShellFolder psfDesktop;
res = SHGetDesktopFolder(out psfDesktop);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
if (csidl == CSIDL_DESKTOP)
{
ppv = psfDesktop;
return;
}
psfDesktop.BindToObject(new PIDLIST_RELATIVE { Ptr = pidl.Ptr }, IntPtr.Zero, riid, out ppv);
}
finally
{
Marshal.FreeCoTaskMem(pidl.Ptr);
}
}
public static IEnumerable<PITEMID_CHILD> Enumerate(this IShellFolder sf)
{
IEnumIDList ppenumIDList;
sf.EnumObjects(IntPtr.Zero, 0x00020 /* SHCONTF_FOLDERS */ | 0x00040 /* SHCONTF_NONFOLDERS */, out ppenumIDList);
if (ppenumIDList == null)
{
yield break;
}
var items = new PITEMID_CHILD[1];
while (true)
{
int fetched;
ppenumIDList.Next(items.Length, items, out fetched);
if (fetched == 0)
{
break;
}
yield return items[0];
}
}
}