SHBrowseForFolderA 関数 (shlobj_core.h)

ユーザーがシェル フォルダーを選択できるようにするダイアログ ボックスを表示します。

構文

PIDLIST_ABSOLUTE SHBrowseForFolderA(
  [in] LPBROWSEINFOA lpbi
);

パラメーター

[in] lpbi

型: LPBROWSEINFO

ダイアログ ボックスの表示に使用される情報を含む BROWSEINFO 構造体へのポインター。

戻り値

種類: PIDLIST_ABSOLUTE

名前空間のルートを基準にして、選択したフォルダーの場所を指定する PIDL を返します。 ユーザーがダイアログ ボックスで [キャンセル ] ボタンを選択した場合、戻り値は NULL になります

PIDL が返されるのは、フォルダーではなくフォルダー ショートカットの場合です。 このケースの詳細については、「解説」セクションを参照してください。

注釈

Windows Vista 以降では、SHBrowseForFolder 関数ではなく、FOS_PICKFOLDERS オプションで IFileDialog を使用することをお勧めします。 これは、選択フォルダー モードで [ファイルを開く] ダイアログを使用し、推奨される実装です。

SHBrowseForFolder を呼び出す前に、コンポーネント オブジェクト モデル (COM) を初期化する必要があります。 CoInitializeEx を使用して COM を初期化する場合は、dwCoInit パラメーターに COINIT_APARTMENTTHREADED フラグを設定する必要があります。 また、常にアパートメント スレッド処理を使用する CoInitialize または OleInitialize を使用することもできます。 ドラッグ アンド ドロップ機能が必要な場合は、必要な OLE と COM を初期化するため、 OleInitialize をお勧めします。

メモCOM が coInitializeEx を使用して COINIT_MULTITHREADED フラグを使用して初期化された場合、呼び出し元のアプリケーションが BROWSEINFO 構造体で BIF_USENEWUI または BIF_NEWDIALOGSTYLE フラグを使用している場合、SHBrowseForFolder は失敗します。
 
呼び出し元のアプリケーションは 、CoTaskMemFree を呼び出して、 SHBrowseForFolder によって返される IDList が不要になったときに解放する必要があります。

ダイアログ ボックスには 2 つのスタイルがあります。 古いスタイルは既定で表示され、サイズ変更できません。 新しいスタイルには、ダイアログ ボックス内のドラッグ アンド ドロップ機能、並べ替え、削除、ショートカット メニュー、新しいフォルダーの作成機能、その他のショートカット メニュー コマンドなど、多くの追加機能が用意されています。 最初は、古いダイアログ ボックスよりも大きくなりますが、ユーザーはサイズを変更できます。 新しいスタイルを使用してダイアログ ボックスを指定するには、BROWSEINFO 構造体の ulFlags メンバーでBIF_USENEWUI フラグを設定します。

BROWSEINFO 構造体の lpfn メンバーで指定されたコールバック関数を実装すると、ダイアログ ボックスへのハンドルが表示されます。 このウィンドウ ハンドルの 1 つの用途は、ダイアログ ボックスのレイアウトまたは内容を変更することです。 サイズ変更できないため、古いスタイルのダイアログ ボックスの変更は比較的簡単です。 新しいスタイル ダイアログ ボックスの変更ははるかに困難であり、推奨されません。 古いスタイルとはサイズやレイアウトが異なるだけでなく、ユーザーがサイズを変更するたびに、そのサイズとコントロールの位置が変わります。

BROWSEINFO 構造体の ulFlags メンバーでBIF_RETURNONLYFSDIRS フラグが設定されている場合、"\server" 項目と "\server\share" およびディレクトリ項目に対して [OK] ボタンは有効なままになります。 ただし、ユーザーが "\server" 項目を選択した場合、 SHBrowseForFolder によって返される PIDL を SHGetPathFromIDList に渡すことは失敗します。

カスタム フィルター処理

