如何“安全”删除文件夹到回收站

我正在寻找一种方法将文件夹(与子文件夹)放入一个回收站与这些条件:

  1. 它必须默默地完成 – 没有任何 Windows用户界面。

  2. 该文件夹不能永久删除。 如果它不能被放入回收站,我希望API失败。

  3. 获取像CopyFileEx这样的过程的callback例程。

到目前为止,我能够想出这个:

SHFILEOPSTRUCT sfo = {0}; sfo.wFunc = FO_DELETE; sfo.pFrom = L"K:\\test del from USB\0"; //Folder on a USB stick sfo.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR | FOF_WANTNUKEWARNING; int res = SHFileOperation(&sfo); BOOL bFullSuccess = res == 0 && !sfo.fAnyOperationsAborted; 

在USB闪存驱动器上的文件夹可怕地失败,即,即使FOF_ALLOWUNDO标志被永久删除。

所以不pipe我是不是做对了,或者SHFileOperation API是错误的!

任何想法如何做我上面概述的?

编辑:我实现了IRecycleBinManager::WillRecycle Anisimovbuild议的IRecycleBinManager::WillRecycle方法,但显然更多。 这是我的C ++版本。 我需要的方法的第一个接口定义:

 #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("5869092D-8AF9-4A6C-AE84-1F03BE2246CC") IRecycleBinManager : public IUnknown { public: //function WillRecycle(const pszPath: LPCWSTR): HRESULT; stdcall; virtual HRESULT STDMETHODCALLTYPE WillRecycle( /* [string][in] */ __RPC__in LPCWSTR pszFile) = 0; }; #endif 

然后通话本身:

 HRESULT hr; CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED); // {4A04656D-52AA-49DE-8A09-CB178760E748} const CLSID CLSID_RecycleBinManager = {0x4A04656D, 0x52AA, 0x49DE, {0x8A, 0x09, 0xCB, 0x17, 0x87, 0x60, 0xE7, 0x48}}; // {5869092D-8AF9-4A6C-AE84-1F03BE2246CC} const IID IID_IRecycleBinManager = {0x5869092D, 0x8AF9, 0x4A6C, {0xAE, 0x84, 0x1F, 0x03, 0xBE, 0x22, 0x46, 0xCC}}; IRecycleBinManager* pIRBM = NULL; hr = CoCreateInstance(CLSID_RecycleBinManager, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IRecycleBinManager, (void**) &pIRBM); // hr = SHCoCreateInstance(NULL, &CLSID_RecycleBinManager, NULL, IID_IRecycleBinManager, (void **)&pIRBM); if (SUCCEEDED(hr)) { hr = pIRBM->WillRecycle(L"C:\\test del"); //Crashes pIRBM->Release(); } 

不幸的是,我得到了这个错误,我应该打电话给WillRecycle方法:

运行时检查失败#0 – ESP的值在函数调用中未正确保存。 这通常是调用一个函数指针与一个调用约定声明一个函数指针与一个不同的调用约定声明的结果。

在这里输入图像说明

Solutions Collecting From Web of "如何“安全”删除文件夹到回收站"

每个驱动器都有自己的回收站。 而当你从驱动器С:删除文件:它应该被移动到驱动器С:回收站。 从USB驱动器中删除文件时,应将其移至USB驱动器上的“回收站”。 但是,当USB驱动器没有回收站时,文件被永久删除。 这是默认的Windows行为。

FOF_ALLOWUNDO标志只是推荐。 MSDN说关于FOF_ALLOWUNDO标志:

如有可能 ,保留撤消信息。

所以即使在使用FOF_ALLOWUNDO标志的情况下,Windows永久删除文件也没有任何错误。

我看到的唯一方法是在删除操作之前使用SHQueryRecycleBin函数(在Alex Farber的评论中指出)检查驱动器上的回收站的存在。 但即使回收站提交它不是充分保证文件将被删除到回收站。 回收站具有最大限制的大小,它可以已经满了。

UPDATE

你可以使用黑客。 您可以使用自己的代码模拟将文件移入回收站,这将在C:\ $ Recycle.Bin \ UserSID文件夹中创建所有必要的系统记录。 我在Windows 7上测试了这个方法,它工作正常。 它允许忽略回收站的最大大小的限制。 此外,它允许将文件从USB移动到任何驱动器上的回收站。

更新2

