【发布时间】:2021-02-11 19:15:48
【问题描述】:
我有一个程序可以获取有关 Windows 回收站中文件的信息。我看到的桶访问问题的唯一非拐杖解决方案是使用 shell 环境。
我有一个使用 winapi(shell 环境)从回收站中删除单个文件(或文件夹)的代码,如下所示:
#include <iostream>
#include <shobjidl_core.h>
#include <Shlobj.h>
#include <shlwapi.h>
#include <ntquery.h>
const SHCOLUMNID SCID_RemovedFrom = { PSGUID_DISPLACED, PID_DISPLACED_FROM };
const SHCOLUMNID SCID_RemovedName = { PSGUID_STORAGE, PID_STG_NAME };
const SHCOLUMNID SCID_DateDeleted = { PSGUID_DISPLACED, PID_DISPLACED_DATE };
const SHCOLUMNID SCID_DateCreated = { PSGUID_STORAGE, PID_STG_CREATETIME };
const SHCOLUMNID SCID_DateModifed = { PSGUID_STORAGE, PID_STG_WRITETIME };
const SHCOLUMNID SCID_DateOpened = { PSGUID_STORAGE, PID_STG_ACCESSTIME };
int main() {
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
LPSHELLFOLDER pDesktop = NULL;
SHGetDesktopFolder(&pDesktop);
LPITEMIDLIST pidlRecycleBin = NULL;
SHGetSpecialFolderLocation(NULL, CSIDL_BITBUCKET, &pidlRecycleBin);
IShellFolder2 *pRecycleBin;
pDesktop->BindToObject(pidlRecycleBin, NULL, IID_IShellFolder2, (LPVOID*)&pRecycleBin);
pDesktop->Release();
CoTaskMemFree(pidlRecycleBin);
IEnumIDList* penumFiles;
pRecycleBin->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penumFiles);
STRRET sret;
IFileOperation *pfo;
CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
pfo->SetOperationFlags(FOF_NO_UI);
LPITEMIDLIST pidl = NULL;
BSTR bstr = NULL;
VARIANT vt;
SYSTEMTIME syst;
while (penumFiles->Next(1, &pidl, NULL) != S_FALSE) {
pRecycleBin->GetDisplayNameOf(pidl, SHGDN_NORMAL, &sret); // not a FULL name!!!
StrRetToBSTR(&sret, pidl, &bstr);
std::wcout << bstr << L' ';
SysFreeString(bstr);
pRecycleBin->GetDetailsEx(pidl, &SCID_DateDeleted, &vt);
VariantTimeToSystemTime(vt.date, &syst);
std::wcout << "\t" << syst.wHour << ":" << syst.wMinute << " " << syst.wDay << "." << syst.wMonth << "." << syst.wYear << std::endl;
/*MARK ITEMS TO DELETE*/
SHCreateItemWithParent(NULL, pRecycleBin, pidl, IID_IShellItem, (void**)&shi);
pfo->DeleteItem(shi, NULL);
shi->Release();
CoTaskMemFree(pidl);
}
penumFiles->Release();
pRecycleBin->Release();
/*DELETE MARKED ITEMS*/
pfo->PerformOperations();
pfo->Release();
//Update recycle bin icon [undocumented function]
(void (*)())GetProcAddress(GetModuleHandle(L"shell32.dll"), "SHUpdateRecycleBinIcon")();
CoUninitialize();
return 0;
}
在上面的代码中,在顶部,有常量定义(SCID_RemovedFrom、SCID_RemovedName)用于通过函数GetDetailsEx获取被删除文件所在的路径和名称。但是,生成的名称并不总是包含扩展名,而只有当文件在系统中注册时,才会在文件资源管理器中显示扩展名。在其他情况下,获取的名称不带扩展名。
无论用户的设置如何,我都找不到GetDetailsEx 将返回全名(带扩展名)的常量。到目前为止,我只找到了一个拐杖:使用pRecycleBin->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &sret); 来获取扩展名,但是有一个问题:我无法确定如何解释名称some.docx 和扩展名$RXZH1I6.docx: 是some.docx 的全名(如果显示扩展名)或some.docx.docx 是全名(如果隐藏扩展名)。原来这个拐杖甚至是危险的。
如何获得保证有扩展名的任何文件(“非文件夹”)的名称?
【问题讨论】:
-
@RemyLebeau 我读了好几遍。正是从这里我拿起了
PSGUID_DISPLACED,这在msdn上没有提到。然而,这里使用了臭名昭著的GetDisplayNameOf,它根据用户的设置提供扩展。我需要保证延期。 -
问题中说明了这一点:
GetDisplayNameOf和pRecycleBin->GetDetailsEx(pidl, &SCID_RemovedName, &vt)都不能给我一个带有扩展名的名字。有时扩展名存在(例如对于 cpp),有时则不存在(例如对于 flac),尽管两者都是文件。 -
你读过Recycle Bin Forensics了吗?最坏的情况是,您可以直接解析 bin 的元数据文件以获得所需的内容。信息就在那里,因为垃圾箱需要它来恢复。
-
我无法重现您的问题,我回收的所有内容都以全名结束。否则,要获取项目的“扩展名”,请使用 PKEY_ItemType(适用于所有外壳项目)和/或 PKEY_FileExtension 物理文件/文件夹外壳项目
标签: c++ winapi windows-shell shell32