夕暮ログ

C#やJavascript、最近はAndroidなんかも好きなtinqのブログ。「夕暮れログ」

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

エクスプローラ(Explorer.EXE)で開いているフォルダのパスを取得する


画像は私が現在使っているX-Finderというファイラーです。(X-Finderについて詳しくは公式サイトをご覧ください)
大変高機能でカスタマイズを仕切れていませんが、そのメニューに「エクスプローラの取り込み」や「他のウインドウのパス」といった項目が存在します。
その名の通り、エクスプローラで開いているパスを取得することができます。

それをC#でやってみます。

今回はdynamicやDllImportは使わずにやります。

参照の追加と用意


まずはテスト用のプロジェクトを作ります。
普通にフォームアプリケーションにしてください。

続いて、エクスプローラを操作するのに必要な参照の追加を行います。
エクスプローラはWindowsからInternet Explorerと同じ扱いを受けています。
そのためCOMを利用してアクセスすることができます。



「参照の追加」の「COM」タブから
・Microsoft Shell Controls And Automation
・Microsoft Internet Control
を選択して追加します。
前者はShell系、後者はInternetExplorerの操作をするために必要です。

ウィンドウの取得


まず、コードの一番上にusing Shell32;using SHDocVw;を追加しておきます。
(もちろんそれをせずにShell32.ShellClassなどと書いてもかまいませんが)

まずShellClassをnewしてインスタンスを作成します。
・・・というのがVisual Studoi 2008の時にはできたのですが、VS 2010にしたらできなくなったみたいです。
コンストラクタがないといわれてビルドが通りません。
ShellClassのかわりにShellというクラスを利用できそうです。
詳しくは
ShellClass shell = new ShellClass();がコンパイルエラーになるので調べてみた
にまとめてあります。ご覧ください。
追記有り。もともとのコードを使う方法は上のリンクをご覧ください。コメントありがとうございました!

そのインスタンスのWindowsメソッドからSHDocVw.ShellWindowsを取得します。
ShellWindowsはすべてのIEとエクスプローラの一覧になります。IEnumerableを実装しているためforeachで各ウインドウを列挙することができます。
このオブジェクトは、MSDNによるとSHDocVw.InternetExplorerになるようですが、SHDocVw.WebBrowserとしているところもあったので正直わかりません。
ということで、どちらのクラスでも実装しているSHDocVw.IWebBrowser2で受け取っておくのが安全かなぁと思います。

なお、MSDNのページは記事下部にまとめて書いてあるので参照してください。

そのIWebBrowser2の中でプロセス名(FullNameプロパティ)の実行ファイル名が「Explorer.EXE」のものだけを取得します。
大文字、小文字がわかりにくいので、ToUpperですべて大文字に変換して比較するといいと思います。

LocationNameで表示名、LocationURLで開いているフォルダ名が取得できます。
LocationNameは多くの場合フォルダ名ですが「ローカルディスク (C:\)」や「デスクトップ」といった特殊な名称が戻ることがあるので、表示名としてのみ利用してください。

サンプルコード


簡単なサンプルコードです。
button1とlistBoxが置いてあり、button1のイベントに以下を設定してください。

開いているフォルダ : 表示名
という形で表示されます。

private void button1_Click(object sender, EventArgs e)
{
//リストボックスをクリアしておく
listBox1.Items.Clear();

//COMのShellクラス作成
Shell shell = new Shell();
//IEとエクスプローラの一覧を取得
ShellWindows win = shell.Windows();
//列挙
foreach (IWebBrowser2 web in win)
{
//エクスプローラのみ(IEを除外)
if (Path.GetFileName(web.FullName).ToUpper() == "EXPLORER.EXE")
{
//リストに追加
listBox1.Items.Add(web.LocationURL + " : " + web.LocationName);
}
}
}



パスの形式を変える、エクスプローラを閉じる


