Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2008年11月24日] [更新 2018年07月10日] Delphi サンプルプログラム集
801_フォルダの参照ダイアログ
動作確認等 Windows 7 U64(SP1) + Delphi XE Pro
一部 Windows 7 U64(SP1) + Delphi 10.2 Tokyo Stater
801_FolderBrowser.zip [4,817 KB] 2018年07月10日版 (EXE 同梱)



  • 2013年11月16日
  • サンプルを関数別にして記事とコードを整備
  • Delphi 7 用のサンプルの添付は中止




フォルダの参照ダイアログ


SelectDirectory 関数と,SHBrowseForFolder 関数を使用した [フォルダの参照] ダイアログ表示のテストプログラムです.

SelectDirectory 関数は,Delphi 7 では旧スタイル,Delphi 2007 では自動的に,サイズ可変の新しいスタイルとなります.SHBrowseForFolder 関数を使用すれば,Delphi のバージョンと無関係に同じスタイルとすることができます.

SelectDirectory 関数では,ルートフォルトと,ダイアログを表示した時に選択状態にするフォルダを指定することができます.ルートフォルダとは,ダイアログを表示した時に先頭に表示するフォルダで,このフォルダより上の階層は表示できません.
SHBrowseForFolder 関数でもルートフォルダが指定できます.SHBrowseForFolder 関数で,選択状態にするフォルダ (初期フォルダ) を設定するには,コールバック関数を使用します.



[備考]
フォルダの選択ダイアログでは,指定したフォルダを選択状態にして表示できますが,新しいスタイルのダイアログでは,選択フォルダまでスクロールしてくれない場合があります.





01_SelectDirectory 関数 - 第 1 の構文


Vcl.FileCtrl.pas の SelectDirectory 関数のヘルプを見ると,overload な関数が 3 つあります.
最初の構文には下表の引数があります.これは,下の図のような Windows 3.1 時代のスタイルのダイアログを表示します.



引数名 説明
var Directory string 選択したフォルダ名
Options TSelectDirOpts

TSelectDirOpt の集合

HelpCtx LongInt ヘルプのコンテキスト ID 番号


図1
Windows 3.1 時代のダイアログ
  • [Win3.1] タブの以下のコンポーネント等を組み合わせたダイアログ
    TDirectoryListBox
    TFileListBox
    TDriveComboBox

リスト1
SelectDirectory 関数を使用したフォルダの参照ダイアログの表示
[Win3.1] タブのコンポーネントを使用したダイアログと同じスタイル
unit Unit1;

interface

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

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

var
  Form1: TForm1;

implementation

uses
  FileCtrl;

{$R *.dfm}

//=============================================================================
//  SelectDirectory関数で[フォルダの参照]ダイアログを表示
//  [Win3.1] タブのコンポーネントを使用したダイアログと同じスタイル
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  SelectFolder : String;
begin
  if SelectDirectory(SelectFolder, [], 0) then begin
    //
  end;
end;

end.




02_SelectDirectory 関数 - 第 2 の構文


以下の表は SelectDirectory 関数の 2 番目の構文における引数です.
その下の表は引数のオプションで設定可能な値です.新しいスタイルとは,Windows Vista で実装されたスタイルのダイアログのことです.



引数名 説明
Caption string ダイアログのタイトル (キャプションではない)
Root WideString

ルートディレクトリ
Directory と同じ変数名は使用できない

var Directory string 選択したフォルダ
Root と同じ変数名は使用できない
Options TSelectDirExtOpts = [] TSelectDirExtOpt の集合.下の表を参照
Parent TWinControl = nil 用途については不明


TSelectDirExtOpt のメンバ 説明
sdNewUI サイズ可変の新しいスタイルのダイアログを表示する
Delphi 2007 以降ではデフォルトでこのスタイル
Delphi 2007 より前の Delphi では指定しても無効
Windows XP でも設定は無効となる
sdNewFolder [新しいフォルダの作成] ボタンを表示する
sdShowEdit 名前編集用ボックスを表示する
sdShowShares 共有リソースを表示して選択可能にする
sdShowFiles ファイルも表示して選択可能とする
sdValidateDir 名前編集ボックスへの無効な文字列をチェックする



