C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

FolderBrowserDialogでネットワークのみ選択

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■90042 / inTopicNo.1)  FolderBrowserDialogでネットワークのみ選択
  
□投稿者/ yu (1回)-(2019/02/01(Fri) 06:41:58)

分類:[.NET 全般] 

開発環境:Visual Studio 2012 使用言語:C#

FolderBrowserDialogでネットワークのみを選択できるようにしたいです。

デフォルトのパス指定だと初期値をselectedPathで設定できるかと思うのですが、
ネットワークのみの選択を、パスもしくはプロパティにて指定することは可能でしょうか。

よろしくお願いいたします。
引用返信 編集キー/
■90044 / inTopicNo.2)  Re[1]: FolderBrowserDialogでネットワークのみ選択
□投稿者/ 魔界の仮面弁士 (2034回)-(2019/02/01(Fri) 10:42:20)
No90042 (yu さん) に返信
> FolderBrowserDialogでネットワークのみを選択できるようにしたいです。

そういう機能は無いと思います。

無理矢理な方法として、

 typeof(FolderBrowserDialog)
  .GetField("rootFolder", BindingFlags.Instance | BindingFlags.NonPublic)
  .SetValue(folderBrowserDialog1, 0x12);

とすれば、「デスクトップ\ネットワーク」をルート階層にできますが、
その下の階層が展開される環境でしか使えなさそう。
引用返信 編集キー/
■90046 / inTopicNo.3)  Re[2]: FolderBrowserDialogでネットワークのみ選択
□投稿者/ とっちゃん (572回)-(2019/02/01(Fri) 11:02:45)
No90042 (yu さん) に返信
> 開発環境:Visual Studio 2012 使用言語:C#
>
> FolderBrowserDialogでネットワークのみを選択できるようにしたいです。
>
> デフォルトのパス指定だと初期値をselectedPathで設定できるかと思うのですが、
> ネットワークのみの選択を、パスもしくはプロパティにて指定することは可能でしょうか。
>

var dlg = new FolderBrowserDialog();
dlg.RootFolder = Environment.SpecialFolder.MyComputer;
dlg.ShowDialog();

こんな感じで設定すると、Windows 10 なら PC に限定してリストアップできるのですが、
RootFolder の選択肢の SpecialFolder に "ネットワーク" を意味する識別子を用意していないので
.NET Framework の FolderBrowseDialog では指定ができません。

一応。。。大元のAPIの SHBrowseForFolder を直接利用すれば指定できますが、
あの構造体宣言とかすごく面倒なのであまりお勧めはできません。

それと、ネットワークドライブを割り当てている場合見れないので
実際のところは選択後に意図したフォルダを選択されたか?とチェックするほうがいいと思います。


あとは、IOpenFileDialog を使ってフォルダ選択するというのもあります。
こっちも、ネットワークドライブとかあると絞り込めないので結果的には変わりませんが。。。

引用返信 編集キー/
■90047 / inTopicNo.4)  Re[2]: FolderBrowserDialogでネットワークのみ選択
□投稿者/ yu (2回)-(2019/02/01(Fri) 12:15:08)
魔界の仮面弁士 様

回答ありがとうございます。

やはりネットワークの階層を展開できる環境ではなかったため、表示できませんでした。

無理矢理な方法、と仰いましたが、なるほど!と思わされる方法でした。
よろしければ、"0x12"がネットワークの番号だとどのように調べたのか教えていただけませんか?
とても気になってしまいました…。


No90044 (魔界の仮面弁士 さん) に返信
> ■No90042 (yu さん) に返信
>>FolderBrowserDialogでネットワークのみを選択できるようにしたいです。
>
> そういう機能は無いと思います。
>
> 無理矢理な方法として、
>
>  typeof(FolderBrowserDialog)
>   .GetField("rootFolder", BindingFlags.Instance | BindingFlags.NonPublic)
>   .SetValue(folderBrowserDialog1, 0x12);
>
> とすれば、「デスクトップ\ネットワーク」をルート階層にできますが、
> その下の階層が展開される環境でしか使えなさそう。
解決済み
引用返信 編集キー/
■90057 / inTopicNo.5)  Re[3]: FolderBrowserDialogでネットワークのみ選択
□投稿者/ 魔界の仮面弁士 (2035回)-(2019/02/01(Fri) 16:05:04)
2019/02/02(Sat) 10:15:12 編集(投稿者)

# 解決済みマークはつけたままにしておきます。

No90047 (yu さん) に返信
> 無理矢理な方法、と仰いましたが、なるほど!と思わされる方法でした。

No90044 はリフレクションで、Backing-Field 変数に強制代入していますが、
これは要するに、下記に相当する処理であることを意味します。

 const int CSIDL_NETWORK = 0x0012
 folderBrowserDialog1.RootFolder = (System.Environment.SpecialFolder)CSIDL_NETWORK;


