我正在撰寫一個 MFC 程式,它偶爾可以洗掉包含所有內容的目錄。這些目錄將位于%LOCALAPPDATA%\MyApp中,因此不會出現權限問題(至少我希望如此)。
我的第一個猜測是遞回使用 CFileFind 以及 DeleteFile 和 DeleteDirectory Win32 函式,但是快速查看 RemoveDirectory檔案將我指向SHFileOperation,最后指向IFileOperation,如果我理解的話,它應該是純 Windows 桌面應用程式必須的方式與檔案系統互動,所以如果可能的話,我會排除 std::filesystem::remove_all 解決方案。
現在,這肯定是我的問題,因為我討厭 COM,但是我發現這個檔案不是很清楚,如果不是很神秘的話,所以我決定看一下開發人員指南,在那里我找到了檔案操作示例,這肯定有助于理解,但不完全是因為在我的情況下,我必須找到要洗掉的檔案,所以我終于找到了本指南,它應該包含我正在尋找的所有資訊。
現在,如果我遇到這種情況,我必須:
- 訪問桌面,即FS的根目錄;
- 從桌面獲取我的目錄的路徑;
- 執行我的操作;
在普通的 C 中:
void CWindowsUtilities::RemoveDirectory(HWND parent, CString& directory)
{
IShellFolder* desktop;
HRESULT res = SHGetDesktopFolder(&desktop);
if (SUCCEEDED(res))
{
ULONG eaten = 0UL;
LPITEMIDLIST itemIdList;
res = desktop->ParseDisplayName(parent, nullptr, directory.GetBuffer(), &eaten, &itemIdList, nullptr);
if (SUCCEEDED(res))
{
IShellFolder* directoryToDelete;
res = desktop->BindToObject(itemIdList, nullptr, IID_IShellFolder, reinterpret_cast<LPVOID*>(&directoryToDelete));
if (SUCCEEDED(res))
{
IEnumIDList* elementsToDelete;
res = directoryToDelete->EnumObjects(parent, SHCONTF_INCLUDEHIDDEN | SHCONTF_CHECKING_FOR_CHILDREN | SHCONTF_FOLDERS | SHCONTF_NAVIGATION_ENUM, &elementsToDelete);
if (res == S_OK)
{
IFileOperation* fileOp;
res = CoCreateInstance(__uuidof(FileOperation), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&fileOp));
if (SUCCEEDED(res))
{
res = fileOp->SetOperationFlags(FOFX_ADDUNDORECORD | FOFX_RECYCLEONDELETE);
if (SUCCEEDED(res))
{
res = fileOp->QueryInterface(IID_PPV_ARGS(&fileOp));
if (SUCCEEDED(res))
{
res = fileOp->DeleteItems(elementsToDelete);
if (SUCCEEDED(res))
{
res = fileOp->PerformOperations();
}
}
}
}
fileOp->Release();
}
directoryToDelete->Release();
}
CoTaskMemFree(itemIdList);
}
desktop->Release();
}
}
讓運行代碼沒有例外,但在 DeleteItems 我得到:
E_NOINTERFACE No such interface supported.
為了了解我的問題可能出在哪里,我嘗試使用以下方法列舉目錄中的檔案:
void CWindowsUtilities::Navigate(IShellFolder* accesso)
{
IEnumIDListPtr file;
HRESULT res = accesso->EnumObjects(nullptr, SHCONTF_FOLDERS, &file);
if (res == S_OK)
{
LPITEMIDLIST itemID;
ULONG fetched;
while (file->Next(1UL, &itemID, &fetched) == S_OK)
{
STRRET nome = { 0 };
accesso->GetDisplayNameOf(itemID, SHGDN_NORMAL, &nome);
CoTaskMemFree(itemID);
}
file->Release();
}
}
所以我可以看到我可以瀏覽桌面,但不能瀏覽我要洗掉的目錄。我也嘗試使用 SHParseDisplayName 而不是 desktop->ParseDisplayName 但沒有成功,即使我得到了不同的itemIdList。
我究竟做錯了什么?
uj5u.com熱心網友回復:
您可以使用SHFileOperation它已在 Windows vista 中被替換,但仍然很好用。
SHFILEOPSTRUCT SHFileOp, SHDirOp;
ZeroMemory(&SHDirOp, sizeof(SHFILEOPSTRUCT));
SHDirOp.hwnd = NULL;
SHDirOp.wFunc = FO_DELETE;
SHDirOp.pFrom = _T("path to folder");
SHDirOp.pTo = NULL;
SHDirOp.fFlags =
FOF_MULTIDESTFILES /* | FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION */;
//The Copying Function
SHFileOperation(&SHDirOp);
如果您真的想使用 IFileOperator,那么您可以使用它:
BOOL deleteFileOrFolder(LPCWSTR fileOrFolderPath) {
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr)) {
//Couldn't initialize COM library - clean up and return
MessageBox(NULL, L"Couldn't initialize COM library", L"Whoops", MB_OK | MB_ICONERROR);
CoUninitialize();
return FALSE;
}
//Initialize the file operation
IFileOperation* fileOperation;
hr = CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&fileOperation));
if (FAILED(hr)) {
//Couldn't CoCreateInstance - clean up and return
MessageBox(NULL, L"Couldn't CoCreateInstance", L"Whoops", MB_OK | MB_ICONERROR);
CoUninitialize();
return FALSE;
}
hr = fileOperation->SetOperationFlags(FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI);
if (FAILED(hr)) {
//Couldn't add flags - clean up and return
MessageBox(NULL, L"Couldn't add flags", L"Whoops", MB_OK | MB_ICONERROR);
fileOperation->Release();
CoUninitialize();
return FALSE;
}
IShellItem* fileOrFolderItem = NULL;
hr = SHCreateItemFromParsingName(fileOrFolderPath, NULL, IID_PPV_ARGS(&fileOrFolderItem));
if (FAILED(hr)) {
//Couldn't get file into an item - clean up and return (maybe the file doesn't exist?)
MessageBox(NULL, L"Couldn't get file into an item", L"Whoops", MB_OK | MB_ICONERROR);
fileOrFolderItem->Release();
fileOperation->Release();
CoUninitialize();
return FALSE;
}
hr = fileOperation->DeleteItem(fileOrFolderItem, NULL); //The second parameter is if you want to keep track of progress
fileOrFolderItem->Release();
if (FAILED(hr)) {
//Failed to mark file/folder item for deletion - clean up and return
MessageBox(NULL, L"Failed to mark file/folder item for deletion", L"Whoops", MB_OK | MB_ICONERROR);
fileOperation->Release();
CoUninitialize();
return FALSE;
}
hr = fileOperation->PerformOperations();
fileOperation->Release();
CoUninitialize();
if (FAILED(hr)) {
//failed to carry out delete - return
MessageBox(NULL, L"failed to carry out delete", L"Whoops", MB_OK | MB_ICONERROR);
return FALSE;
}
return TRUE;
}
這兩種方法已經在 SO 中分別在以下鏈接中得到解決:
https://stackoverflow.com/a/22226730/1856251
https://stackoverflow.com/a/68736092/1856251
查看您的代碼,我可以看到您做錯的一件事是,根據 IFileOperation::DeleteItems 檔案,它需要以下之一的指標:IShellItemArray、IDataObject、IEnumShellItems 或 IPersistIDList。但是您正在傳遞一個 IEnumIDList 指標。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/528652.html
標籤:C 温纳皮com窗口外壳
上一篇:檢查和保護C 中的執行緒
