チュートリアル : Windows フォームを別個のスレッドに表示することによって COM 相互運用をサポートする

更新 : 2007 年 11 月

COM 相互運用機能に関する問題は、フォームを .NET Framework メッセージ ループに表示することで解決できます。このメッセージ ループは、Application.Run メソッドを使って作成します。

COM クライアント アプリケーションから Windows フォームを正しく動作させるには、フォームを Windows フォーム メッセージ ループで実行する必要があります。この場合、次のいずれかの方法を使用します。

次のプロシージャは、Windows フォームを別個のスレッドに表示する方法を示しています。

このトピックのコードを単一のリストとしてコピーするには、「方法 : 独自のスレッドで各 Windows フォームを表示して COM 相互運用機能をサポートする」を参照してください。

手順

フォームを別個のスレッドに配置し、Application.Run メソッドを呼び出すと、Windows フォーム メッセージ ポンプがそのスレッドで開始されます。この方法を使うには、Invoke メソッドを使って、アンマネージ アプリケーションからフォームへのすべての呼び出しをマーシャリングする必要があります。

この方法を使う場合、フォームの各インスタンスが個別のメッセージ ループを使って個別のスレッドで動作する必要があります。1 つのスレッドで複数のメッセージ ループを使うことはできません。したがって、クライアント アプリケーションのメッセージ ループは変更できません。ただし、.NET Framework コンポーネントを変更して、別個のメッセージ ループを使う新しいスレッドを開始することはできます。

Windows フォームの各インスタンスを新しいスレッドに作成するには

  1. 新しいクラス ライブラリ プロジェクトを作成して、COMWinform と命名します。

  2. 既定の Class1.vb ファイルを削除します。

  3. [プロジェクト] メニューの [クラスの追加] を選択します。

  4. [COM クラス] テンプレートをクリックします。

  5. [ファイル名] ボックスに「COMForm.vb」と入力し、[追加] をクリックします。

  6. 次のコード ステートメントを、COMForm ファイルの先頭部分にあるクラス定義の前に貼り付けます。

    Imports System.Windows.Forms
    Imports System.Runtime.InteropServices
    
  7. COMForm クラス定義内のコンストラクタ定義の下に、次のコードを貼り付けます。

    Private WithEvents frmManager As FormManager
    
    Public Sub ShowForm1()
        ' Call the StartForm method by using a new instance
        ' of the Form1 class.
        StartForm(New Form1)
    End Sub
    
    Private Sub StartForm(ByVal frm As Form)
    
        ' This procedure is used to show all forms
        ' that the client application requests. When the first form
        ' is displayed, this code will create a new message
        ' loop that runs on a new thread. The new form will
        ' be treated as the main form.
    
        ' Later forms will be shown on the same message loop.
        If IsNothing(frmManager) Then
            frmManager = New FormManager(frm)
        Else
            frmManager.ShowForm(frm)
        End If
    End Sub
    
    Private Sub frmManager_MessageLoopExit() _
    Handles frmManager.MessageLoopExit
    
        'Release the reference to the frmManager object.
        frmManager = Nothing
    
    End Sub
    
  8. [プロジェクト] メニューの [クラスの追加] をクリックします。次に、[クラス] テンプレートをクリックします。

  9. [ファイル名] ボックスに「FormManager.vb」と入力し、[追加] をクリックします。

  10. FormManager ファイルの内容を次のコードに置き換えます。

    Imports System.Runtime.InteropServices
    Imports System.Threading
    Imports System.Windows.Forms
    
    <ComVisible(False)> _
    Friend Class FormManager
        ' This class is used so that you can generically pass any
        ' form that you want to the delegate.
    
        Private WithEvents appContext As ApplicationContext
        Private Delegate Sub FormShowDelegate(ByVal form As Form)
        Event MessageLoopExit()
    
        Public Sub New(ByVal MainForm As Form)
            Dim t As Thread
            If IsNothing(appContext) Then
                appContext = New ApplicationContext(MainForm)
                t = New Thread(AddressOf StartMessageLoop)
                t.IsBackground = True
                t.SetApartmentState(ApartmentState.STA)
                t.Start()
            End If
        End Sub
    
        Private Sub StartMessageLoop()
            ' Call the Application.Run method to run the form on its own message loop.
            Application.Run(appContext)
        End Sub
    
        Public Sub ShowForm(ByVal form As Form)
    
            Dim formShow As FormShowDelegate
    
            ' Start the main form first. Otherwise, focus will stay on the 
            ' calling form.
            appContext.MainForm.Activate()
    
            ' Create a new instance of the FormShowDelegate method, and
            ' then invoke the delegate off the MainForm object.
            formShow = New FormShowDelegate( _
            AddressOf ShowFormOnMainForm_MessageLoop)
    
            appContext.MainForm.Invoke(formShow, New Object() {form})
        End Sub
    
        Private Sub ShowFormOnMainForm_MessageLoop(ByVal form As Form)
            form.Show()
        End Sub
    
        Private Sub ac_ThreadExit( _
        ByVal sender As Object, _
        ByVal e As System.EventArgs) _
        Handles appContext.ThreadExit
            appContext.MainForm.Dispose()
            appContext.MainForm = Nothing
            appContext.Dispose()
            appContext = Nothing
            RaiseEvent MessageLoopExit()
        End Sub
    End Class
    
  11. [プロジェクト] メニューの [Windows フォームの追加] をクリックします。次に、[追加] をクリックします。

  12. フォームに TextBox コントロールおよび Button コントロールを追加します。

  13. [Button1] をダブルクリックして Click イベント ハンドラを追加します。

  14. Click イベント ハンドラに次のコードを追加します。

    Private Sub Button1_Click( _
    ByVal sender As System.Object, _
    ByVal e As System.EventArgs) _
    Handles Button1.Click
        MessageBox.Show("Clicked button")
    End Sub
    
  15. ソリューションをビルドします。

    また、このステップでは、プロジェクトをこのコンピュータの COM 相互運用機能に登録します。

COM 相互運用機能を使用する実行可能ファイルを作成するには

  1. Microsoft Visual Basic 6.0 を起動します。

  2. 新しい標準 EXE プロジェクトを作成します。

  3. [プロジェクト] メニューの [参照設定] をクリックします。

  4. Visual Basic 2005 ソリューションの生成時に作成された COMWinform タイプ ライブラリへの参照を追加します。

    または

    このタイプ ライブラリが一覧に表示されていない場合は、[参照] をクリックしてタイプ ライブラリ (.tlb) ファイルを手動で見つけます。

  5. フォームにボタンを追加します。

  6. [表示] メニューの [コード] をクリックし、以下のコードをフォーム モジュールに追加します。

[Visual Basic]

Option Explicit

Private Sub Command1_Click()
    Dim frm As COMWinform.COMForm
    Set frm = New COMWinform.COMForm
    frm.ShowForm1
End Sub

参照

処理手順

方法 : ShowDialog メソッドで Windows フォームを表示して COM 相互運用機能をサポートする

チュートリアル : Windows フォームを共有スレッドに表示することによって COM 相互運用をサポートする

概念

COM への .NET Framework コンポーネントの公開

COM 用のアセンブリのパッケージ化

COM へのアセンブリの登録

Windows フォームおよびアンマネージ アプリケーションの概要