上の表の引数を使用する SelectDirectory 関数を使用したサンプルです.

オンラインヘルプにも書いてありますが,ルートフォルダと選択フォルダには同じ変数名を使わないようにします.挙動が怪しくなる場合があります.このことは,内部処理の結果,戻り値を返す可変型変数,つまり,var 渡しの変数に対して,一般的に言えることです.



図2
設計時画面
図3
デフォルトで関数を実行
図4
ルートフォルダを指定して起動
図5
スタイルを指定して起動

リスト2
SelectDirectory 関数の第 2 の構文を使用したフォルダの参照ダイアログの表示
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses FileCtrl, ShlObj, ActiveX;

{$R *.dfm}

//=============================================================================
//  SelectDirectory関数で[フォルダの参照]ダイアログを表示
//  デフォルトの設定で起動
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  RootFolder   : String;
  SelectFolder : String;
begin
  if SelectDirectory('フォルダの指定', RootFolder, SelectFolder) then begin
    MessageBox(Handle, PChar(SelectFolder), '選択フォルダ', MB_ICONINFORMATION);
  end;
end;

//=============================================================================
//  SelectDirectory関数で[フォルダの参照]ダイアログを表示
//  ルートフォルダはGUID値でマイネットワークを指定
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  RootFolder   : WideString;
  SelectFolder : String;
begin
  RootFolder := '::{208D2C60-3AEA-1069-A2D7-08002B30309D}';

  if SelectDirectory('フォルダの指定', RootFolder, SelectFolder) then begin
    MessageBox(Handle, PChar(SelectFolder), '選択フォルダ', MB_ICONINFORMATION);
  end;
end;

//=============================================================================
//  SelectDirectory関数で[フォルダの参照]ダイアログを表示
//  スタイルの指定例
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  RootFolder   : String;
  SelectFolder : String;
begin
 RootFolder   := '';
 SelectFolder := '';

 {$IF CompilerVersion > 18.49}
 if SelectDirectory('フォルダの指定',
                    RootFolder,
                    SelectFolder,
                    [sdNewUI, sdNewFolder, sdShowEdit],
                    Self) then begin
   MessageBox(Handle, PChar(SelectFolder), '選択フォルダ', MB_ICONINFORMATION);
 end;
 {$ELSE}
 MessageBox(Handle, '利用できません', '使用不可', MB_ICONWARNING);
 {$IFEND}
end;

end.




03_SelectDirectory 関数 - 第 3 の構文


SelectDirectory 関数の 3 番目の構文の引数は以下の表のようになっています.
この構文によるダイアログは Delphi 10 Seattle で使用可能になったダイアログで,Delphi 2007 で実装された TFileOpenDialog コンポーネントで表示するダイアログと同じです.このダイアログのデフォルトのキャプションは「フォルダの選択」となります.

下図は Windows 7 U64(SP1) + Delphi 10.2 Tokyo Stater での実行画面です.



引数名 説明
StartDirectory string ダイアログ表示開始時の選択フォルダ名
out Directories TArray<string>

選択したフォルダのリスト
TSelectDirFileDlgOpts で複数選択の設定可能

Options TSelectDirFileDlgOpts = [] TSelectDirFileDlgOpt の集合
Title string = '' ダイアログのキャプション
FolderNameLabel string = '' フォルダ名入力欄のラベル
OkButtonLabel string = '' [OK] ボタンのキャプション


図6
実行画面

リスト3
SelectDirectory 関数の第 3 の構文を使用したフォルダの選択ダイアログの表示
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

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

var
  Form1: TForm1;

implementation

uses
  Vcl.FileCtrl;

{$R *.dfm}