Windows XP 以降、 SHBrowseForFolder では、ダイアログ ボックスの内容に対するカスタム フィルター処理がサポートされています。 カスタム フィルターを作成するには、次の手順に従います。
  1. lpbi パラメーターが指す BROWSEINFO 構造体の ulFlags メンバーに、BIF_NEWDIALOGSTYLE フラグを設定します。
  2. 同じ BROWSEINFO 構造体の lpfn メンバーにコールバック関数を指定します。
  3. コールバック関数をコーディングして、BFFM_INITIALIZEDメッセージとBFFM_IUNKNOWN メッセージを受信します。 BFFM_IUNKNOWN メッセージを受信すると、コールバック関数の lParam パラメーターには、ダイアログ ボックスの IUnknown の実装へのポインターが含まれます。 その IUnknownQueryInterface を呼び出して、IFolderFilterSite のインスタンスへのポインターを取得します。
  4. IFolderFilter を実装するオブジェクトを作成します。
  5. IFolderFilterSite::SetFilter を呼び出し、IFolderFilter へのポインターを渡します。 その後、IFolderFilter メソッドを使用して、ツリーに項目を含めて除外できます。
  6. フィルターが作成されると、 IFolderFilterSite インターフェイスは不要になります。 これ以上使用できない場合は、 IFolderFilterSite::Release を呼び出します。

ショートカットの処理

メモ このセクションは、Windows 2000 以前のシステムにのみ適用されます。 既定では、WINDOWS XP 以降のシステムは、 BROWSEINFO 構造体でBIF_NOTRANSLATETARGETS フラグが設定されていない限り、ショートカット自体ではなくショートカットのターゲットの PIDL を返します。
 
SHBrowseForFolder がショートカットに PIDL を返す場合、その PIDL を SHGetPathFromIDList に送信すると、ターゲットのパスではなく、ショートカット自体のパスが返されます。 ショートカットのターゲットへのパスは、この例に示すように IShellLink インターフェイスを使用して取得できます。
#include 

// Macros for interface casts
#ifdef __cplusplus
#define IID_PPV_ARG(IType, ppType) IID_##IType, reinterpret_cast(static_cast(ppType))
#else
#define IID_PPV_ARG(IType, ppType) &IID_##IType, (void**)(ppType)
#endif

// Retrieves the UIObject interface for the specified full PIDL
STDAPI SHGetUIObjectFromFullPIDL(LPCITEMIDLIST pidl, HWND hwnd, REFIID riid, void **ppv)
{
    LPCITEMIDLIST pidlChild;
    IShellFolder* psf;

    *ppv = NULL;

    HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
    if (SUCCEEDED(hr))
    {
        hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);
        psf->Release();
    }
    return hr;
}
 
#define ILSkip(pidl, cb)       ((LPITEMIDLIST)(((BYTE*)(pidl))+cb))
#define ILNext(pidl)           ILSkip(pidl, (pidl)->mkid.cb)
 
HRESULT SHILClone(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
{
    DWORD cbTotal = 0;

    if (pidl)
    {
        LPCITEMIDLIST pidl_temp = pidl;
        cbTotal += sizeof (pidl_temp->mkid.cb);

        while (pidl_temp->mkid.cb) 
        {
            cbTotal += pidl_temp->mkid.cb;
            pidl_temp += ILNext (pidl_temp);
        }
    }
    
    *ppidl = (LPITEMIDLIST)CoTaskMemAlloc(cbTotal);
    
    if (*ppidl)
        CopyMemory(*ppidl, pidl, cbTotal);
 
    return  *ppidl ? S_OK: E_OUTOFMEMORY;
}
 
// Get the target PIDL for a folder PIDL. This also deals with cases of a folder  
// shortcut or an alias to a real folder.
STDAPI SHGetTargetFolderIDList(LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidl)
{
    IShellLink *psl;
	
    *ppidl = NULL;
    
    HRESULT hr = SHGetUIObjectFromFullPIDL(pidlFolder, NULL, IID_PPV_ARG(IShellLink, &psl));
    
    if (SUCCEEDED(hr))
    {
        hr = psl->GetIDList(ppidl);
        psl->Release();
    }
    
    // It's not a folder shortcut so get the PIDL normally.
    if (FAILED(hr))
        hr = SHILClone(pidlFolder, ppidl);
    
    return hr;
}

// Get the target folder for a folder PIDL. This deals with cases where a folder
// is an alias to a real folder, folder shortcuts, the My Documents folder, and 
// other items of that nature.
STDAPI SHGetTargetFolderPath(LPCITEMIDLIST pidlFolder, LPWSTR pszPath, UINT cchPath)
{
    LPITEMIDLIST pidlTarget;
	
    *pszPath = 0;

    HRESULT hr = SHGetTargetFolderIDList(pidlFolder, &pidlTarget);
    
    if (SUCCEEDED(hr))
    {
        SHGetPathFromIDListW(pidlTarget, pszPath);   // Make sure it is a path
        CoTaskMemFree(pidlTarget);
    }
    
    return *pszPath ? S_OK : E_FAIL;
}

// Retrieves the UIObject interface for the specified full PIDLstatic 
HRESULT SHGetUIObjectFromFullPIDL(LPCITEMIDLIST pidl, HWND hwnd, REFIID riid, void **ppv)
{    
    LPCITEMIDLIST pidlChild;    
    IShellFolder* psf;    
    *ppv = NULL;    
    
    HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&psf, &pidlChild);    
    if (SUCCEEDED(hr))    
    {        
        hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);        
        psf->Release();    
    }    
    return hr;
}