对于Vista +,您可以使用未公开的界面IRecycleBinManager(俄罗斯的说明可以在http://rcrrad.com/2010/10/14/bitbucket-interfaces/网页上找到):

 const IID_IEnumRecycleItems: TGUID = '{6E325F88-D12F-49E5-895B-8EC98630C021}'; IID_IRecycle: TGUID = '{0125E62F-8349-443A-854B-A55FB84CFA35}'; IID_IRecycleBin: TGUID = '{F964AD97-96F4-48AB-B444-E8588BC7C7B3}'; IID_IRecycleBinManager: TGUID = '{5869092D-8AF9-4A6C-AE84-1F03BE2246CC}'; CLSID_RecycleBinManager: TGUID = '{4A04656D-52AA-49DE-8A09-CB178760E748}'; type { Тип Корзины } tagRECYCLEBIN_TYPE = (RBTYPE_VOLUME, RBTYPE_KNOWNFOLDER); TRecycleBinType = tagRECYCLEBIN_TYPE; { Данные об удаленном элементе } PDeletedItem = ^TDeletedItem; tagDELETEDITEM = packed record dwFileSizeLow: DWORD; dwFileSizeHigh: DWORD; ftDeletionTime: TFileTime; szOriginalPath: array[0..Pred(MAX_PATH)] of WideChar; szDisplacedPath: array[0..Pred(MAX_PATH)] of WideChar; end; TDeletedItem = tagDELETEDITEM; { Перечислитель элементов Корзины } IEnumRecycleItems = interface(IUnknown) ['{6E325F88-D12F-49E5-895B-8EC98630C021}'] { celt может быть равен только единице } function Next(celt: ULONG; out rgelt: TDeletedItem; var pceltFetched: ULONG): HRESULT; stdcall; { Not Implemented } function Skip(celt: ULONG): HRESULT; stdcall; function Reset: HRESULT; stdcall; { Not Implemented } function Clone(out ppenum: IEnumRecycleItems): HRESULT; stdcall; end; { "Интерфейс-переходник" между IRecycleBin и IRecycleBinManager } IRecycle = interface(IUnknown) ['{0125E62F-8349-443A-854B-A55FB84CFA35}'] function Compact(): HRESULT; stdcall; function GetFileData(const pszPath: LPCWSTR; out lpData: TDeletedItem): HRESULT; stdcall; function GetItemCount(out lpCount: TLargeInteger): HRESULT; stdcall; function GetUsedSpace(out lpUsedSpace: TLargeInteger): HRESULT; stdcall; function IsEmpty(): HRESULT; stdcall; function PurgeAll(pfo: IFileOperation): HRESULT; stdcall; function PurgeItems(const lpstrItems: LPCWSTR; pfo: IFileOperation): HRESULT; stdcall; function SuspendUpdating(fSuspend: BOOL): HRESULT; stdcall; function RecycleItem(const lpstrItem: LPCWSTR; const dwAttrs: DWORD; const iFileSize: TLargeInteger; out psi: IShellItem): HRESULT; stdcall; function RestoreItems(const lpstrItems: LPCWSTR; pfo: IFileOperation): HRESULT; stdcall; function IsRecycled(const pszPath: LPCWSTR; lpRecycled: PBOOL): HRESULT; stdcall; function EnumItems(dwFlags: DWORD; out EnumRecycleItems: IEnumRecycleItems): HRESULT; stdcall; function WillRecycle(const pszPath: LPCWSTR): HRESULT; stdcall; end; { Представляет определенную Корзину на конкретном диске } IRecycleBin = interface(IUnknown) ['{F964AD97-96F4-48AB-B444-E8588BC7C7B3}'] function Compact(): HRESULT; stdcall; function GetFileData(const pszPath: LPCWSTR; out lpData: TDeletedItem): HRESULT; stdcall; function GetItemCount(out lpCount: TLargeInteger): HRESULT; stdcall; function GetUsedSpace(out lpUsedSpace: TLargeInteger): HRESULT; stdcall; function IsEmpty(): HRESULT; stdcall; function PurgeAll(pfo: IFileOperation): HRESULT; stdcall; function PurgeItems(const lpstrItems: LPCWSTR; pfo: IFileOperation): HRESULT; stdcall; function SuspendUpdating(fSuspend: BOOL): HRESULT; stdcall; function RecycleItem(const lpstrItem: LPCWSTR; const dwAttrs: DWORD; const iFileSize: TLargeInteger; out psi: IShellItem): HRESULT; stdcall; function RestoreItems(const lpstrItems: LPCWSTR; pfo: IFileOperation): HRESULT; stdcall; function IsRecycled(const pszPath: LPCWSTR; lpRecycled: PBOOL): HRESULT; stdcall; function EnumItems(dwFlags: DWORD; out EnumRecycleItems: IEnumRecycleItems): HRESULT; stdcall; function WillRecycle(const pszPath: LPCWSTR): HRESULT; stdcall; function Initialize(const rbType: TRecycleBinType; const pszID: LPCWSTR): HRESULT; stdcall; function GetTypeID(out rbType: TRecycleBinType; var pszID: LPWSTR): HRESULT; stdcall; function GetIDList(out ppidl: PItemIDList): HRESULT; stdcall; function GetLocation(pszPathBuffer: LPWSTR; cchMax: DWORD): HRESULT; stdcall; function GetMaxCapacityRange(out lpMin: TLargeInteger; out lpMax: TLargeInteger): HRESULT; stdcall; function GetMaxCapacity(out lpCapacity: TLargeInteger): HRESULT; stdcall; function SetMaxCapacity(const lpCapacity: TLargeInteger): HRESULT; stdcall; function GetPurgeOnDelete(out fNukeOnDelete: BOOL): HRESULT; stdcall; function SetPurgeOnDelete(const fNukeOnDelete: BOOL): HRESULT; stdcall; end; { Менеджер всех Корзин данной ОС } IRecycleBinManager = interface(IUnknown) ['{5869092D-8AF9-4A6C-AE84-1F03BE2246CC}'] function Compact(): HRESULT; stdcall; function GetFileData(const pszPath: LPCWSTR; out lpData: TDeletedItem): HRESULT; stdcall; function GetItemCount(out lpCount: TLargeInteger): HRESULT; stdcall; function GetUsedSpace(out lpUsedSpace: TLargeInteger): HRESULT; stdcall; function IsEmpty(): HRESULT; stdcall; function PurgeAll(pfo: IFileOperation): HRESULT; stdcall; function PurgeItems(const lpstrItems: LPCWSTR; pfo: IFileOperation): HRESULT; stdcall; function SuspendUpdating(fSuspend: BOOL): HRESULT; stdcall; { Not Implemented } function RecycleItem(const lpstrItem: LPCWSTR; const dwAttrs: DWORD; const iFileSize: TLargeInteger; out psi: IShellItem): HRESULT; stdcall; function RestoreItems(const lpstrItems: LPCWSTR; pfo: IFileOperation): HRESULT; stdcall; function IsRecycled(const pszPath: LPCWSTR; lpRecycled: PBOOL): HRESULT; stdcall; function EnumItems(dwFlags: DWORD; out EnumRecycleItems: IEnumRecycleItems): HRESULT; stdcall; function WillRecycle(const pszPath: LPCWSTR): HRESULT; stdcall; function DelayCompaction(const fDelay: BOOL): HRESULT; stdcall; function GetRecycleBinCount(out iCount: Integer): HRESULT; stdcall; function GetRecycleBinAt(const index: Integer; const iid: TGUID; out ppv): HRESULT; stdcall; function GetRecycleBin(const pszPath: LPCWSTR; const iid: TGUID; out ppv): HRESULT; stdcall; function Refresh(): HRESULT; stdcall; end; 

您可以使用以下代码检查将文件删除到回收站中的可能性:

 function CanFileBeDeletedToRecycleBin(const AFileName: UnicodeString): Boolean; var RecycleBinManager: IRecycleBinManager; begin OleCheck(CoCreateInstance(CLSID_RecycleBinManager, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IRecycleBinManager, RecycleBinManager)); try Result := RecycleBinManager.WillRecycle(PWideChar(AFileName)) = S_OK; finally RecycleBinManager := nil; end; end; 

更新3

你也可以尝试下面的代码删除对象回收站:

 function GetObjectSize(const AFileName: UnicodeString): Int64; var FindHandle: THandle; FindData: TWin32FindDataW; S: Int64; begin Result := 0; FindHandle := FindFirstFileW(PWideChar(AFileName), FindData); if FindHandle = INVALID_HANDLE_VALUE then RaiseLastOSError; try repeat if (FindData.cFileName <> UnicodeString('.')) and (FindData.cFileName <> '..') then begin Int64Rec(S).Lo := FindData.nFileSizeLow; Int64Rec(S).Hi := FindData.nFileSizeHigh; Result := Result + S; if FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then Result := Result + GetObjectSize(AFileName + '\*.*'); end; until not FindNextFileW(FindHandle, FindData); finally FindClose(FindHandle); end; end; procedure DeleteToRecycleBin(const AFileName: UnicodeString); var Attr: DWORD; Size: Int64; RecycleBinManager: IRecycleBinManager; RecycleBin: IRecycleBin; ShellItem: IShellItem; begin OleCheck(CoCreateInstance(CLSID_RecycleBinManager, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IRecycleBinManager, RecycleBinManager)); try OleCheck(RecycleBinManager.GetRecycleBin(PWideChar(AFileName), IRecycleBin, RecycleBin)); try Attr := GetFileAttributes(PWideChar(AFileName)); Size := GetObjectSize(AFileName); OleCheck(RecycleBin.RecycleItem(PWideChar(AFileName), Attr, Size, ShellItem)); ShellItem := nil; finally RecycleBin := nil; end; finally RecycleBinManager := nil; end; end; 

我能够想出一个解决方案,我所有的原始要点/要求3。

简而言之,需要使用IFileOperation接口并在其中实现IFileOperationProgressSink

这是完整的代码示例和解释。

编辑:好的,还有更多。 我上面贴的方法不包括所有的碱基:(