結果を見るとわかりますが、C:\hogeのような形ではなくfileスキームがつき、URLエンコードされた状態で返されます。
基本的に.NETはfileスキームに対応していないようで、それをフォルダ名として利用しようとすると「URI フォーマットはサポートされていません」という例外が投げられてしまいます。
ファイル名として使う場合、
file:///やfile://localhost/、URLエンコードなどがされているパスをWindowsの形式に直す
の方法を使うのがいいと思います。Uriはfileスキームを認識できるので、そのLocalPathプロパティでOSの対応する形式に変換しています。
IEのオブジェクトはlocalhostなどの余分なものはつかないようなので問題はあまり起きないようです。


エクスプローラを閉じる場合、Quitメソッドを呼び出します。
エクスプローラを取り込む場合、間違えてInternetExplorerまで道連れにして落とさないように気を付けましょう。

問題点


しかし、この方法は大きな問題点を抱えています。
マイコンピュータやコントロールパネルなど、特殊なフォルダなどを開いているときにはパスが取得できません。(表示名は可能です。)
ですので、LocationURLが空になります。


LocationURLが空の場合は飛ばすようにしてください。

ただ、マイコンピュータはパスがないので仕方がないにしても、ライブラリ、ドキュメントなども取得できません。
これではかなり不便ですがX-Finderの場合にはこれにも対応しています。
C#でもできないことはないと思うのですが、簡単には対応できません。

やるとするといくつかのインターフェースをたどって最終的にPIDLを取得することになるようです。
しかし、C#でやるには深すぎるCOMの話で、私はそれほどCOMに詳しくないのでここでは遠慮しておきます。
というか、やってみたのですができませんでした。
X-Finderの作者さんのブログエクスプローラの取り込み - がかな?に情報があります。
ただし、WindowsVistaのことですので、Windows7やWindowsXPでどうなるかは不明です。

サンプルコード


取得できないファイルをはじくのと\区切りに直すのを実装したサンプルです。

private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();

Shell shell = new Shell();
ShellWindows win = shell.Windows();
foreach (IWebBrowser2 web in win)
{
if (Path.GetFileName(web.FullName).ToUpper() == "EXPLORER.EXE")
{
//パスを取得できなかったものを除外
if(web.LocationURL != "")
//Windowsのファイル形式に修正(c:\aaa\bbbのような形)
listBox1.Items.Add(new Uri(web.LocationURL).LocalPath + " : " + web.LocationName);
}
}
}


参考ページ


参考にしたページです。MSDNは皆さんご存知の通りちょくちょくURLが変わるのでリンク切れになっていたら検索してください。
エクスプローラの取り込み - がかな?
Windows Shell - MSDN WindowsのShell系のトップページ。
ShellWindows Object - MSDNwindowsメソッドの戻り値であるShellWindows
Reference for Visual Basic Developers - MSDNVisualBasicと書いてありますが、Shellに関するリファレンスです。
InternetExplorer Object - MSDNInternetExplorerオブジェクトです。
IWebBrowser2 Interface -MSDN上のInternetExplorerオブジェクトとほぼ同一のインターフェースです。
関連記事

コメント

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

ありがとうございます。

設定したら元のコードでも動くようになりました。
ありがとうございました^_^

エクスプローラのイベント取得方法について

参考となる内容でとてもわかりやすく読むことができました。

ひとつ質問ですが、起動中のエクスプローラのフォルダを選択した時にそのイベントを拾い、選択したフォルダパスを取得する事って可能でしょうか?

お返事遅れました

ここのところ忙しくて見ることができませんでした。ごめんなさい・・・

日付から見て、こちらの質問者の方でしょうか?後で見た方のためにリンク張っておきます。
http://social.msdn.microsoft.com/Forums/vstudio/ja-JP/dbf29a5e-3129-41cd-baf3-f0cab295a93e
COMは難しいですね・・・

承認待ちコメント

このコメントは管理者の承認待ちです

ここをクリックしてコメントを投稿

非公開コメント

トラックバック

http://tinqwill.blog59.fc2.com/tb.php/84-e01c3f6c

« next  ホーム  prev »

プロフィール

tinq tinq(もしくはTinqWill)

Sky  For   Every 改装予定

プログラミングお勉強中の高校生。月一くらいは更新したい

最新記事

カテゴリ

月別アーカイブ

検索フォーム

最新コメント

リンク

最新トラックバック

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。