static HRESULT SHILClone(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
{    
    DWORD cbTotal = 0;    
    if (pidl)
    {        
        LPCITEMIDLIST pidl_temp = pidl;        
        cbTotal += pidl_temp->mkid.cb;        
        
        while (pidl_temp->mkid.cb)         
        {            
            cbTotal += pidl_temp->mkid.cb;            
            pidl_temp = ILNext(pidl_temp);        
        }    
    }    
    
    *ppidl = (LPITEMIDLIST)CoTaskMemAlloc(cbTotal);    
    if (*ppidl)        
        CopyMemory(*ppidl, pidl, cbTotal);    
        
    return  *ppidl ? S_OK: E_OUTOFMEMORY;
}
    
// Get the target PIDL for a folder PIDL. This also deals with cases of a folder  
// shortcut or an alias to a real folder.
static HRESULT SHGetTargetFolderIDList(LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidl)
{    
    IShellLink *psl;    
    *ppidl = NULL;    
    
    HRESULT hr = SHGetUIObjectFromFullPIDL(pidlFolder, NULL, IID_IShellLink, (LPVOID*)&psl);    
    if (SUCCEEDED(hr))    
    {        
        hr = psl->GetIDList(ppidl);        
        psl->Release();    
    }    
    
    // It's not a folder shortcut so get the PIDL normally.    
    if (FAILED(hr))        
        hr = SHILClone(pidlFolder, ppidl);    
    return hr;
}

// Get the target folder for a folder PIDL. This deals with cases where a folder
// is an alias to a real folder, folder shortcuts, the My Documents folder, 
// and so on.
STDAPI SHGetTargetFolderPath(LPCITEMIDLIST pidlFolder, LPWSTR pszPath, UINT cchPath)
{    
    LPITEMIDLIST pidlTarget;    
    *pszPath = 0;    
    
    HRESULT hr = SHGetTargetFolderIDList(pidlFolder, &pidlTarget);    
    if (SUCCEEDED(hr))    
    {        
        SHGetPathFromIDListW(pidlTarget, pszPath);   
        
        // Make sure it is a path        
        CoTaskMemFree(pidlTarget);    
    }    
    
    return *pszPath ? S_OK : E_FAIL;
}

注意

shlobj_core.h ヘッダーは、UNICODE プリプロセッサ定数の定義に基づいて、この関数の ANSI または Unicode バージョンを自動的に選択するエイリアスとして SHBrowseForFolder を定義します。 encoding-neutral エイリアスの使用を encoding-neutral ではないコードと混在すると、コンパイル エラーまたはランタイム エラーが発生する不一致が発生する可能性があります。 詳細については、「 関数プロトタイプの規則」を参照してください。

要件

要件
サポートされている最小のクライアント Windows XP (デスクトップ アプリのみ)
サポートされている最小のサーバー Windows 2000 Server [デスクトップ アプリのみ]
対象プラットフォーム Windows
ヘッダー shlobj_core.h (Shlobj.h、Shlobj_core.h を含む)
Library Shell32.lib
[DLL] Shell32.dll (バージョン 4.0 以降)

こちらもご覧ください

ダイアログ ボックスを開いて保存