SHBrowseForFolderW
関数シグネチャ
// SHELL32.dll (Unicode / -W)
#include <windows.h>
ITEMIDLIST* SHBrowseForFolderW(
BROWSEINFOW* lpbi
);パラメーター
| 名前 | 型 | 方向 | 説明 |
|---|---|---|---|
| lpbi | BROWSEINFOW* | in | ダイアログ ボックスの表示に使用される情報を含む BROWSEINFO 構造体へのポインターです。 |
戻り値の型: ITEMIDLIST*
公式ドキュメント
ユーザーが Shell フォルダーを選択できるダイアログ ボックスを表示します。(Unicode)
戻り値
型: 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 を実装するオブジェクトを作成します。
- IFolderFilterSite::SetFilter を呼び出し、自分の IFolderFilter へのポインターを渡します。これにより、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 ヘッダーは、UNICODE プリプロセッサ定数の定義に基づいて、この関数の ANSI 版または Unicode 版を自動的に選択するエイリアスとして SHBrowseForFolder を定義します。エンコーディング中立のエイリアスの使用を、エンコーディング中立でないコードと混在させると、不一致が生じてコンパイル エラーや実行時エラーが発生する可能性があります。詳細については、「Conventions for Function Prototypes」を参照してください。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
各言語での呼び出し定義
// SHELL32.dll (Unicode / -W)
#include <windows.h>
ITEMIDLIST* SHBrowseForFolderW(
BROWSEINFOW* lpbi
);[DllImport("SHELL32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
static extern IntPtr SHBrowseForFolderW(
IntPtr lpbi // BROWSEINFOW*
);<DllImport("SHELL32.dll", CharSet:=CharSet.Unicode, ExactSpelling:=True)>
Public Shared Function SHBrowseForFolderW(
lpbi As IntPtr ' BROWSEINFOW*
) As IntPtr
End Function' lpbi : BROWSEINFOW*
Declare PtrSafe Function SHBrowseForFolderW Lib "shell32" ( _
ByVal lpbi As LongPtr) As LongPtr
' Unicode(W): 文字列は ByVal As LongPtr とし StrPtr(unicodeStr) を渡す
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。import ctypes
from ctypes import wintypes
SHBrowseForFolderW = ctypes.windll.shell32.SHBrowseForFolderW
SHBrowseForFolderW.restype = ctypes.c_void_p
SHBrowseForFolderW.argtypes = [
ctypes.c_void_p, # lpbi : BROWSEINFOW*
]require 'fiddle'
require 'fiddle/import'
lib = Fiddle.dlopen('SHELL32.dll')
SHBrowseForFolderW = Fiddle::Function.new(
lib['SHBrowseForFolderW'],
[
Fiddle::TYPE_VOIDP, # lpbi : BROWSEINFOW*
],
Fiddle::TYPE_VOIDP)
# Wide strings: pass str.encode("UTF-16LE") + "\x00\x00"#[link(name = "shell32")]
extern "system" {
fn SHBrowseForFolderW(
lpbi: *mut BROWSEINFOW // BROWSEINFOW*
) -> *mut ITEMIDLIST;
}
// crates: windows-sys provides ready-made bindings for this API.$sig = @"
[DllImport("SHELL32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr SHBrowseForFolderW(IntPtr lpbi);
"@
$api = Add-Type -MemberDefinition $sig -Name 'SHELL32_SHBrowseForFolderW' -Namespace Win32 -PassThru
# $api::SHBrowseForFolderW(lpbi)#uselib "SHELL32.dll"
#func global SHBrowseForFolderW "SHBrowseForFolderW" wptr
; SHBrowseForFolderW varptr(lpbi) ; 戻り値は stat
; lpbi : BROWSEINFOW* -> "wptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。#uselib "SHELL32.dll" #cfunc global SHBrowseForFolderW "SHBrowseForFolderW" var ; res = SHBrowseForFolderW(lpbi) ; lpbi : BROWSEINFOW* -> "var" ; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。#uselib "SHELL32.dll" #cfunc global SHBrowseForFolderW "SHBrowseForFolderW" sptr ; res = SHBrowseForFolderW(varptr(lpbi)) ; lpbi : BROWSEINFOW* -> "sptr" ; ※出力/バッファ引数はポインタ方式(token=sptr / 呼び出しは varptr(変数))。
; ITEMIDLIST* SHBrowseForFolderW(BROWSEINFOW* lpbi) #uselib "SHELL32.dll" #cfunc global SHBrowseForFolderW "SHBrowseForFolderW" var ; res = SHBrowseForFolderW(lpbi) ; lpbi : BROWSEINFOW* -> "var" ; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。; ITEMIDLIST* SHBrowseForFolderW(BROWSEINFOW* lpbi) #uselib "SHELL32.dll" #cfunc global SHBrowseForFolderW "SHBrowseForFolderW" intptr ; res = SHBrowseForFolderW(varptr(lpbi)) ; lpbi : BROWSEINFOW* -> "intptr" ; ※出力/バッファ引数はポインタ方式(token=intptr / 呼び出しは varptr(変数))。
import (
"golang.org/x/sys/windows"
"unsafe"
)
var (
shell32 = windows.NewLazySystemDLL("SHELL32.dll")
procSHBrowseForFolderW = shell32.NewProc("SHBrowseForFolderW")
)
// lpbi (BROWSEINFOW*)
r1, _, err := procSHBrowseForFolderW.Call(
uintptr(lpbi),
)
_ = err // syscall.Errno (valid when the call sets last-error)
_ = r1 // ITEMIDLIST*function SHBrowseForFolderW(
lpbi: Pointer // BROWSEINFOW*
): Pointer; stdcall;
external 'SHELL32.dll' name 'SHBrowseForFolderW';result := DllCall("SHELL32\SHBrowseForFolderW"
, "Ptr", lpbi ; BROWSEINFOW*
, "Ptr") ; return: ITEMIDLIST*●SHBrowseForFolderW(lpbi) = DLL("SHELL32.dll", "void* SHBrowseForFolderW(void*)")
# 呼び出し: SHBrowseForFolderW(lpbi)
# lpbi : BROWSEINFOW* -> "void*"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
# ※-W(Unicode)関数。なでしこ1はANSIのため -A 版の利用を推奨。const std = @import("std");
extern "shell32" fn SHBrowseForFolderW(
lpbi: [*c]BROWSEINFOW // BROWSEINFOW*
) callconv(std.os.windows.WINAPI) [*c]ITEMIDLIST;
// Unicode(-W): UTF-16LE のヌル終端バッファ([*c]const u16)を渡す。proc SHBrowseForFolderW(
lpbi: ptr BROWSEINFOW # BROWSEINFOW*
): ptr ITEMIDLIST {.importc: "SHBrowseForFolderW", stdcall, dynlib: "SHELL32.dll".}
# Unicode(-W): WideCString は newWideCString("...") で生成。pragma(lib, "shell32");
extern(Windows)
ITEMIDLIST* SHBrowseForFolderW(
BROWSEINFOW* lpbi // BROWSEINFOW*
);ccall((:SHBrowseForFolderW, "SHELL32.dll"), stdcall, Ptr{ITEMIDLIST},
(Ptr{BROWSEINFOW},),
lpbi)
# lpbi : BROWSEINFOW* -> Ptr{BROWSEINFOW}
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
# Unicode(-W): Cwstring には transcode(UInt16, "...") 等で UTF-16 を渡す。local ffi = require("ffi")
ffi.cdef[[
void* SHBrowseForFolderW(
void* lpbi);
]]
local shell32 = ffi.load("shell32")
-- shell32.SHBrowseForFolderW(lpbi)
-- lpbi : BROWSEINFOW*
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
-- Unicode(-W): uint16_t* には UTF-16LE のバッファ(ffi.new("uint16_t[?]", ...))を渡す。const koffi = require('koffi');
const lib = koffi.load('SHELL32.dll');
const SHBrowseForFolderW = lib.func('__stdcall', 'SHBrowseForFolderW', 'void *', ['void *']);
// SHBrowseForFolderW(lpbi)
// lpbi : BROWSEINFOW* -> 'void *'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。const lib = Deno.dlopen("SHELL32.dll", {
SHBrowseForFolderW: { parameters: ["pointer"], result: "pointer" },
});
// lib.symbols.SHBrowseForFolderW(lpbi)
// lpbi : BROWSEINFOW* -> "pointer"
// 文字列は "buffer"。Unicode(-W) は new TextEncoder() ではなく UTF-16LE のバイト列(末尾に \x00\x00)を Uint8Array で渡す。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。<?php
$ffi = FFI::cdef(<<<C
void* SHBrowseForFolderW(
void* lpbi);
C, "SHELL32.dll");
// $ffi->SHBrowseForFolderW(lpbi);
// lpbi : BROWSEINFOW*
// 構造体/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.UNICODE_OPTIONS);
Pointer SHBrowseForFolderW(
Pointer lpbi // BROWSEINFOW*
);
}
// Unicode(-W): WString(入力)/char[](出力)で UTF-16 をマーシャリング。@[Link("shell32")]
lib LibSHELL32
fun SHBrowseForFolderW = SHBrowseForFolderW(
lpbi : BROWSEINFOW* # BROWSEINFOW*
) : ITEMIDLIST*
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef SHBrowseForFolderWNative = Pointer<Void> Function(Pointer<Void>);
typedef SHBrowseForFolderWDart = Pointer<Void> Function(Pointer<Void>);
final SHBrowseForFolderW = DynamicLibrary.open('SHELL32.dll')
.lookupFunction<SHBrowseForFolderWNative, SHBrowseForFolderWDart>('SHBrowseForFolderW');
// lpbi : BROWSEINFOW* -> Pointer<Void>
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。{$mode objfpc}{$H+}
function SHBrowseForFolderW(
lpbi: Pointer // BROWSEINFOW*
): Pointer; stdcall;
external 'SHELL32.dll' name 'SHBrowseForFolderW';import Foreign
import Foreign.C.Types
import Foreign.C.String
foreign import stdcall safe "SHBrowseForFolderW"
c_SHBrowseForFolderW :: Ptr () -> IO (Ptr ())
-- lpbi : BROWSEINFOW* -> Ptr ()
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。open Ctypes
open Foreign
let shbrowseforfolderw =
foreign "SHBrowseForFolderW"
((ptr void) @-> returning (ptr void))
(* lpbi : BROWSEINFOW* -> (ptr void) *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)(cffi:define-foreign-library shell32 (t "SHELL32.dll"))
(cffi:use-foreign-library shell32)
(cffi:defcfun ("SHBrowseForFolderW" shbrowse-for-folder-w :convention :stdcall) :pointer
(lpbi :pointer)) ; BROWSEINFOW*
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。use Win32::API;
my $SHBrowseForFolderW = Win32::API::More->new('SHELL32',
'LPVOID SHBrowseForFolderW(LPVOID lpbi)');
# my $ret = $SHBrowseForFolderW->Call($lpbi);
# lpbi : BROWSEINFOW* -> LPVOID
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。
# Unicode(-W): LPCWSTR/LPWSTR は Win32::API が UTF-16 変換を行う。関連項目
- f SHBrowseForFolderA (ANSI版) — フォルダー選択ダイアログ(ANSI)を表示する。