I have a program that gets information about files in the windows recycle bin. The only non-crutch solution to the bucket access problem I see is using the shell environment.
I have a code for removing single file (or folder) from recycle bin with winapi (shell envirionment) like the next:
#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;
}
In the code above, at the top, there are constant definitions (SCID_RemovedFrom, SCID_RemovedName) for getting the path where the deleted file was located and the name via the function GetDetailsEx. However, the resulting name does not always contain the extension, but only when the file is registered in the system in such a way that the extension is displayed in File Explorer. In other cases, the name is obtained without an extension.
I couldn't find a constant where GetDetailsEx will return the full name (with the extension) regardless of the user's settings. So far, I've only found a crutch: use pRecycleBin->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &sret); to get extensions, BUT there a problem: I can't determine how to interpret the name some.docx and extension $RXZH1I6.docx: is some.docx a full name (if extensions are shown) or some.docx.docx is a full name (if extensions are hidden). It turns out that this crutch is even dangerous.
How can I get the name of any file ("NONFOLDER") guaranteed to have an extension?
Here is some sample code (using ATL for smart pointers) that displays all properties for all items in the recycle bin (or any other folder you'd like).
You can pick the properties you want. I've dumped a sample output with a deleted txt file. The item's display name actually depends on the maching settings, but you can see there are lots of other interesting properties, for example:
System.Recycle.DeletedFrom(eq to SCID_RemovedFrom)System.Recycle.DateDeleted(eq to SCID_DateDeleted)System.ItemNameDisplay(note for virtual items, you won't always have a System.FileName)System.ItemType(note for virtual items, you won't always have a System.FileExtension)Sample output:
Sample code: