フォルダ選択ダイアログボックス


ファイルを選ぶダイアログボックスはOpenDialogコンポーネントなどを使って簡単に表示できますが、フォルダを選ぶダイアログボックスはDirectoryListBoxコンポーネントなどを組み合わせて作るなどをして表示させるしかありません。

ところが、Win32 APIを使うとフォルダ選択ダイアログ(下の図)を表示させることができます。ただし、けっこう面倒です。

 

 

使うAPI関数は、SHBrowseForFolderとSHGetPathFromIDListです。つまり、SHBrowseForFolderでフォルダのIDリストを取得して、SHGetPathFromIDListでフォルダ名に変換するという2段階の手順をとります。

これらのAPI関数はWindowsパッケージで宣言されていないので、プログラムの中で宣言する必要があります。次にサンプルを示します。

unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  SHITEMID = record
  	cb: Word;
    abID: PByte;
  end;

  ITEMIDLIST = record
  	mkid: SHITEMID;
  end;

  LPITEMIDLIST = ^ITEMIDLIST;

  BROWSEINFO = record
  	hwndOwner: LongWord;
    pidlRoot: LPITEMIDLIST;
    pszDisplayName: PChar;
    lpszTitle: PChar;
    ulFlags: LongWord;
    lpfn: Pointer;
    lParam: LongWord;
    iImage: Integer;
  end;

  LPBROWSEINFO = ^BROWSEINFO;

  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function SHBrowseForFolder(lpbi: LPBROWSEINFO): LPITEMIDLIST; stdcall;  external 'Shell32.dll';
function SHGetPathFromIDList(idlist: LPITEMIDLIST; pszPath: PChar): LongWord; stdcall; external 'Shell32.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
    bi: BROWSEINFO;
    buff: PChar;
    idlist: LPITEMIDLIST;
    lpDir: PChar;
begin
    buff := StrAlloc(MAX_PATH);
    lpDir := StrAlloc(MAX_PATH);
    bi.hwndOwner := Self.Handle;
    bi.pidlRoot := nil;
    bi.pszDisplayName := buff;
    bi.lpszTitle := 'フォルダを選んでください';
    bi.iImage := 0;
    bi.ulFlags := 0;
    bi.lParam := 0;
    bi.lpfn := nil;
    idlist := SHBrowseForFolder(@bi);
    if idlist <> nil then
    begin
        SHGetPathFromIDList(idlist, lpDir);
        Label1.Caption := lpDir;
    end;
    StrDispose(buff);
    StrDispose(lpDir);
end;

end.