しかし、RootFolder プロパティの setter は下記の実装になっており、そのままだと例外で失敗するため、
それを回避するため、rootFolder メンバーへの直接代入で回避していたというわけで。

 if (!Enum.IsDefined(typeof(System.Environment.SpecialFolder), value))
 {
  throw new InvalidEnumArgumentException("value", (int)value, typeof(System.Environment.SpecialFolder));
 }
 rootFolder = value;


> よろしければ、"0x12"がネットワークの番号だとどのように調べたのか教えていただけませんか?

0x12 は、"ネットワーク" フォルダーを意味する識別子です。
Windows SDK 上では CSIDL_NETWORK 定数として定義されています。(see: ShFolder.h , KnownFolders.h)


=======================
同じ処理を COM 版で書くとこんな感じ。

Shell32.dll を参照設定した上で、
ShellSpecialFolderConstants 列挙型の ssfNETWORK を利用できます。


const int BIF_NEWDIALOGSTYLE = 0x40;
const int BIF_NONEWFOLDERBUTTON = 0x200;

int Hwnd = (int)(long)Handle;
string Title = "フォルダを選択して下さい";
int Options = BIF_NEWDIALOGSTYLE | BIF_NONEWFOLDERBUTTON;
object RootFolder = Shell32.ShellSpecialFolderConstants.ssfNETWORK;

Shell32.Shell sh = new Shell32.Shell();
Shell32.Folder fo = sh.BrowseForFolder(Hwnd, Title, Options, RootFolder);

string selectedFolder = null;
if ( fo != null)
{
  Shell32.FolderItems fis = fo.Items();
  Shell32.FolderItem fi = fis.Item(Type.Missing);
  selectedFolder = fi.Path;
  Marshal.ReleaseComObject(fi);
  Marshal.ReleaseComObject(fis);
  Marshal.ReleaseComObject(fis);
  Marshal.ReleaseComObject(fo);
}
Marshal.ReleaseComObject(sh);

return selectedFolder;

=======================
参照設定したくなければ、レイトバインドで。

dynamic sh = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
dynamic fo = sh.BrowseForFolder((int)(long) Handle, "フォルダを選択して下さい", 0x240, 0x12);
string selectedFolder = null;
if ( fo != null)
{
  dynamic fis = fo.Items();
  dynamic fi = fis.Item();
  selectedFolder = fi.Path;
  Marshal.ReleaseComObject(fi);
  Marshal.ReleaseComObject(fo);
}
Marshal.ReleaseComObject(sh);
return selectedFolder;


=======================
上記 COM の BrowseForFolder メソッドや
.NET の FolderBrowserDialog クラスというものは、
SHBrowseForFolder という API をカプセル化したものです。
https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/nf-shlobj_core-shbrowseforfolderw
https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/nf-shlobj_core-shbrowseforfoldera
https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/FolderBrowserDialog.cs,94edc2b722c18d1f
解決済み
引用返信 編集キー/
■90062 / inTopicNo.6)  Re[3]: FolderBrowserDialogでネットワークのみ選択
□投稿者/ yu (4回)-(2019/02/02(Sat) 01:22:08)
とっちゃん 様

ご回答ありがとうございます。

C#の世界だけで考え過ぎていました、なるほど…。
しかし初心者の私には、SHBrowseForFolder を直接利用するのは難しそうでした。

仰る通り、IOpenFileDialog を使ってフォルダ選択をすると絞り込めないのですが、
やはり、選択後に意図したフォルダを選択されたかのチェックで進めていこうかと思います。

貴重なご意見、感謝いたします。


No90046 (とっちゃん さん) に返信
> ■No90042 (yu さん) に返信
>>開発環境:Visual Studio 2012 使用言語:C#
>>
>>FolderBrowserDialogでネットワークのみを選択できるようにしたいです。
>>
>>デフォルトのパス指定だと初期値をselectedPathで設定できるかと思うのですが、
>>ネットワークのみの選択を、パスもしくはプロパティにて指定することは可能でしょうか。
>>
>
> var dlg = new FolderBrowserDialog();
> dlg.RootFolder = Environment.SpecialFolder.MyComputer;
> dlg.ShowDialog();
>
> こんな感じで設定すると、Windows 10 なら PC に限定してリストアップできるのですが、
> RootFolder の選択肢の SpecialFolder に "ネットワーク" を意味する識別子を用意していないので
> .NET Framework の FolderBrowseDialog では指定ができません。
>
> 一応。。。大元のAPIの SHBrowseForFolder を直接利用すれば指定できますが、
> あの構造体宣言とかすごく面倒なのであまりお勧めはできません。
>
> それと、ネットワークドライブを割り当てている場合見れないので
> 実際のところは選択後に意図したフォルダを選択されたか?とチェックするほうがいいと思います。
>
>
> あとは、IOpenFileDialog を使ってフォルダ選択するというのもあります。
> こっちも、ネットワークドライブとかあると絞り込めないので結果的には変わりませんが。。。
>
引用返信 編集キー/
■90066 / inTopicNo.7)  Re[4]: FolderBrowserDialogでネットワークのみ選択
□投稿者/ yu (5回)-(2019/02/04(Mon) 02:54:26)
2019/02/04(Mon) 02:57:08 編集(投稿者)
魔界の仮面弁士 様

