misc.log

日常茶飯事とお仕事と

別スレッドから親スレッドのコントロールをいじる

別スレッドで動くC++.NETで作成したライブラリから発生するイベントを受けて、自作ビューワコントロールに「タブを追加して複数のイメージを各タブに表示」という処理を行うと、下記のエラーが発生した。

System.ArgumentExceptionのハンドルされていない例外が 
system.windows.forms.dll で発生しました。

追加情報 : あるスレッドで作成されたコントロールに対して、
別のスレッドのコントロールを親にすることはできません。

最初は何のことだか?という感じだったが、結局、

  • 別スレッドで動くライブラリにAddHandlerで関連付けられたイベント処理は、主フォームとは別のスレッド管理下におかれてしまう。
  • スレッド間で、相手が管理するオブジェクトに対する命令実行は制限される。

ということらしい。スレッド系の処理は、正直「未経験」(←仕事を始めて、ずーっとVB5.0、VB6.0の世界だけだったから)。というわけでこういうのはすんごく苦手なのだが、以下のサイトを参考にしてうまく切り抜けられた。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/vbcon/html/vbtskmanipulatingcontrolsfromthreads.asp

'呼び出したいメソッドと同じシグネチャのデリゲートを宣言
Public Delegate Sub AddImages_Delegated(ByVal Files As ArrayList)

'別スレッドの監視ライブラリからのメッセージ受信
Private Function EventReceive(ByVal EventType As Integer) As Integer

    Dim FileNames As New ArrayList
    FileNames.Add("c:\testdata.jpg")
    FileNames.Add("c:\transalp.jpg")

    '↓本来やりたかった処理
    'MainViewer.AddImages(FileNames)

    '↓代わりに実行する処理
    MainViewer.Invoke( _
        New AddImages_Delegated(AddressOf MainViewer.AddImages), _
        New Object() {FileNames})

End Function

MainViewerはプロジェクト内に組み込まれたユーザーコントロールで、ファイル名を含んだArrayListを元に、複数のイメージをタブで重ねて同時表示する。この表示処理内部では、すでにあるタブに、新しく生成したタブを動的に追加するという処理が含まれており、エラーはそこで発生していた。

インサイドWINDOWS 第6版 上 (Microsoft Press)

インサイドWINDOWS 第6版 上 (Microsoft Press)