SHBrowseForFolderA
関数シグネチャ
// SHELL32.dll (ANSI / -A)
#include <windows.h>
ITEMIDLIST* SHBrowseForFolderA(
BROWSEINFOA* lpbi
);パラメーター
| 名前 | 型 | 方向 | 説明 |
|---|---|---|---|
| lpbi | BROWSEINFOA* | in | ダイアログ ボックスの表示に使用する情報を格納した BROWSEINFO 構造体へのポインター。 |
戻り値の型: ITEMIDLIST*
公式ドキュメント
ユーザーが Shell フォルダーを選択できるダイアログ ボックスを表示します。(ANSI)
戻り値
型: PIDLIST_ABSOLUTE
名前空間のルートを基準とした、選択されたフォルダーの位置を指定する PIDL を返します。ユーザーがダイアログ ボックスで キャンセル ボタンを選択した場合、戻り値は NULL です。
返される PIDL が、フォルダーではなくフォルダーへのショートカットを指す場合があります。このケースの詳細については、「解説」セクションを参照してください。
解説(Remarks)
Windows Vista 以降では、SHBrowseForFolder 関数よりも、FOS_PICKFOLDERS オプションを指定した IFileDialog の使用が推奨されます。これはフォルダー選択モードの [ファイルを開く] ダイアログを使用するもので、推奨される実装です。
SHBrowseForFolder を呼び出す前に、Component Object Model (COM) を初期化する必要があります。CoInitializeEx を使用して COM を初期化する場合は、その dwCoInit パラメーターに COINIT_APARTMENTTHREADED フラグを設定する必要があります。CoInitialize または OleInitialize を使用することもでき、これらは常にアパートメント スレッディングを使用します。ドラッグ アンド ドロップ機能が必要な場合は、必要な OLE と COM の両方を初期化する OleInitialize が推奨されます。
ダイアログ ボックスには 2 つのスタイルがあります。古いスタイルは既定で表示され、サイズ変更はできません。新しいスタイルには、ダイアログ ボックス内でのドラッグ アンド ドロップ機能、並べ替え、削除、ショートカット メニュー、新しいフォルダーの作成機能、その他のショートカット メニュー コマンドなど、いくつかの追加機能が用意されています。初期状態では古いダイアログ ボックスより大きいですが、ユーザーがサイズを変更できます。新しいスタイルのダイアログ ボックスを指定するには、BROWSEINFO 構造体の ulFlags メンバーに BIF_USENEWUI フラグを設定します。
BROWSEINFO 構造体の lpfn メンバーで指定するコールバック関数を実装すると、ダイアログ ボックスへのハンドルを受け取ります。このウィンドウ ハンドルの用途の 1 つは、ダイアログ ボックスのレイアウトや内容を変更することです。古いスタイルのダイアログ ボックスはサイズ変更できないため、変更は比較的簡単です。新しいスタイルのダイアログ ボックスの変更ははるかに難しく、推奨されません。古いスタイルとはサイズやレイアウトが異なるだけでなく、ユーザーがサイズを変更するたびに、その寸法やコントロールの位置が変化するためです。
BROWSEINFO 構造体の ulFlags メンバーに BIF_RETURNONLYFSDIRS フラグが設定されている場合、OK ボタンは "\server\share" やディレクトリの項目だけでなく、"\server" の項目に対しても有効なままになります。ただし、ユーザーが "\server" の項目を選択した場合、SHBrowseForFolder が返した PIDL を SHGetPathFromIDList に渡しても失敗します。
カスタム フィルター
Windows XP 以降、SHBrowseForFolder はダイアログ ボックスの内容に対するカスタム フィルターをサポートしています。カスタム フィルターを作成するには、次の手順に従います。- lpbi パラメーターが指す BROWSEINFO 構造体の ulFlags メンバーに BIF_NEWDIALOGSTYLE フラグを設定します。
- 同じ BROWSEINFO 構造体の lpfn メンバーにコールバック関数を指定します。
- BFFM_INITIALIZED および BFFM_IUNKNOWN メッセージを受け取るようにコールバック関数を記述します。BFFM_IUNKNOWN メッセージを受信すると、コールバック関数の lParam パラメーターには、ダイアログ ボックスの IUnknown の実装へのポインターが格納されます。その IUnknown に対して QueryInterface を呼び出して、IFolderFilterSite のインスタンスへのポインターを取得します。
- IFolderFilter を実装するオブジェクトを作成します。
- 作成した IFolderFilter へのポインターを渡して IFolderFilterSite::SetFilter を呼び出します。その後、IFolderFilter のメソッドを使用して、ツリーから項目を含めたり除外したりできます。
- フィルターを作成したら、IFolderFilterSite インターフェイスは不要になります。これ以上使用しない場合は IFolderFilterSite::Release を呼び出します。
ショートカットの処理
#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 ヘッダーは、SHBrowseForFolder を、UNICODE プリプロセッサ定数の定義に基づいてこの関数の ANSI 版または Unicode 版を自動的に選択するエイリアスとして定義します。エンコーディング非依存のエイリアスの使用を、エンコーディング非依存でないコードと混在させると、不一致が生じ、コンパイル エラーや実行時エラーの原因となる場合があります。詳細については、「Conventions for Function Prototypes」を参照してください。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
各言語での呼び出し定義
// SHELL32.dll (ANSI / -A)
#include <windows.h>
ITEMIDLIST* SHBrowseForFolderA(
BROWSEINFOA* lpbi
);[DllImport("SHELL32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
static extern IntPtr SHBrowseForFolderA(
IntPtr lpbi // BROWSEINFOA*
);<DllImport("SHELL32.dll", CharSet:=CharSet.Ansi, ExactSpelling:=True)>
Public Shared Function SHBrowseForFolderA(
lpbi As IntPtr ' BROWSEINFOA*
) As IntPtr
End Function' lpbi : BROWSEINFOA*
Declare PtrSafe Function SHBrowseForFolderA Lib "shell32" ( _
ByVal lpbi As LongPtr) As LongPtr
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。import ctypes
from ctypes import wintypes
SHBrowseForFolderA = ctypes.windll.shell32.SHBrowseForFolderA
SHBrowseForFolderA.restype = ctypes.c_void_p
SHBrowseForFolderA.argtypes = [
ctypes.c_void_p, # lpbi : BROWSEINFOA*
]require 'fiddle'
require 'fiddle/import'
lib = Fiddle.dlopen('SHELL32.dll')
SHBrowseForFolderA = Fiddle::Function.new(
lib['SHBrowseForFolderA'],
[
Fiddle::TYPE_VOIDP, # lpbi : BROWSEINFOA*
],
Fiddle::TYPE_VOIDP)#[link(name = "shell32")]
extern "system" {
fn SHBrowseForFolderA(
lpbi: *mut BROWSEINFOA // BROWSEINFOA*
) -> *mut ITEMIDLIST;
}
// crates: windows-sys provides ready-made bindings for this API.$sig = @"
[DllImport("SHELL32.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr SHBrowseForFolderA(IntPtr lpbi);
"@
$api = Add-Type -MemberDefinition $sig -Name 'SHELL32_SHBrowseForFolderA' -Namespace Win32 -PassThru
# $api::SHBrowseForFolderA(lpbi)#uselib "SHELL32.dll"
#func global SHBrowseForFolderA "SHBrowseForFolderA" sptr
; SHBrowseForFolderA varptr(lpbi) ; 戻り値は stat
; lpbi : BROWSEINFOA* -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。#uselib "SHELL32.dll" #cfunc global SHBrowseForFolderA "SHBrowseForFolderA" var ; res = SHBrowseForFolderA(lpbi) ; lpbi : BROWSEINFOA* -> "var" ; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。#uselib "SHELL32.dll" #cfunc global SHBrowseForFolderA "SHBrowseForFolderA" sptr ; res = SHBrowseForFolderA(varptr(lpbi)) ; lpbi : BROWSEINFOA* -> "sptr" ; ※出力/バッファ引数はポインタ方式(token=sptr / 呼び出しは varptr(変数))。
; ITEMIDLIST* SHBrowseForFolderA(BROWSEINFOA* lpbi) #uselib "SHELL32.dll" #cfunc global SHBrowseForFolderA "SHBrowseForFolderA" var ; res = SHBrowseForFolderA(lpbi) ; lpbi : BROWSEINFOA* -> "var" ; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。; ITEMIDLIST* SHBrowseForFolderA(BROWSEINFOA* lpbi) #uselib "SHELL32.dll" #cfunc global SHBrowseForFolderA "SHBrowseForFolderA" intptr ; res = SHBrowseForFolderA(varptr(lpbi)) ; lpbi : BROWSEINFOA* -> "intptr" ; ※出力/バッファ引数はポインタ方式(token=intptr / 呼び出しは varptr(変数))。
import (
"golang.org/x/sys/windows"
"unsafe"
)
var (
shell32 = windows.NewLazySystemDLL("SHELL32.dll")
procSHBrowseForFolderA = shell32.NewProc("SHBrowseForFolderA")
)
// lpbi (BROWSEINFOA*)
r1, _, err := procSHBrowseForFolderA.Call(
uintptr(lpbi),
)
_ = err // syscall.Errno (valid when the call sets last-error)
_ = r1 // ITEMIDLIST*function SHBrowseForFolderA(
lpbi: Pointer // BROWSEINFOA*
): Pointer; stdcall;
external 'SHELL32.dll' name 'SHBrowseForFolderA';result := DllCall("SHELL32\SHBrowseForFolderA"
, "Ptr", lpbi ; BROWSEINFOA*
, "Ptr") ; return: ITEMIDLIST*●SHBrowseForFolderA(lpbi) = DLL("SHELL32.dll", "void* SHBrowseForFolderA(void*)")
# 呼び出し: SHBrowseForFolderA(lpbi)
# lpbi : BROWSEINFOA* -> "void*"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。const std = @import("std");
extern "shell32" fn SHBrowseForFolderA(
lpbi: [*c]BROWSEINFOA // BROWSEINFOA*
) callconv(std.os.windows.WINAPI) [*c]ITEMIDLIST;proc SHBrowseForFolderA(
lpbi: ptr BROWSEINFOA # BROWSEINFOA*
): ptr ITEMIDLIST {.importc: "SHBrowseForFolderA", stdcall, dynlib: "SHELL32.dll".}pragma(lib, "shell32");
extern(Windows)
ITEMIDLIST* SHBrowseForFolderA(
BROWSEINFOA* lpbi // BROWSEINFOA*
);ccall((:SHBrowseForFolderA, "SHELL32.dll"), stdcall, Ptr{ITEMIDLIST},
(Ptr{BROWSEINFOA},),
lpbi)
# lpbi : BROWSEINFOA* -> Ptr{BROWSEINFOA}
# stdcall は 32bit のみ意味を持つ(x64 では無視)。local ffi = require("ffi")
ffi.cdef[[
void* SHBrowseForFolderA(
void* lpbi);
]]
local shell32 = ffi.load("shell32")
-- shell32.SHBrowseForFolderA(lpbi)
-- lpbi : BROWSEINFOA*
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。const koffi = require('koffi');
const lib = koffi.load('SHELL32.dll');
const SHBrowseForFolderA = lib.func('__stdcall', 'SHBrowseForFolderA', 'void *', ['void *']);
// SHBrowseForFolderA(lpbi)
// lpbi : BROWSEINFOA* -> 'void *'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。const lib = Deno.dlopen("SHELL32.dll", {
SHBrowseForFolderA: { parameters: ["pointer"], result: "pointer" },
});
// lib.symbols.SHBrowseForFolderA(lpbi)
// lpbi : BROWSEINFOA* -> "pointer"
// 文字列は "buffer"。ANSI(-A) は new TextEncoder() で UTF-8/ANSI バイト列(末尾に \x00)を渡す。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。<?php
$ffi = FFI::cdef(<<<C
void* SHBrowseForFolderA(
void* lpbi);
C, "SHELL32.dll");
// $ffi->SHBrowseForFolderA(lpbi);
// lpbi : BROWSEINFOA*
// 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
// WINAPI(stdcall): x64 では呼出規約が統一されるため問題なし。x86 では __stdcall 対応のラッパが必要な場合あり。import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
public interface Shell32 extends StdCallLibrary {
Shell32 INSTANCE = Native.load("shell32", Shell32.class, W32APIOptions.ASCII_OPTIONS);
Pointer SHBrowseForFolderA(
Pointer lpbi // BROWSEINFOA*
);
}@[Link("shell32")]
lib LibSHELL32
fun SHBrowseForFolderA = SHBrowseForFolderA(
lpbi : BROWSEINFOA* # BROWSEINFOA*
) : ITEMIDLIST*
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef SHBrowseForFolderANative = Pointer<Void> Function(Pointer<Void>);
typedef SHBrowseForFolderADart = Pointer<Void> Function(Pointer<Void>);
final SHBrowseForFolderA = DynamicLibrary.open('SHELL32.dll')
.lookupFunction<SHBrowseForFolderANative, SHBrowseForFolderADart>('SHBrowseForFolderA');
// lpbi : BROWSEINFOA* -> Pointer<Void>
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。{$mode objfpc}{$H+}
function SHBrowseForFolderA(
lpbi: Pointer // BROWSEINFOA*
): Pointer; stdcall;
external 'SHELL32.dll' name 'SHBrowseForFolderA';import Foreign
import Foreign.C.Types
import Foreign.C.String
foreign import stdcall safe "SHBrowseForFolderA"
c_SHBrowseForFolderA :: Ptr () -> IO (Ptr ())
-- lpbi : BROWSEINFOA* -> Ptr ()
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。open Ctypes
open Foreign
let shbrowseforfoldera =
foreign "SHBrowseForFolderA"
((ptr void) @-> returning (ptr void))
(* lpbi : BROWSEINFOA* -> (ptr void) *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)(cffi:define-foreign-library shell32 (t "SHELL32.dll"))
(cffi:use-foreign-library shell32)
(cffi:defcfun ("SHBrowseForFolderA" shbrowse-for-folder-a :convention :stdcall) :pointer
(lpbi :pointer)) ; BROWSEINFOA*
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。use Win32::API;
my $SHBrowseForFolderA = Win32::API::More->new('SHELL32',
'LPVOID SHBrowseForFolderA(LPVOID lpbi)');
# my $ret = $SHBrowseForFolderA->Call($lpbi);
# lpbi : BROWSEINFOA* -> LPVOID
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。関連項目
- f SHBrowseForFolderW (Unicode版) — フォルダー選択ダイアログ(Unicode)を表示する。