DOBON.NET DOBON.NETプログラミング掲示板過去ログ

スレッド内でのCOMラッパー呼出

分類:[.NET]

はじめまして、やきにく羅生門と申します。
「.NET」ならずともプログラミングの初心者でございます。

現在、COMラッパーによって、OCXを利用したコーディングに取
り組んでいますが、のっぴきならない状態に追い込まれてしまい
まして、皆様のお力をお借りできないかと思い参上しました。

スレッドの中にて、ラッパーオブジェクトのメソッドを呼び出すと
プログラムがこけてしまいます。(036行目)
メッセージ:
「'System.Runtime.InteropServices.COMException' のハンドルさ
れていない例外が mscorlib.dll で発生しました。」

ラッパーあるいはOCX側を疑いまして、032行目を通常のプロシージ
ャとして呼び出したところ、問題なく動作しました。

また、以下のコードにて、34行目のように一方的にラッパーオブジ
ェクトのメソッドを呼び出す部分ではスレッド内であろうと不思議と
エラーは発生していません。

上記エラーを回避するためには、どうすれば宜しいのでしょうか。
COM関係に触れますので、場違いな質問でしたら申し訳ございません。
ただ、スレッド内外でのCOMラッパーの扱いの違いについて、とても
戸惑っています。

//////////////////////////////////////////////////////////////
開発OS :Windows 2000 Pro
開発環境:Visiul Studio.NET
開発言語:Visual Basic.NET
使用COM :GrapeCity社 LeadTools Raster Imaging版 12.0J
※.NETサポート対象外
トライアル版:ttp://www.grapecity.com/japan/support/database/VisualBasic_TrialVersions.htm
//////////////////////////////////////////////////////////////

000:Imports System.threading
001: Inherits System.Windows.Forms.Form
002:
003:Public class form1
004:
005: '〜省略〜
006:
007: Friend WithEvents Button1 As System.Windows.Forms.Button
008: 'ラッパーオブジェクトをフォームに貼り付ける
009: Friend WithEvents objOCX As AxLEADLib.AxLEAD
010:
011: <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
012:
013: Me.Button1 = New System.Windows.Forms.Button()
014: 'ラッパーオブジェクトのインスタンス生成
015: Me.objOCX = New AxLEADLib.AxLEAD()
016:
017: '〜省略〜
018:
019: End Sub
020:
021: 'Button1押下によりスレッドを開始する
022: Private Sub Button1_Click(ByVal sender As System.Object, _
023: ByVal e As System.EventArgs) Handles Button1.Click
024:
025: 'スレッドのインタンス生成
026: threadCall = New System.Threading.Thread(AddressOf Me.ThreadRun)
027:
028: threadCall.Start()
029:
030: End Sub
031: 'スレッド
032: Sub ThreadRun()
033:
034: objOCX.load("C\temp\test.jpg",0,1,1)
035:
036: dim bitmapData as Bitmap = objOCX.GetPicture()
037:
038: End Sub
039:
040:end class
> スレッドの中にて、ラッパーオブジェクトのメソッドを呼び出すと
> プログラムがこけてしまいます。(036行目)

System.Windows.Forms.Control クラスのヘルプより

> スレッドセーフ
> マルチスレッド操作で安全なのは、 BeginInvoke 、 EndInvoke 、 Invoke 、
> InvokeRequired 、 CreateGraphics の各メンバだけです。

とあります。そのため、コントロールのメソッドは
Invoke(BeginInvoke)メソッド経由で実行する必要があります。

> メッセージ:
> 「'System.Runtime.InteropServices.COMException' のハンドルさ
> れていない例外が mscorlib.dll で発生しました。」
>
> ラッパーあるいはOCX側を疑いまして、032行目を通常のプロシージ
> ャとして呼び出したところ、問題なく動作しました。
>
> また、以下のコードにて、34行目のように一方的にラッパーオブジ
> ェクトのメソッドを呼び出す部分ではスレッド内であろうと不思議と
> エラーは発生していません。

