Reputation: 13
I need to get a directory listing of a specific directory (like dir /b in cmd) that is in the same place as my app's exe file.
Here is what I have tried:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
BROWSEINFO BrowsingInfo;
LPITEMIDLIST ItemID;
char szDirPath[MAX_PATH];
memset(&BrowsingInfo, 0, sizeof(BROWSEINFO));
memset(szDirPath, 0, MAX_PATH);
memset(szFolderName, 0, MAX_PATH);
BrowsingInfo.hwndOwner = Application->Handle;
BrowsingInfo.lpszTitle = "Select A Folder";
BrowsingInfo.ulFlags = BIF_RETURNONLYFSDIRS;
ItemID = SHBrowseForFolder(&BrowsingInfo);
SHGetPathFromIDList(ItemID, szDirPath);
Label1->Caption = szDirPath;
}
Upvotes: 0
Views: 636
Reputation: 596216
That code gives you a path to a folder that is selected by the user.
To then get the contents of that folder, you have to enumerate the contents manually. You have a few options for that:
FindFirstFile()
and FindNextFile()
functions:void __fastcall TForm1::Button1Click(TObject *Sender)
{
BROWSEINFO BrowsingInfo = {};
BrowsingInfo.hwndOwner = this->Handle;
BrowsingInfo.lpszTitle = "Select A Folder";
BrowsingInfo.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST ItemID = SHBrowseForFolder(&BrowsingInfo);
if (!ItemID)
return;
char szDirPath[MAX_PATH] = {};
bool bDirPathOK = SHGetPathFromIDListA(ItemID, szDirPath);
CoTaskMemFree(ItemID);
if (!bDirPathOK)
return;
Label1->Caption = szDirPath;
WIN32_FIND_DATAA fd;
HANDLE hFind = FindFirstFileA((Label1->Caption+"\\*").c_str(), &fd);
if (hFind == INVALID_HANDLE_VALUE)
return;
do {
if ((strcmp(fd.cFileName, ".") != 0) && (strcmp(fd.cFileName, "..") != 0)) {
// use fd as needed...
}
}
while (FindNextFileA(hFind, &fd));
FindClose(hFind);
}
FindFirst()
and FindNext()
functions (in SysUtils.hpp
):#include <SysUtils.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
BROWSEINFO BrowsingInfo = {};
BrowsingInfo.hwndOwner = this->Handle;
BrowsingInfo.lpszTitle = "Select A Folder";
BrowsingInfo.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST ItemID = SHBrowseForFolder(&BrowsingInfo);
if (!ItemID)
return;
char szDirPath[MAX_PATH];
bool bDirPathOK = SHGetPathFromIDListA(ItemID, szDirPath);
CoTaskMemFree(ItemID);
if (!bDirPathOK)
return;
Label1->Caption = szDirPath;
TSearchRec sr;
if (FindFirst(Label1->Caption+"\\*", faAnyFile, sr) != 0)
return;
do {
if ((sr.Name != ".") && (sr.Name != "..")) {
// use sr as needed...
}
}
while (FindNext(sr) == 0);
FindClose(sr);
}
IShellFolder
interface, in particular its EnumObjects()
method:#include <shlobj.h>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
BROWSEINFO BrowsingInfo = {};
BrowsingInfo.hwndOwner = this->Handle;
BrowsingInfo.lpszTitle = "Select A Folder";
BrowsingInfo.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST ItemID = SHBrowseForFolder(&BrowsingInfo);
if (!ItemID)
return;
char szDirPath[MAX_PATH];
if (!SHGetPathFromIDListA(ItemID, szDirPath)) {
CoTaskMemFree(ItemID);
return;
}
Label1->Caption = szDirPath;
IShellFolder *desktop;
if (FAILED(SHGetDesktopFolder(&desktop))) {
CoTaskMemFree(ItemID);
return;
}
IShellFolder *sf;
HRESULT hres = desktop->BindToObject(ItemID, NULL, IID_IShellFolder, (void**)&sf);
desktop->Release();
CoTaskMemFree(ItemID);
if (FAILED(hres))
return;
IEnumIDList *enum;
if (FAILED(sf->EnumObjects(this->Handle, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &enum))) {
sf->Release();
return;
}
PITEMID_CHILD ChildID;
while (enum->Next(1, &ChildID, NULL) == S_OK) {
// use ChildID as needed, such as with
// sf->GetAttributesOf(), sf->GetDisplayNameOf(), etc...
CoTaskMemFree(ChildID);
}
enum->Release();
sf->Release();
}
BTW, C++Builder also has a SelectDirectory()
function (in FileCtrl.hpp
) that wraps the SHBrowseForFolder()
API for you:
#include <FileCtrl.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String DirPath;
if (!SelectDirectory("Select A Folder", L"", DirPath))
return;
Label1->Caption = DirPath;
...
}
Upvotes: 0