すごい…なるほど。
設定された識別子以外で設定するのは、特にC#ではやはり難しいですね。

実際にWindows SDK のコードで確認するには開発ツールのダウンロードが必要なようですね。
今の開発環境だとすぐには確認できず残念です。

初心者ながらに色々と調べてみましたが、知識不足でせっかく教えていただいた内容を
全ては理解しきれておらず大変申し訳ないですが、非常に勉強になりました。

ご回答いただきまして本当にありがとうございます。


No90057 (魔界の仮面弁士 さん) に返信
> 2019/02/02(Sat) 10:15:12 編集(投稿者)
>
> # 解決済みマークはつけたままにしておきます。
>
> ■No90047 (yu さん) に返信
>>無理矢理な方法、と仰いましたが、なるほど!と思わされる方法でした。
>
> No90044 はリフレクションで、Backing-Field 変数に強制代入していますが、
> これは要するに、下記に相当する処理であることを意味します。
>
>  const int CSIDL_NETWORK = 0x0012
>  folderBrowserDialog1.RootFolder = (System.Environment.SpecialFolder)CSIDL_NETWORK;
>
>
> しかし、RootFolder プロパティの setter は下記の実装になっており、そのままだと例外で失敗するため、
> それを回避するため、rootFolder メンバーへの直接代入で回避していたというわけで。
>
>  if (!Enum.IsDefined(typeof(System.Environment.SpecialFolder), value))
>  {
>   throw new InvalidEnumArgumentException("value", (int)value, typeof(System.Environment.SpecialFolder));
>  }
>  rootFolder = value;
>
>
>>よろしければ、"0x12"がネットワークの番号だとどのように調べたのか教えていただけませんか?
>
> 0x12 は、"ネットワーク" フォルダーを意味する識別子です。
> Windows SDK 上では CSIDL_NETWORK 定数として定義されています。(see: ShFolder.h , KnownFolders.h)
>
>
> =======================
> 同じ処理を COM 版で書くとこんな感じ。
>
> Shell32.dll を参照設定した上で、
> ShellSpecialFolderConstants 列挙型の ssfNETWORK を利用できます。
>
>
> const int BIF_NEWDIALOGSTYLE = 0x40;
> const int BIF_NONEWFOLDERBUTTON = 0x200;
>
> int Hwnd = (int)(long)Handle;
> string Title = "フォルダを選択して下さい";
> int Options = BIF_NEWDIALOGSTYLE | BIF_NONEWFOLDERBUTTON;
> object RootFolder = Shell32.ShellSpecialFolderConstants.ssfNETWORK;
>
> Shell32.Shell sh = new Shell32.Shell();
> Shell32.Folder fo = sh.BrowseForFolder(Hwnd, Title, Options, RootFolder);
>
> string selectedFolder = null;
> if ( fo != null)
> {
>   Shell32.FolderItems fis = fo.Items();
>   Shell32.FolderItem fi = fis.Item(Type.Missing);
>   selectedFolder = fi.Path;
>   Marshal.ReleaseComObject(fi);
>   Marshal.ReleaseComObject(fis);
>   Marshal.ReleaseComObject(fis);
>   Marshal.ReleaseComObject(fo);
> }
> Marshal.ReleaseComObject(sh);
>
> return selectedFolder;
>
> =======================
> 参照設定したくなければ、レイトバインドで。
>
> dynamic sh = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
> dynamic fo = sh.BrowseForFolder((int)(long) Handle, "フォルダを選択して下さい", 0x240, 0x12);
> string selectedFolder = null;
> if ( fo != null)
> {
>   dynamic fis = fo.Items();
>   dynamic fi = fis.Item();
>   selectedFolder = fi.Path;
>   Marshal.ReleaseComObject(fi);
>   Marshal.ReleaseComObject(fo);
> }
> Marshal.ReleaseComObject(sh);
> return selectedFolder;
>
>
> =======================
> 上記 COM の BrowseForFolder メソッドや
> .NET の FolderBrowserDialog クラスというものは、
> SHBrowseForFolder という API をカプセル化したものです。
> https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/nf-shlobj_core-shbrowseforfolderw
> https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/nf-shlobj_core-shbrowseforfoldera
> https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/FolderBrowserDialog.cs,94edc2b722c18d1f
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