//=============================================================================
//  SelectDirectory関数で[フォルダの参照]ダイアログを表示
//
//  モダンになった[ディレクトリの選択]ダイアログ ボックス
//  Delphi 10 Seattle で実装された形式で表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LStartDir    : string;
  LDirArray    : TArray<string>;
  LTitle       : string;
  LFolderName  : string;
  LBtnCaption  : string;
begin
  LStartDir   := ExpandFileName('..\');
  LTitle      := '';
  LBtnCaption := 'OK';

  if SelectDirectory(LStartDir,
                     LDirArray,
                     [],
                     LTitle,
                     LFolderName,
                     LBtnCaption) then begin
  end;
end;

end.




04_SHBrowseForFolder 関数


SHBrowseForFolder 関数を使用したサンプルです.
SHBrowseForFolder 関数を使用すれば,Delphi のバージョンと無関係に同じスタイルとすることができます.SelectDirectory 関数も第 3 の構文以外は内部でこの関数の機能を使用しています.

SHBrowseForFolder 関数は項目識別子でルートフォルダを指定します.戻り値も項目識別子です.そのため,通常の使用では,フォルダ名を項目識別子へ変換する処理と,その逆の操作を行う処理が必要となってきます.
項目識別子から実パスを取得する確実な方法は,以下の記事の SHGetKnownFolderIDList 関数を使用したコードを参考にしてください.


本サンプルでは,選択したフォルダ名を表示するようにしていますが,SHGetPathFromIDList 関数は,GUID 値で表わされるようなフォルダ等は空文字となります.
SHBrowseForFolder 関数の引数については, 以下の最初のリンクのコールバック関数の記事にに少しだけ詳しい説明があります.


図7
設計時画面
図8
旧スタイルで起動
  • ルートフォルダはデスクトップ
図9
新しいスタイルで起動
  • ルートフォルダはデスクトップ
図10
項目識別子でルートフォルダを指定
  • CSIDL_NETWORK を項目識別子に変換してルートフォルダに指定している

リスト4
SHBrowseForFolder 関数を使用したフォルダの参照ダイアログの表示
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses FileCtrl, ShlObj, ActiveX;

{$R *.dfm}

//=============================================================================
//  SHBrowseForFolder関数で[フォルダの参照]ダイアログを表示
//  旧スタイル
//  ルートフォルダはデスクトップ
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  FolderPidl : PItemIDList;
  BrowseInfo : TBrowseInfo;
  BPathName  : array[0..MAX_PATH-1] of Char;
  AMalloc    : IMalloc;
begin
  //項目識別子解放のためのメモリアロケーションのポインタ取得
  ShGetMalloc(AMalloc);
  FolderPidl := nil;

  FillChar(BrowseInfo, SizeOf(BrowseInfo), #0);
  BrowseInfo.hwndOwner := Handle;
  BrowseInfo.lpfn      := nil;
  BrowseInfo.lpszTitle := PChar('フォルダの指定');
  BrowseInfo.pidlRoot  := nil;
  BrowseInfo.ulFlags   := BIF_RETURNONLYFSDIRS;

  //上の設定に基づきフォルダ参照ダイアログを表示
  try
    FolderPidl := SHBrowseForFolder(BrowseInfo);
    If FolderPidl <> nil then begin
      //項目識別子をパスの文字列BPathNameに変換
      SHGetPathFromIDList(FolderPidl, BPathName);

      MessageBox(Handle, BPathName, '選択フォルダ', MB_ICONINFORMATION);
    end;
  finally
    AMalloc.Free(FolderPidl);
  end;
end;

//=============================================================================
//  SHBrowseForFolder関数で[フォルダの参照]ダイアログを表示
//  新スタイル
//  ルートフォルダはデスクトップ
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  FolderPidl : PItemIDList;
  BrowseInfo : TBrowseInfo;
  BPathName  : array[0..MAX_PATH-1] of Char;
  AMalloc    : IMalloc;
begin
  //項目識別子解放のためのメモリアロケーションのポインタ取得
  ShGetMalloc(AMalloc);
  FolderPidl := nil;

  FillChar(BrowseInfo, SizeOf(BrowseInfo), #0);
  BrowseInfo.hwndOwner := Handle;
  BrowseInfo.lpfn      := nil;
  BrowseInfo.lpszTitle := PChar('フォルダの指定');
  BrowseInfo.pidlRoot  := nil;
  BrowseInfo.ulFlags   := BIF_RETURNONLYFSDIRS or
                          BIF_NEWDIALOGSTYLE   or
                          BIF_VALIDATE;

  //上の設定に基づきフォルダ参照ダイアログを表示
  try
    FolderPidl := SHBrowseForFolder(BrowseInfo);
    If FolderPidl <> nil then begin
      //項目識別子をパスの文字列BPathNameに変換
      SHGetPathFromIDList(FolderPidl, BPathName);

      MessageBox(Handle, BPathName, '選択フォルダ', MB_ICONINFORMATION);
    end;
  finally
    AMalloc.Free(FolderPidl);
  end;
end;

//=============================================================================
//  SHBrowseForFolder関数で[フォルダの参照]ダイアログを表示
//  ルートフォルダはネットワーク
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  FolderPidl : PItemIDList;
  RootPidl   : PItemIDList;
  BrowseInfo : TBrowseInfo;
  BPathName  : array[0..MAX_PATH-1] of Char;
  AMalloc    : IMalloc;
begin
  //項目識別子解放のためのメモリアロケーションのポインタ取得
  ShGetMalloc(AMalloc);
  FolderPidl := nil;

  //CSIDL_XXXの値を項目識別子に変換
  SHGetSpecialFolderLocation(Handle, CSIDL_NETWORK, RootPidl);

  FillChar(BrowseInfo, SizeOf(BrowseInfo), #0);
  BrowseInfo.hwndOwner := Handle;
  BrowseInfo.lpfn      := nil;
  BrowseInfo.lpszTitle := PChar('フォルダの指定');
  BrowseInfo.pidlRoot  := RootPidl;
  BrowseInfo.ulFlags   := BIF_RETURNONLYFSDIRS or BIF_RETURNFSANCESTORS;

  //上の設定に基づきフォルダ参照ダイアログを表示
  try
    FolderPidl := SHBrowseForFolder(BrowseInfo);
    If FolderPidl <> nil then begin
      //項目識別子をパスの文字列BPathNameに変換
      SHGetPathFromIDList(FolderPidl, BPathName);

      MessageBox(Handle, BPathName, '選択フォルダ', MB_ICONINFORMATION);
    end;
  finally
    AMalloc.Free(FolderPidl);
  end;
end;

//=============================================================================
//  SHBrowseForFolder関数で[フォルダの参照]ダイアログを表示
//  ルートフォルダはプリンタフォルダ
//  新スタイルでプリンタのみを選択可能にする
//=============================================================================
procedure TForm1.Button4Click(Sender: TObject);
var
  FolderPidl : PItemIDList;
  RootPidl   : PItemIDList;
  BrowseInfo : TBrowseInfo;
  BPathName  : array[0..MAX_PATH-1] of Char;
  AMalloc    : IMalloc;
begin
  //項目識別子解放のためのメモリアロケーションのポインタ取得
  ShGetMalloc(AMalloc);
  FolderPidl := nil;

  //CSIDL_XXXの値を項目識別子に変換
  SHGetSpecialFolderLocation(Handle, CSIDL_PRINTERS, RootPidl);

  FillChar(BrowseInfo, SizeOf(BrowseInfo), #0);
  BrowseInfo.hwndOwner := Handle;
  BrowseInfo.lpfn      := nil;
  BrowseInfo.lpszTitle := PChar('フォルダの指定');
  BrowseInfo.pidlRoot  := RootPidl;
  BrowseInfo.ulFlags   := BIF_NEWDIALOGSTYLE or BIF_BROWSEFORPRINTER;

  //上の設定に基づきフォルダ参照ダイアログを表示
  try
    FolderPidl := SHBrowseForFolder(BrowseInfo);
    If FolderPidl <> nil then begin
      //項目識別子をパスの文字列BPathNameに変換
      SHGetPathFromIDList(FolderPidl, BPathName);

      MessageBox(Handle, BPathName, '選択フォルダ', MB_ICONINFORMATION);
    end;
  finally
    AMalloc.Free(FolderPidl);
  end;
end;

end.




05_SHBrowseForFolder 関数で Vista 以降の特殊フォルダを表示


Windows Vista 以降に追加された特殊フォルダは,CSIDL_XXX という定数名は定義されていません.
SHBrowseForFolder 関数は項目識別子でルートフォルダを指定することになっています.これらの 特殊フォルダの項目識別子は,Delphi 2010 以降で使用可能な SHGetKnownFolderIDList という関数を使用すると取得できます.引数には,KnownFolders.pas 内の FOLDERID という特殊フォルダ用の定数名を使用します.

次のコードは,この関数を使用して,Windows 7 で追加された [ライブラリ] というフォルダをルートフォルダにして,フォルダの参照ダイアログを表示します.

下のコードでは,選択したフォルダ名を表示するようにしていますが,SHGetPathFromIDList 関数は,GUID 値で表わされるような仮想フォルダ等は空文字となります.


図11
ライブラリを表示
  • [ライブラリ] というフォルダは,Windows  7 で追加された仮想フォルダ

リスト5
GUID 値を使用して,Vista 以降に追加された特殊フォルダを表示
unit Unit1;

interface

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

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

var
  Form1: TForm1;

implementation

uses FileCtrl, ShlObj, ActiveX, KnownFolders;

{$R *.dfm}

//=============================================================================
//  SHBrowseForFolder関数で[フォルダの参照]ダイアログを表示
//  ルートフォルダはライブラリ
//  
//  FOLDERID_Libraries定数の使用にはusesにKnownFoldersが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  FolderPidl : PItemIDList;
  RootPidl   : PItemIDList;
  BrowseInfo : TBrowseInfo;
  BPathName  : array[0..MAX_PATH-1] of Char;
  AMalloc    : IMalloc;
begin
  //項目識別子解放のためのメモリアロケーションのポインタ取得
  ShGetMalloc(AMalloc);
  FolderPidl := nil;

  //TGUIDのFOLDERID_Librariesに相当する項目識別子を取得
  if SHGetKnownFolderIDList(FOLDERID_Libraries, 0, 0, RootPidl) = S_OK then begin

    FillChar(BrowseInfo, SizeOf(BrowseInfo), #0);
    BrowseInfo.hwndOwner := Handle;
    BrowseInfo.lpfn      := nil;
    BrowseInfo.lpszTitle := PChar('フォルダの指定');
    BrowseInfo.pidlRoot  := RootPidl;
    BrowseInfo.ulFlags   := BIF_NEWDIALOGSTYLE or BIF_VALIDATE;

    //上の設定に基づきフォルダ参照ダイアログを表示
    try
      FolderPidl := SHBrowseForFolder(BrowseInfo);
      If FolderPidl <> nil then begin
        //項目識別子をパスの文字列BPathNameに変換
        SHGetPathFromIDList(FolderPidl, BPathName);

        MessageBox(Handle, BPathName, '選択フォルダ', MB_ICONINFORMATION);
      end;
    finally
      AMalloc.Free(FolderPidl);
    end;
  end;
end;

end.




06_仮想フォルダの表示名とパス名を GUID 文字列で取得


上のコードで使用している,項目識別子からフォルダのパス名を求める SHGetPathFromIDList 関数では仮想フォルダは取得できません.
仮想フォルダのパス名は,以下のように,IShellFolder インターフェイスの GetDisplayName 関数を使用すると取得することができます.仮想フォルダのパス名は GUID の文字列となります.

図は [ライブラリ] をルートフォルダにしてフォルダの参照ダイアログを表示し,そのルートフォルダを選択した結果です.以下のリンクの記事の SHGetKnownFolderIDList 関数を使用したコードも参考にしてください.


図12
仮想フォルダ [ライブラリ] の GUID 値
図13
[ライブラリ] の [ドキュメント] を選択
  • [ライブラリ] の GUID 文字列に
    \Documents.library-ms
    が追加されている

リスト6
仮想フォルダの表示名と GUID の文字列を取得する例.[ライブラリ] の場合
必要なユニットは上のコードと同じ
//-----------------------------------------------------------------------------
//  相対項目識別子からフォルダまたはファイル名を求める
//  仮想フォルダはGUID文字列として求まる
//
//  第1引数  対象の項目識別子を取得する際に使用したシェルフォルダオブジェクト
//  第2引数  対象の項目識別子.ShFolder階層下の相対値
//  第3引数  フルパスを取得する場合は,SHGDN_FORPARSING
//           ファイル名だけ取得する場合は,SHGDN_NORMALまたはSHGDN_INFOLDER
//-----------------------------------------------------------------------------
function GetDispNameFromPItemID(ShFolder: IShellFolder; ItemID:
  PItemIDList; Flag: DWORD=SHGDN_NORMAL): String;
var
  StrRet : TStrRet;
begin
  Result := '';
  if ShFolder = nil then exit;
  if ItemID   = nil then exit;

  FillChar(StrRet, SizeOf(StrRet), #0);
  if NOERROR = ShFolder.GetDisplayNameOf(ItemID, Flag, StrRet) then begin
    Result := StrRet.pOleStr;
  end;
end;

//=============================================================================
//  SHBrowseForFolder関数で[フォルダの参照]ダイアログを表示
//  ルートフォルダはライブラリ
//  仮想フォルダの表示名とGUIDのパス名を取得
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  FolderPidl  : PItemIDList;
  RootPidl    : PItemIDList;
  BrowseInfo  : TBrowseInfo;
  pDesktop    : IShellFolder;
  DisplayName : String;
  FolderPath  : String;
  StrText     : String;
  AMalloc     : IMalloc;
begin
  //項目識別子解放のためのメモリアロケーションのポインタ取得
  ShGetMalloc(AMalloc);
  FolderPidl := nil;

  //FOLDERID_Librariesに相当する項目識別子を取得
  if SHGetKnownFolderIDList(FOLDERID_Libraries, 0, 0, RootPidl) = S_OK then begin

    FillChar(BrowseInfo, SizeOf(BrowseInfo), #0);
    BrowseInfo.hwndOwner := Handle;
    BrowseInfo.lpfn      := nil;
    BrowseInfo.lpszTitle := PChar('フォルダの指定');
    BrowseInfo.pidlRoot  := RootPidl;
    BrowseInfo.ulFlags   := BIF_NEWDIALOGSTYLE or BIF_VALIDATE;

    //上の設定に基づきフォルダ参照ダイアログを表示
    try
      FolderPidl := SHBrowseForFolder(BrowseInfo);
      If FolderPidl <> nil then begin

        //[デスクトップ]のシェルフォルダオブジェクトを取得
        SHGetDesktopFolder(pDesktop);

        //取得した項目識別子から表示名とバス名を取得
        DisplayName := GetDispNameFromPItemID(pDesktop, FolderPidl, SHGDN_INFOLDER);
        FolderPath  := GetDispNameFromPItemID(pDesktop, FolderPidl, SHGDN_FORPARSING);
        StrText     := DisplayName + sLineBreak + FolderPath;

        MessageBox(Handle,  PChar(StrText), '選択フォルダ', MB_ICONINFORMATION);
      end;
    finally
      AMalloc.Free(FolderPidl);
    end;
  end;
end;




07_仮想フォルダをルートにしてフォルダの参照ダイアログを表示


仮想フォルダの GUID 文字列を使用すると,その仮想フォルダをルートフォルダにしてフォルダの損傷ダイアログを表示できます.
次のコードは SelectDirectory 関数を使用する例です.

リスト7
仮想フォルダの GUID 値を使用して,仮想フォルダを表示する
uses に FileCtrl が必要
//=============================================================================
//  仮想フォルダをルートフォルダに指定して[フォルダの参照]ダイアログを表示
//  仮想フォルダをGUIDの文字列で指定する例
//
//  [ライブラリ]をルートフォルダにする
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  RootFolder   : String;
  SelectFolder : String;
begin
  RootFolder := '::{031E4825-7B94-4DC3-B131-E946B44C8DD5}';

  if SelectDirectory('フォルダの指定', RootFolder, SelectFolder) then begin
    MessageBox(Handle, PChar(SelectFolder), '選択フォルダ', MB_ICONINFORMATION);
  end;
end;

//=============================================================================
//  仮想フォルダをルートフォルダに指定して[フォルダの参照]ダイアログを表示
//  仮想フォルダをGUIDの文字列で指定する例
//
//  [ライブラリ]フォルダ下の[ドキュメント]をルートフォルダにする
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  RootFolder   : String;
  SelectFolder : String;
begin
  RootFolder := '::{031E4825-7B94-4DC3-B131-E946B44C8DD5}\Documents.library-ms';

  if SelectDirectory('フォルダの指定', RootFolder, SelectFolder) then begin
    MessageBox(Handle, PChar(SelectFolder), '選択フォルダ', MB_ICONINFORMATION);
  end;
end;




08_仮想フォルダの実パス名を取得


FOLDERID (FOLDERID_XXXX) の仮想フォルダの実際のパス名は,SHGetKnownFolderPath 関数で取得することができます.下のコードはその例です.
FOLDERID は TGUID 型の定数ですが,この GUID は該当する仮想フォルダの値ではありません.注意してください.


図14
下のコードの実行結果
  • [ライブラリ] の実際のパス名

リスト8
FOLDERID_XXXX の定数値から仮想フォルダの実パスを取得
uses にShlObj, KnownFolders が必要
//=============================================================================
//  仮想フォルダの実フルパス名を取得する方法
//  SHGetKnownFolderPath関数を使用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  pFolderPath : PChar;
  StrText     : String;
begin
  //FOLDERID_Librariesに相当するフルパス名を取得
  if SHGetKnownFolderPath(FOLDERID_Libraries, 0, 0, pFolderPath) = S_OK then begin
    StrText := pFolderPath;
    MessageBox(Handle, PChar(StrText), '実パス名', MB_ICONINFORMATION);
  end;
end;




09_フォルダの参照ダイアログの表示位置とサイズの設定


フォルダの参照ダイアログの起動時に,その表示位置とサイズを設定するには,下記のリンクの記事を参考にしてください.
サイズを設定するには,リサイズ可能な設定で起動します.SHBrowseForFolder でコールバック関数を定義して使用すると,コールバック関数内で表示位置や表示サイズを設定することができます.





10_特定のプラットフォームに固有のものです


サンプルコードをコンパイルすると,次のような警告が現れることがあります.
これは,FileCtrl ユニットが,文字通り,特定のプラットフォーム専用であることを意味しています.この場合は VCL というプラットフォーム専用ということになります. VCL は Windows 専用ですから,Windows 用のアプリケーション専用ということになります.

[DCC 警告] Unit1.pas(62): W1005: ユニット 'FileCtrl' は特定のプラットフォームに固有のものです

この警告が現れないようにすることができます.
例えば,{$WARN UNIT_PLATFORM OFF} というコンパイラ指令をユニットの先頭に書きます.あるいは次のように,該当ユニットに対して実行するようにします.


uses
  {$WARN UNIT_PLATFORM OFF}
  FileCtrl,
  {$WARN UNIT_PLATFORM ON}
  ShlObj,
  ActiveX;