エラーが起きる場合と起きない場合があるのは、たぶん、
エラーが起きない場合のメソッドは純粋なロジックのメソッドで、
エラーが起きる場合のメソッドはOCX内部でウィンドウ(コントロール)に
アクセスしているためではないかなと思います。

どのメソッドがどういう実装なのかは作成者にしかわかりませんので、
安全に使用するには、使用者はすべてInvoke(BeginInvoke)メソッド経由で
実行するしかないと思います。

やきにく羅生門です。
よねKENさん、早速のレスありがとうございました。

よねKENさんの仰るとおりにコントロールのメソッドをデリゲー
トしてから、Invokeメソッドによる呼出に成功しました。

デリゲートをはじめて使いましたので、報告が遅れまして申し訳ご
ざいません。

> System.Windows.Forms.Control クラスのヘルプより
>
>>スレッドセーフ
>>マルチスレッド操作で安全なのは、 BeginInvoke 、 EndInvoke 、 Invoke 、
>>InvokeRequired 、 CreateGraphics の各メンバだけです。
>
> とあります。そのため、コントロールのメソッドは
> Invoke(BeginInvoke)メソッド経由で実行する必要があります。

関係するヘルプには、すべて目を通しているつもりなのですが、自
分の理解の足りない都合の悪い文章を読み飛ばす癖があるので、、、
、、、ご迷惑をお掛けします。

> エラーが起きる場合と起きない場合があるのは、たぶん、
> エラーが起きない場合のメソッドは純粋なロジックのメソッドで、
> エラーが起きる場合のメソッドはOCX内部でウィンドウ(コントロール)に
> アクセスしているためではないかなと思います。

なるほどです。
他のメソッドに関しても、安全性とパフォーマンスを検証して、デ
リゲート化する必要もありそうですね。

以下のソースは、同期や他スレッドのことを一切考えないで作って
みたのですが、スレッド内からCOMラッパー提供によるメソッドの呼
出に成功しました。

よねKENさん、HP拝見しました。これからも、勉強に伺わせて頂
きます。
重ね重ねありがとうございました。
また、ご考察いただきました皆様もありがとうございました。

これにて、私からの質問を「解決」とさせていただきます。

000:Imports System.threading
001:
002:Public class form1
003: Inherits System.Windows.Forms.Form
004:
005: '〜省略〜
006:
007: Friend WithEvents Button1 As System.Windows.Forms.Button
008: 'ラッパーオブジェクトをフォームに貼り付ける
009: Friend WithEvents objOCX As AxLEADLib.AxLEAD
010:
011: <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
012:
013: Me.Button1 = New System.Windows.Forms.Button()
014: 'ラッパーオブジェクトのインスタンス生成
015: Me.objOCX = New AxLEADLib.AxLEAD()
016:
017: '〜省略〜
018:
019: End Sub
020:
021: 'デリゲートの宣言
022: Delegate Function OCXDelegete() As System.Drawing.Image
023:
024: 'メソッドの委譲
025: Function OCXGetPicture() As Object
026:
027: Dim Del As New OCXDelegete(AddressOf Me.objOCX.GetPicture)
028:
029: Return Del
030:
031: End Function
032:
033: 'Button1押下によりスレッドを開始する
034: Private Sub Button1_Click(ByVal sender As System.Object, _
035: ByVal e As System.EventArgs) Handles Button1.Click
036:
037: 'スレッドのインタンス生成
038: threadCall = New System.Threading.Thread(AddressOf Me.ThreadRun)
039:
040: threadCall.Start()
041:
042: End Sub
043:
044: 'スレッド
045: Sub ThreadRun()
046:
047: objOCX.load("C\temp\test.jpg",0,1,1)
048:
049: dim bitmapData as Bitmap = Me.invoke(Me.OCXGetPicture)
050:
051: End Sub
052:
053:end class
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板