c00*_*0fd 9 c++ windows winapi recycle-bin windows-shell
我正在寻找一种方法将文件夹(包含子文件夹)放入具有以下条件的回收站:
它必须以静默方式完成 - 没有任何 Windows UI.
永远不能永久删除该文件夹.如果无法将其放入回收站,我希望API失败.
像CopyFileEx那样获取进程的回调例程.
到目前为止,我能够想出这个:
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;
Run Code Online (Sandbox Code Playgroud)
哪个位于USB闪存驱动器上的文件夹可怕失败,即尽管有标志,它仍被永久删除FOF_ALLOWUNDO.
所以我是不是做对了,或者SHFileOperation API是非常错误的!
知道如何做我上面概述的内容吗?
编辑:我实现了IRecycleBinManager::WillRecycle@Denis Anisimov建议的方法,但显然更多.这是我的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
Run Code Online (Sandbox Code Playgroud)
然后是呼叫本身:
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();
}
Run Code Online (Sandbox Code Playgroud)
不幸的是我在我应该调用WillRecycle方法的行上遇到这个错误:
运行时检查失败#0 - ESP的值未在函数调用中正确保存.这通常是调用使用一个调用约定声明的函数和使用不同调用约定声明的函数指针的结果.

Den*_*mov 10
每个驱动器都有自己的回收站.当您从驱动器С中删除文件时:它应该被移动到驱动器上的回收站С:.从USB驱动器中删除文件时,应将其移至USB驱动器上的回收站.但是当USB驱动器没有回收站时,文件将被永久删除.这是默认的Windows行为.
FOF_ALLOWUNDO标志仅为推荐.MSDN说FOF_ALLOWUNDO标志:
如果可能,请保留撤消信息.
因此,即使使用FOF_ALLOWUNDO标志,Windows永久删除文件也没有任何错误.
我看到的唯一方法是在删除操作之前使用SHQueryRecycleBin函数(在评论中由Alex Farber指出)检查驱动器上是否存在回收站.但即使回收站出现,也不能完全保证文件将被删除到回收站.回收站具有最大大小限制,并且可以已满.
UPDATE
你可以使用hack.您可以使用自己的代码模拟将文件删除到回收站,这将在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;
Run Code Online (Sandbox Code Playgroud)
您可以使用以下代码检查将文件删除到回收站的可能性:
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;
Run Code Online (Sandbox Code Playgroud)
更新3
您也可以尝试使用以下代码删除oject到回收站:
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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2226 次 |
| 最近记录: |