FolderBrowserDialogの機能拡張 への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 葉月  (社会人)
投稿日時
2009/4/4 07:02:19
neptuneさん、お疲れ様です。
実装できたようで何よりです。
提示されている
http://support.microsoft.com/kb/306285/ja
のURLにも興味があります。
FolderBrowserDialogをあまり使わないので、何時いじるかわかりませんが、
取り組んでみようと思います。
>>>#なお、先の(自信なし)ソースでこれはやばいってな箇所があればご指摘ください。
掲載されているコードは、InitDirectoryの部分が静的に記述されていました。
ディレクトリの指定は、動的に行った方がいいと思います。
静的に行うと環境が変わった時にエラーになる可能性があります。
動的に扱う例として、自分が汎用的に使っている駄目クラスの一部を載せます。
横着してC#のままコピペしています。ご了承ください。
メイン機のOSがVistaなので、ドキュメントを基準にしています。
自分がパスを指定する際は、このクラスを中継して記述します。
それから、MSDNの命名規則に違反してたりして、微妙なクラスになっているのはご了承ください。
実装できたようで何よりです。
提示されている
http://support.microsoft.com/kb/306285/ja
のURLにも興味があります。
FolderBrowserDialogをあまり使わないので、何時いじるかわかりませんが、
取り組んでみようと思います。
>>>#なお、先の(自信なし)ソースでこれはやばいってな箇所があればご指摘ください。
掲載されているコードは、InitDirectoryの部分が静的に記述されていました。
ディレクトリの指定は、動的に行った方がいいと思います。
静的に行うと環境が変わった時にエラーになる可能性があります。
With clsBrowse
.InitDirectory = "E:\VS2008"
'省略
End With
動的に扱う例として、自分が汎用的に使っている駄目クラスの一部を載せます。
横着してC#のままコピペしています。ご了承ください。
/// <summary>
/// ユーザー名までのディレクトリを返す。
/// </summary>
/// <returns>現在、ログインしているユーザのディレクトリ</returns>
public String GetUserPath()
{
// ドライブ名のみを取得。
string strDrive = Directory.GetCurrentDirectory();
strDrive = strDrive.Substring(0, strDrive.IndexOf('\\'));
return string.Concat(strDrive, @"\Users\", Environment.UserName);
}
/// <summary>
/// ドキュメントまでのディレクトリを返す。
/// </summary>
/// <returns>ドキュメントまでのパスを返す</returns>
public String GetDocument()
{
return string.Concat(this.GetUserPath(), @"\Documents");
}
// 他のメソッドを省略
メイン機のOSがVistaなので、ドキュメントを基準にしています。
自分がパスを指定する際は、このクラスを中継して記述します。
それから、MSDNの命名規則に違反してたりして、微妙なクラスになっているのはご了承ください。
投稿者 neptune  (社会人)
投稿日時
2009/4/3 08:30:02
え~一人で書いてます。感想です。
最初FolderBrowserDialogコントロールでのRunDialogとHockProcの使い方で質問しました。
で、結果SHBrowseForFolder を使って、RunDialogとHockProcを使わず、
APIでのソースになってしまいました。
葉月 さんから
>RunDialogとHockProcの組み合わせも、コードをガリガリ書くイメージがあります。
のような書き込みがあり、調べていたんですが、例えば、ファイルを開くダイアログにしても
RunDialogとHockProcを使っても、結局GetOpenFileName APIを使うという事に
気が付きました。
要はOFNHookProc APIの代わりにHockProcという名前になりGetOpenFileName を
動作させる為にShowDialogを使ってRunDialogを動かす仕組みになったように感じています。
はっきり言って、個人的にはそれならその仕組み自体はAPIで書いたほうが
わかり易いですし、コード量も同じようなもんと思います。
RunDialogとHockProcで書くメリットが感じられません。
先日SHBrowseForFolder の(自信なし)ソースをUPしましたが、しっかり作りこんでおけば
それで、いくらでも使い回しが効くので、他のCommonDialogもその方が楽チンかなと思ってます。
以上RunDialogとHockProc感想でした。
これにて、一件落着とします。
それにしても、RunDialogとHockProcは皆さん殆ど利用しないのかサンプルは少なかったです。
#なお、先の(自信なし)ソースでこれはやばいってな箇所があればご指摘ください。
最初FolderBrowserDialogコントロールでのRunDialogとHockProcの使い方で質問しました。
で、結果SHBrowseForFolder を使って、RunDialogとHockProcを使わず、
APIでのソースになってしまいました。
葉月 さんから
>RunDialogとHockProcの組み合わせも、コードをガリガリ書くイメージがあります。
のような書き込みがあり、調べていたんですが、例えば、ファイルを開くダイアログにしても
RunDialogとHockProcを使っても、結局GetOpenFileName APIを使うという事に
気が付きました。
要はOFNHookProc APIの代わりにHockProcという名前になりGetOpenFileName を
動作させる為にShowDialogを使ってRunDialogを動かす仕組みになったように感じています。
はっきり言って、個人的にはそれならその仕組み自体はAPIで書いたほうが
わかり易いですし、コード量も同じようなもんと思います。
RunDialogとHockProcで書くメリットが感じられません。
先日SHBrowseForFolder の(自信なし)ソースをUPしましたが、しっかり作りこんでおけば
それで、いくらでも使い回しが効くので、他のCommonDialogもその方が楽チンかなと思ってます。
以上RunDialogとHockProc感想でした。
これにて、一件落着とします。
それにしても、RunDialogとHockProcは皆さん殆ど利用しないのかサンプルは少なかったです。
#なお、先の(自信なし)ソースでこれはやばいってな箇所があればご指摘ください。
投稿者 neptune  (社会人)
投稿日時
2009/4/1 07:58:04
続き
Public Sub New(ByVal pOwner As IntPtr)
m_Owner = pOwner
End Sub
Protected Overrides Sub Finalize()
'm_BInfo = Nothing
MyBase.Finalize()
End Sub
Public Function ShowDirDialog() As String
Dim sRet As String = ""
Dim pID As IntPtr
With m_BInfo
.hWndOwner = m_Owner
.pidlRoot = IntPtr.Zero
.lpszTitle = m_Description
.ulFlags = BIF_NEWDIALOGSTYLE Or BIF_EDITBOX 'EditBox表示
.lpfn = AddressOf BrowseHookProc 'コールバック関数のアドレス
End With
'「フォルダの参照」ダイアログの呼び出し
pID = SHBrowseForFolder(m_BInfo)
If Not pID = IntPtr.Zero Then
sRet = New String(vbNullChar, MAX_PATH)
'SHBrowseForFolderで得られた値からフォルダのパス名を取得
SHGetPathFromIDList(pID, sRet)
'割り当てられたメモリを開放
CoTaskMemFree(pID)
End If
Return sRet
End Function
'コールバック
Private Function BrowseHookProc(ByVal hwnd As IntPtr, ByVal uMsg As Integer, _
ByVal lParam As IntPtr, ByVal lpData As IntPtr) As Integer
Select Case uMsg
Case BFFM_INITIALIZED 'ダイアログ初期化
Dim ret As Integer = SendMessage(hwnd, BFFM_SETSELECTION, 1, _
m_InitDirectory) '初期フォルダ指定
'Console.WriteLine(ret.ToString())
Return True
End Select
Return False
End Function
'初期フォルダを指定する
Public Property InitDirectory() As String
Get
Return m_InitDirectory
End Get
Set(ByVal value As String)
m_InitDirectory = value & vbNullChar
End Set
End Property
'Descriptionの設定
Public Property Title() As String
Get
Return m_Description
End Get
Set(ByVal value As String)
m_Description = value
End Set
End Property
End Class
////////////使い方///////////
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim clsBrowse As New SHBrowseForFolderClass(Me.Handle)
Dim sRet As String
With clsBrowse
.InitDirectory = "E:\VS2008"
.Title = "フォルダを選択して下さい。"
sRet = .ShowDirDialog()
End With
If sRet <> "" Then
MessageBox.Show(sRet)
End If
End Sub
End Class
投稿者 neptune  (社会人)
投稿日時
2009/4/1 07:56:50
一応動きます程度のサンプルとしてUPしておきます。
不要な宣言とか、無駄もありますが、その辺はご勘弁。
(こんなものでも、すぐ動くサンプルは殆どなさそうなので)
初期フォルダの指定、選択したフォルダ名の表示をするようにしてます。
本気で使う時は、きっちり作りこんで下さい。
本当はC#のサンプル
http://support.microsoft.com/kb/306285/ja
をVBで書き直すのがよさそうです。
なお、これはやばいぞってな所があれば、お教え頂ければ幸いです。
不要な宣言とか、無駄もありますが、その辺はご勘弁。
(こんなものでも、すぐ動くサンプルは殆どなさそうなので)
初期フォルダの指定、選択したフォルダ名の表示をするようにしてます。
本気で使う時は、きっちり作りこんで下さい。
本当はC#のサンプル
http://support.microsoft.com/kb/306285/ja
をVBで書き直すのがよさそうです。
なお、これはやばいぞってな所があれば、お教え頂ければ幸いです。
Imports System.Runtime.InteropServices
Public Class BrowseForFolder
#Region "API宣言"
Private Const BFFM_INITIALIZED As Integer = 1
Private Const BFFM_SELCHANGED As Integer = 2
Private Const BFFM_VALIDATEFAILED As Integer = 3
Private Const WM_USER As Integer = &H400
Private Const BFFM_SETSTATUSTEXTA As Integer = (WM_USER + 100)
Private Const BFFM_ENABLEOK As Integer = (WM_USER + 101)
Private Const BFFM_SETSELECTION As Integer = (WM_USER + 102)
Private Const MAX_PATH As Integer = 260
Private BIF_EDITBOX = &H10 'ダイアログボックス内にアイテム名入力用のテキストボックスを追加する
Private BIF_NEWDIALOGSTYLE = &H40
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Private Structure BROWSEINFO
Public hWndOwner As IntPtr
Public pidlRoot As Integer
Public pszDisplayName As IntPtr
<MarshalAs(UnmanagedType.LPTStr)> _
Public lpszTitle As String
Public ulFlags As Integer
<MarshalAs(UnmanagedType.FunctionPtr)> _
Public lpfn As BrowseCallbackProc
Public lParam As IntPtr
Public iImage As Integer
End Structure
Private Declare Auto Function SHBrowseForFolder Lib "shell32.dll" _
(ByRef bi As BROWSEINFO) As IntPtr
Private Declare Auto Function SHGetPathFromIDList Lib "shell32.dll" _
(ByVal pidl As IntPtr, ByVal pszPath As String) As Integer
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As IntPtr, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer
'Auto修飾子を付けたらSendMessageが失敗する(Alias "SendMessageA"がなくても失敗する。理由はわからない)
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As IntPtr, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As String) As Integer
'SHGetPathFromIDListで取得したItemIDListを開放する
Private Declare Function CoTaskMemFree Lib "ole32.dll" (ByVal pv As Integer) As Integer
#End Region
#Region "Class宣言"
Private Delegate Function BrowseCallbackProc(ByVal hwnd As IntPtr, ByVal uMsg As Integer, _
ByVal lParam As IntPtr, ByVal lpData As IntPtr) As Integer
'プロパティ保管用
Private m_BInfo As BROWSEINFO
Private m_Owner As IntPtr '親ウィンドウのHWND
Private m_InitDirectory As String '初期表示フォルダを指定する際に使用
Private m_Description As String 'STATUSTEXT
Private m_TitleBarText As String 'タイトルバーテキスト
Private m_ShowEditBox As Boolean 'EditBoxの表示指定
#End Region
投稿者 neptune  (社会人)
投稿日時
2009/3/30 07:55:13
SHBrowseForFolder APIでササッと書こうと思っていましたが、案外苦戦中。
こんなC#なサンプルがありましたけど、それにしても少ない。
http://support.microsoft.com/kb/306285/ja
VB6やC++なら沢山あるのに、.net以降では一気に情報が少なくなりますね。
こんなC#なサンプルがありましたけど、それにしても少ない。
http://support.microsoft.com/kb/306285/ja
VB6やC++なら沢山あるのに、.net以降では一気に情報が少なくなりますね。
投稿者 neptune  (社会人)
投稿日時
2009/3/28 22:05:06
葉月さん、こんにちは。
今日はまだ、始動してないneptuneです。
調べていただいてすみません。
http://www.kanazawa-net.ne.jp/~pmansato/net/net_technics.htm
の方は私も発見していたんですが、そうなんです。継承がFolderBrowserDialogでは
出来ないんですよね。
>私にとっては、かなり難しく感じました。初心者なので、そう感じるだけかも知れません
私も万年初心者で、VB.net以降についてはあまり勉強してないので滅茶苦茶ややこしいです。
取り合えず、APIゴリゴリでやるつもりになってきたんですが、宿題で、
frameworkでのやり方も引き続き調べていこうと思います。
って、やってみるしかないみたいですが。。。
質問の方ですが
>2.FolderBrowserDialogのframeworkを使ったHWNDの取得の仕方
はどうも関係ないような気もしてきました。
今日はまだ、始動してないneptuneです。
調べていただいてすみません。
http://www.kanazawa-net.ne.jp/~pmansato/net/net_technics.htm
の方は私も発見していたんですが、そうなんです。継承がFolderBrowserDialogでは
出来ないんですよね。
>私にとっては、かなり難しく感じました。初心者なので、そう感じるだけかも知れません
私も万年初心者で、VB.net以降についてはあまり勉強してないので滅茶苦茶ややこしいです。
取り合えず、APIゴリゴリでやるつもりになってきたんですが、宿題で、
frameworkでのやり方も引き続き調べていこうと思います。
って、やってみるしかないみたいですが。。。
質問の方ですが
>2.FolderBrowserDialogのframeworkを使ったHWNDの取得の仕方
はどうも関係ないような気もしてきました。
投稿者 葉月  (社会人)
投稿日時
2009/3/28 12:00:35
neputuneさん、こんにちは。
RunDialogとHockProcの組み合わせも、コードをガリガリ書くイメージがあります。
興味があったので、少し調べました。
参考になったサイトを掲載します。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=161&KLOG=1
OpenFileダイアログの話ですが、下の方で発言されている名無しさんの意見が参考になります。
試していませんが、サンプル(C#)もありました。
http://www.kanazawa-net.ne.jp/~pmansato/net/net_technics.htm
ここにHookProcのサンプルがあります。
ColorDialogクラスを継承して使っております。
FolderBrowserDialogクラスに置き換えていけるかと思いましたが……
残念ながら、FolderBrowserDialogクラスは継承できないので無理でした。
私にとっては、かなり難しく感じました。初心者なので、そう感じるだけかも知れません。
RunDialogとHockProcの組み合わせは興味があります。
サンプルがあると重宝しますので、出来上がったら掲載してもらえると嬉しいです(他力本願)
RunDialogとHockProcの組み合わせも、コードをガリガリ書くイメージがあります。
興味があったので、少し調べました。
参考になったサイトを掲載します。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=161&KLOG=1
OpenFileダイアログの話ですが、下の方で発言されている名無しさんの意見が参考になります。
試していませんが、サンプル(C#)もありました。
http://www.kanazawa-net.ne.jp/~pmansato/net/net_technics.htm
ここにHookProcのサンプルがあります。
ColorDialogクラスを継承して使っております。
FolderBrowserDialogクラスに置き換えていけるかと思いましたが……
残念ながら、FolderBrowserDialogクラスは継承できないので無理でした。
私にとっては、かなり難しく感じました。初心者なので、そう感じるだけかも知れません。
RunDialogとHockProcの組み合わせは興味があります。
サンプルがあると重宝しますので、出来上がったら掲載してもらえると嬉しいです(他力本願)
投稿者 neptune  (社会人)
投稿日時
2009/3/28 08:33:16
こんにちは
FolderBrowserDialog の機能拡張の仕方をご教示お願いします。
FolderBrowserDialog は初めて使います。
FolderBrowserDialogコントロールにTextBoxを実装してやろうと思うのですが、
どうも、プロパティとして用意されてなくDialogをHookしてやらなければならない
ということがわかりました。
で、キーワードとしてRunDialog HookProc等はMSDNから調べられて、
MSDNの解説には
///////////////////////以下引用/////////////////////////
継承クラスでは、特定のコモン ダイアログ ボックスを作成するために、ShowDialog を呼び出す
ことによって RunDialog を実装する必要があります。継承クラスでは、HookProc をオーバーライド
して、ダイアログ ボックスに対して特定のフック機能を実装することもできます。
///////////////////引用終わり////////////////////////////
と書いてあるんですが、使い方が良くわかりません。
「FolderBrowserDialog RunDialog HookProc」でググッても見たんですが、
どうもVBのサンプルも(日本語では)見当たらないようです。外国語も多分???
しかし、この程度のことなら誰もやってないはずないんですけどねぇ・・・
やはりSHBrowseForFolderでゴリゴリ書くしかないんでしょうか??
それなら
BIF_EDITBOX = &H10
をflgに追加してやるということは理解してます。
しかしながら、FolderBrowserDialogのHWNDもAPIで取得しなければならないのか、
それとも、なにかMSDNに書いてない方法があるのかもわかりません。
プロパティにない事は確認してます。
恐らく、FolderBrowserDialogでも同様な処理が必要とは推測してますので、RunDialog HookProc
の使い方がわかれば何とかなるような気がします。
長くなったので纏めます。
目的としてはFolderBrowserDialogをHookしてflgにBIF_EDITBOXを追加したい。
質問事項は以下のようになります。
1.FolderBrowserDialogの RunDialog HookProcの使い方
2.FolderBrowserDialogのframeworkを使ったHWNDの取得の仕方
3.普通APIでゴリゴリやるもんなんでしょうか??
よろしくお願いします。
FolderBrowserDialog の機能拡張の仕方をご教示お願いします。
FolderBrowserDialog は初めて使います。
FolderBrowserDialogコントロールにTextBoxを実装してやろうと思うのですが、
どうも、プロパティとして用意されてなくDialogをHookしてやらなければならない
ということがわかりました。
で、キーワードとしてRunDialog HookProc等はMSDNから調べられて、
MSDNの解説には
///////////////////////以下引用/////////////////////////
継承クラスでは、特定のコモン ダイアログ ボックスを作成するために、ShowDialog を呼び出す
ことによって RunDialog を実装する必要があります。継承クラスでは、HookProc をオーバーライド
して、ダイアログ ボックスに対して特定のフック機能を実装することもできます。
///////////////////引用終わり////////////////////////////
と書いてあるんですが、使い方が良くわかりません。
「FolderBrowserDialog RunDialog HookProc」でググッても見たんですが、
どうもVBのサンプルも(日本語では)見当たらないようです。外国語も多分???
しかし、この程度のことなら誰もやってないはずないんですけどねぇ・・・
やはりSHBrowseForFolderでゴリゴリ書くしかないんでしょうか??
それなら
BIF_EDITBOX = &H10
をflgに追加してやるということは理解してます。
しかしながら、FolderBrowserDialogのHWNDもAPIで取得しなければならないのか、
それとも、なにかMSDNに書いてない方法があるのかもわかりません。
プロパティにない事は確認してます。
恐らく、FolderBrowserDialogでも同様な処理が必要とは推測してますので、RunDialog HookProc
の使い方がわかれば何とかなるような気がします。
長くなったので纏めます。
目的としてはFolderBrowserDialogをHookしてflgにBIF_EDITBOXを追加したい。
質問事項は以下のようになります。
1.FolderBrowserDialogの RunDialog HookProcの使い方
2.FolderBrowserDialogのframeworkを使ったHWNDの取得の仕方
3.普通APIでゴリゴリやるもんなんでしょうか??
よろしくお願いします。
アドバイスありがとうございます。
私は、汎用性を持たせるときは、特殊フォルダ取得にはSHGetSpecialFolderPath APIを
使用するようにしています。
と、言ってもまだ、vb6以降では配布するようなものを作ったことないので、
本当の汎用性を持たせる際参考にさせていただきます。
所で、今日GetOpenFileNameの方でクラス作成していたんですが、構造体の
宣言って、ややこしいですねぇ。OPENFILENAME構造体なんですが、
構造体のサイズって、
.lStructSize = Marshal.SizeOf(ofn)
とやらなければならないのがなかなかわかりませんでした。
文字列のメンバも
MarshalAs(UnmanagedType・・・
ってな感じで宣言しなければならないし。
自由度は高くなりますけどその分鬱陶しいです。
Unmanaged扱いしなければならなくなった事でAPIは本当に使いにくくなった様に感じます。
なのでできれば使わないに越したことはないですね。