Bill
Bill

Reputation: 3033

TFileDialogEvent.OnSelectionChange GetFolder

[EDIT]

function PathFromShellItem(AShellItem: IShellItem): string;
{Helper function to get path from ShellItem}
var
  hr: HRESULT;
  iPath: PWideChar;
begin
  hr := AShellItem.GetDisplayName(SIGDN_FILESYSPATH, iPath);
  if hr = 0 then
    Result := iPath
  else
    Result := '';
end;

The code below attempts to get the foldername and filename from an IShellItem. The filename (iName) is obtained correctly but the folder name (iFolder) is always "". Why doesn't pfd.GetFolder return the folder name? Am I trying to get the folder name the wrong way?

function TFileDialogEvent.OnSelectionChange(const pfd: IFileDialog): HResult; stdcall;
{Handle the OnSelectionChange event and fill labels with information}
var
  ShellItem: IShellItem;
  iFilename: string;
  iFolder: string;
  iName: PWideChar;
begin
  if pfd.GetFolder(ShellItem) = S_OK then
    iFolder := PathFromShellItem(ShellItem);
  OleCheck(pfd.GetFileName(iName));
  {Set the filepath}
  if DirectoryExists(iFolder) then
    iFilename := IncludeTrailingPathDelimiter(iFolder) + string(iName);
end;

Upvotes: 1

Views: 263

Answers (1)

David Heffernan
David Heffernan

Reputation: 613302

You code for PathFromShellItem is incorrect. You want something like this, inspired by the VCL code for file dialogs:

function GetItemName(const Item: IShellItem; var ItemName: string): HRESULT;
var
  pszItemName: PWideChar;
begin
  Result := Item.GetDisplayName(SIGDN_FILESYSPATH, pszItemName);
  if Failed(Result) then
    Result := Item.GetDisplayName(SIGDN_NORMALDISPLAY, pszItemName);
  if Succeeded(Result) then
  try
    ItemName := pszItemName;
  finally
    CoTaskMemFree(pszItemName);
  end;
end;

function FileDialogFilename(const pfd: IFileDialog): string;
var
  Item: IShellItem;
  FileName: string;
  pszFileName: PWideChar;
begin
  if Succeeded(pfd.GetFolder(Item)) and 
     Succeeded(GetItemName(Item, FileName)) and
     Succeeded(pfd.GetFileName(pszFileName)) then
  try
    Result := TPath.Combine(FileName, pszFileName);
  finally
    CoTaskMemFree(pszFileName);
  end;
end;

You can use TCustomFileDialog.GetFileName as your template for this code, if you can't actually use TFileOpenDialog itself. Come to think of it, why can't you just use TFileOpenDialog.

Upvotes: 2

Related Questions