furybowser
furybowser

Reputation: 13

Directory listing in c++ Builder 6

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

Answers (1)

Remy Lebeau
Remy Lebeau

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:

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);
}
#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);
}
#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

Related Questions