Programming Field - プログラミング Tips

IShellBrowserのBrowseObjectが呼び出されるようにする

※Windows 7では以下の方法ではうまくいかないようです。2010/05/26追記
※Windows 7でうまくいく方法を追記しました。また、「SID_SShellBrowser」の表記を加えました。2010/05/29追記

IShellBrowserBrowseObjectメソッドは、IShellViewのウィンドウ内でフォルダがダブルクリックされたときなど、「ブラウザ」内で別の項目に遷移するときに呼び出されます。

ところが、Windows ExplorerによるIShellViewの実装である内部クラス「CDefView」(厳密にはさらに別の内部クラス)は、フォルダアイテムがダブルクリックされたときに単にIShellBrowserのBrowseObjectを呼び出すことはしません。IShellViewはCreateViewWindowによるウィンドウ作成時にIShellBrowserインスタンスが渡されるためそれを利用すればBrowseObjectを呼び出すことは可能ですが、CDefViewはそのインスタンスに対してIServiceProvider::QueryServiceを呼び出して新たにIShellBrowserのインスタンスを得て、そのインスタンスに対してBrowseObjectを呼び出そうとします。しかも、QueryServiceを呼び出すとき「guidService」に指定する値は「SID_STopLevelBrowser」ではなく「SID_SShellBrowser」(IID_IShellBrowserと同値)が渡されます

※ここでIShellBrowserインスタンスを取得できなかった場合、CDefViewは新たにWindows Explorerを起動してフォルダを表示しようとします。XPとそれ以前ではDDE通信を使ってその情報をブロードキャストするためそれを捉える事が出来ますが、Vista以降ではDDE通信は使われないためこの方法は使えません。
※Windows 7では「SID_SShellBrowser」の代わりに「SID_SInPlaceBrowser」(= {1D2AE02B-3655-46CC-B63A-285988153BCA})が渡されます。この定数はWindows SDK 7.0以降のShlGuid.hに定義されています。(参考: 「In-Place Shell Navigation with the WebBrowser Control on Windows 7 - EricLaw's IEInternals - Site Home - MSDN Blogs」)

したがって、IShellViewからのフォルダ遷移を自前のアプリケーションで処理したい場合は、BrowseObjectメソッドを実装すると同時に、IServiceProvider::QueryServiceメソッドで「guidService」が「SID_SShellBrowser」(および「SID_SInPlaceBrowser」)であるときの処理も実装する必要があります。

ちなみにこの方法で実装を行うと、ICommDlgBrowserを実装せずとも自前のアプリケーションでフォルダ遷移を行うことができるようになります。

P.S. Windows XP (SP2以降?)などで上記の実装をした場合、「マイ ドキュメント」など一部のフォルダをダブルクリックしても何も反応しないことがあります。この場合はIInternetHostSecurityManagerを実装し、QueryServiceで「SID_SInternetHostSecurityManager」を捉えるようにすると反応するようになります。

最終更新日: 2010/05/29 (作成: 2010/05/23)