トップ回答者
別スレッド上でCOMインターフェイスのメソッドを呼び出すには

質問
-
Windows Vistaで採用された、サムネイル画像を取得するための新しいインターフェイス「IThumbnailProvider」を実装しようと、Windows SDKに含まれているC++のサンプルコードをC#向けにに書き直しています(Windows Vista上のVisual C# 2008で作成)。
[ComImport] [GuidAttribute("43826d1e-e718-42ee-bc55-a1e261c37bfe")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IShellItem { [PreserveSig] int BindToHandler(IntPtr pbcReserved, ref Guid rbhid, ref Guid riid, ref IThumbnailProvider ppvOut); void Compare(IShellItem psi, uint hint, out int piorder); void GetAttributes(ulong sfgaoMask, out ulong psfgaoAttribs); void GetDisplayName(uint sigdnName, out string ppszName); void GetParent(ref IShellItem ppsi); } [ComImport] [Guid("e357fccd-a995-4576-b01f-234630154e96")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IThumbnailProvider { [PreserveSig] int GetThumbnail(uint cx, out IntPtr phbmp, out UInt32 pdwAlpha); } [DllImport("Shell32")] private extern static int SHCreateItemFromParsingName ([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, out IShellItem ppv); public static Image CreateThumbnail(string path, Size size) { Image resimg = null; IntPtr bitmap = IntPtr.Zero; IShellItem pFileItem; Guid itemRiid = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"); SHCreateItemFromParsingName(path, IntPtr.Zero, ref itemRiid, out pFileItem); if (pFileItem != null) { IThumbnailProvider pThumbProvider = null; Guid riid = new Guid("e357fccd-a995-4576-b01f-234630154e96"); Guid bhid = new Guid("7b2e650a-8e20-4f4a-b09e-6597afc72fb0"); pFileItem.BindToHandler(IntPtr.Zero, ref bhid, ref riid, ref pThumbProvider); if (pThumbProvider != null) { UInt32 u_dummy; uint width = (uint)size.Width, res; try { res = (uint)pThumbProvider.GetThumbnail(width, out bitmap, out u_dummy); resimg = Image.FromHbitmap(bitmap); } catch (Exception ex) { } } } return resimg; }
同じスレッド上からであればこのコードは正常に動作するのですが、BackgroundWorkerなどで別スレッドからこのメソッドを利用しようとすると、IThumbProvider.GetThumbnailの箇所でE_NOINTERFACEのエラーコードが帰ってきます。マルチスレッドでこのコードを利用できるようにするにはどうしたらよいでしょうか。
回答
-
IThumbnailProviderを使ったことがないので、外しているかもしれませんが、気になった点として書いておきます。
本当にマルチスレッドだから問題なのでしょうか?
BackgroundWorkerでのスレッドはMTAになりますが、ThreadクラスでThread.SetApartmentStateを使ってSTAとして開始したスレッドに処理させると状況に変化があるのでしょうか?
現時点では、マルチスレッドだから駄目だとは言い切れないので、COM関連のトラブルを疑っていって下さい。
# かなり同じような質問だったけれども、関係あるのかな?
# http://vsug.jp/tabid/63/forumid/-1/threadid/11554/scope/posts/Default.aspx
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク sk7474 2009年3月19日 9:25
-
Tank2005 さん の発言:ただ消すのではなく、どこで続きをやるとか、そういった誘導にしたらよかったんじゃないでしょうか。
参照リンク先のフォーラムにも投稿したのですが、回答がなかったのでこちらにも書き込ませていただきました(VSUGにはスレッドの削除方法がヘルプになかったためそのままとなっております)。
検索でタイトルで引っかかって、ページを開いてみたら中身が空というのは、同じ悩みを抱えている人にとっては不運としか言えません。
Tank2005 さん の発言:問題点が見えにくいのですが、「IThumbnailProviderを実装したクラスを自作した」のか、「IThumbnailProviderを利用するメソッドを自作した」のか、どちらが主眼なのでしょうか?お教えいただいたとおり試しにApartmentState.STAにパラメータを設定した上でThread.Start()を実行したところ、サムネイルを取得することができました(ApartmentState.MTAでは取得に失敗)。ということは、COMの属性設定などに抜け落ちている点があるのでしょうか。
当初の発言では”IThumbnailProviderを実装しようと"という行があるため、迷いました。
後者、つまり、利用するコードだけ書いているという前提であれば、STAだけで動く、MTAだけで動くというのは利用側の対策で何とかなるものではないはずです。
シェル絡みはSTAになることが多いかなと言う予想で書いていますので、MTAでも利用可能な手法があるかどうか等については存じません。
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク sk7474 2009年3月19日 9:25
すべての返信
-
IThumbnailProviderを使ったことがないので、外しているかもしれませんが、気になった点として書いておきます。
本当にマルチスレッドだから問題なのでしょうか?
BackgroundWorkerでのスレッドはMTAになりますが、ThreadクラスでThread.SetApartmentStateを使ってSTAとして開始したスレッドに処理させると状況に変化があるのでしょうか?
現時点では、マルチスレッドだから駄目だとは言い切れないので、COM関連のトラブルを疑っていって下さい。
# かなり同じような質問だったけれども、関係あるのかな?
# http://vsug.jp/tabid/63/forumid/-1/threadid/11554/scope/posts/Default.aspx
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク sk7474 2009年3月19日 9:25
-
Tank2005 さん の発言:ただ消すのではなく、どこで続きをやるとか、そういった誘導にしたらよかったんじゃないでしょうか。
参照リンク先のフォーラムにも投稿したのですが、回答がなかったのでこちらにも書き込ませていただきました(VSUGにはスレッドの削除方法がヘルプになかったためそのままとなっております)。
検索でタイトルで引っかかって、ページを開いてみたら中身が空というのは、同じ悩みを抱えている人にとっては不運としか言えません。
Tank2005 さん の発言:問題点が見えにくいのですが、「IThumbnailProviderを実装したクラスを自作した」のか、「IThumbnailProviderを利用するメソッドを自作した」のか、どちらが主眼なのでしょうか?お教えいただいたとおり試しにApartmentState.STAにパラメータを設定した上でThread.Start()を実行したところ、サムネイルを取得することができました(ApartmentState.MTAでは取得に失敗)。ということは、COMの属性設定などに抜け落ちている点があるのでしょうか。
当初の発言では”IThumbnailProviderを実装しようと"という行があるため、迷いました。
後者、つまり、利用するコードだけ書いているという前提であれば、STAだけで動く、MTAだけで動くというのは利用側の対策で何とかなるものではないはずです。
シェル絡みはSTAになることが多いかなと言う予想で書いていますので、MTAでも利用可能な手法があるかどうか等については存じません。
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク sk7474 2009年3月19日 9:25