次の方法で共有


方法 : 共有スレッド上に Windows フォームを表示することで COM 相互運用をサポートする

更新 : 2007 年 11 月

コンポーネント オブジェクト モデル (COM) 相互運用機能に関する問題は、フォームを .NET Framework メッセージ ループに表示することで解決できます。このメッセージ ループは、Application.Run メソッドを使って作成します。

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

共有メッセージ ループを持つ新しいスレッドに Windows フォームを表示する方法を、次のコード例に示します。

Visual Studio では、この機能に対する広範なサポートが用意されています。

使用例

共有スレッドに Windows フォームを表示する方法は、「方法 : 独自のスレッドで各 Windows フォームを表示して COM 相互運用機能をサポートする」に示されている方法に似ています。ただし、独自のメッセージ ループを使って各フォームを独自のスレッドに表示するのではなく、.NET Framework コンポーネント内の 1 つの新しいスレッド上でのみ実行する共有メッセージ ループを作成します。

この方法は、標準の Windows フォーム アプリケーションの動作を、より正確に表しています。また、すべてのフォームが同じスレッドで実行するため、複数のフォーム間で簡単にリソースを共有できます。「方法 : 独自のスレッドで各 Windows フォームを表示して COM 相互運用機能をサポートする」のソリューションは、フォームごとに新しいスレッドを作成することです。この場合、異なるフォーム間でリソースを共有するためのスレッド同期コードが必要です。

共有スレッドにおけるフォームの表示は、Windows フォーム アプリケーションの動作と非常に似ているため、.NET Framework Windows フォームでは、.NET Framework メッセージ ループが停止すると、クライアント アプリケーションが閉じます。この動作は、ApplicationContext のメイン フォームとして指定されているフォームをユーザーが閉じると発生します。メッセージ ループを開始するには、ApplicationContext を使用します。

次のコード例では、ApplicationContext のメイン フォームが、クライアント アプリケーションが開く最初のフォームに設定されています。そのため、ユーザーがそのフォーム インスタンスを閉じると、.NET Framework メッセージ ループが終了し、他のすべての Windows フォームが閉じます。

Imports System.Windows.Forms
Imports System.Runtime.InteropServices

<ComClass(COMForm.ClassId, COMForm.InterfaceId, COMForm.EventsId)> _
Public Class COMForm

#Region "COM GUIDs"
    ' These  GUIDs provide the COM identity for this class 
    ' and its COM interfaces. If you change them, existing 
    ' clients will no longer be able to access the class.
    Public Const ClassId As String = "9322c6dd-2738-428b-ba89-414ce2ea1941"
    Public Const InterfaceId As String = "210f5b8e-296a-4e26-bd7b-cd2cffa43389"
    Public Const EventsId As String = "f25c0ebb-2a2e-42b5-bf20-4bb84989a7da"
#End Region

    ' A creatable COM class must have a Public Sub New() 
    ' with no parameters, otherwise, the class will not be 
    ' registered in the COM registry and cannot be created 
    ' via CreateObject.
    Public Sub New()
        MyBase.New()
    End Sub

    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

End Class
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
Imports System.Windows.Forms

Public Class Form1
    Inherits System.Windows.Forms.Form

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MessageBox.Show("Clicked button")
    End Sub

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing AndAlso components IsNot Nothing Then
            components.Dispose()
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
        Me.TextBox1 = New System.Windows.Forms.TextBox
        Me.TextBox2 = New System.Windows.Forms.TextBox
        Me.TextBox3 = New System.Windows.Forms.TextBox
        Me.Button1 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'TextBox1
        '
        Me.TextBox1.Location = New System.Drawing.Point(12, 12)
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.Size = New System.Drawing.Size(100, 20)
        Me.TextBox1.TabIndex = 0
        '
        'TextBox2
        '
        Me.TextBox2.Location = New System.Drawing.Point(12, 38)
        Me.TextBox2.Name = "TextBox2"
        Me.TextBox2.Size = New System.Drawing.Size(100, 20)
        Me.TextBox2.TabIndex = 1
        '
        'TextBox3
        '
        Me.TextBox3.Location = New System.Drawing.Point(12, 64)
        Me.TextBox3.Name = "TextBox3"
        Me.TextBox3.Size = New System.Drawing.Size(100, 20)
        Me.TextBox3.TabIndex = 2
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(12, 90)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(75, 23)
        Me.Button1.TabIndex = 3
        Me.Button1.Text = "Button1"
        Me.Button1.UseVisualStyleBackColor = True
        '
        'Form1
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(130, 138)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.TextBox3)
        Me.Controls.Add(Me.TextBox2)
        Me.Controls.Add(Me.TextBox1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)
        Me.PerformLayout()

    End Sub
    Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
    Friend WithEvents TextBox2 As System.Windows.Forms.TextBox
    Friend WithEvents TextBox3 As System.Windows.Forms.TextBox
    Friend WithEvents Button1 As System.Windows.Forms.Button
End Class

コードのコンパイル方法

  • COMForm、Form1、および FormManager の各型を、COMWinform.dll という名前のアセンブリにコンパイルします。「COM 用のアセンブリのパッケージ化」に示されているメソッドの 1 つを使って、アセンブリを COM 相互運用用として登録します。これで、アンマネージ アプリケーションで、アセンブリと対応するタイプ ライブラリ (.tlb) ファイルを使用できます。たとえば、Visual Basic 6.0 実行可能プロジェクト内の参照としてタイプ ライブラリを使用できます。

参照

処理手順

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

方法 : 独自のスレッドで各 Windows フォームを表示して COM 相互運用機能をサポートする

概念

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

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

COM へのアセンブリの登録

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