다음을 통해 공유


방법: 공유 스레드에서 Windows Forms을 표시하여 COM Interop 지원

업데이트: 2007년 11월

Application.Run 메서드를 사용하여 만들어지는 .NET Framework 메시지 루프에 폼을 표시하여 COM 상호 운용성 문제를 해결할 수 있습니다.

COM 클라이언트 응용 프로그램에서 Windows Form이 올바르게 작동하도록 하려면 응용 프로그램을 Windows Forms 메시지 루프에서 실행해야 합니다. 이렇게 하려면 다음 방법 중 하나를 사용합니다.

다음 코드 예제에서는 공유 메시지 루프를 가진 새 스레드에서 Windows Forms을 표시하는 방법을 보여 줍니다.

Visual Studio에서는 이 기능이 폭넓게 지원됩니다.

예제

Windows Forms을 공유 스레드에서 표시하는 방법은 방법: 각 Windows Form을 별개의 스레드에서 표시하여 COM Interop 지원에서 보여 준 방법과 비슷합니다. 그러나 자체 메시지 루프를 사용하여 자체 스레드에서 각 폼을 표시하는 대신 .NET Framework 구성 요소에 있는 단 하나의 새 스레드에서 실행되는 공유 메시지 루프를 만듭니다.

이 방법은 표준 Windows Forms 응용 프로그램의 동작을 보다 정확하게 나타냅니다. 또한 같은 스레드에서 모든 폼이 실행되기 때문에 여러 폼에서 리소스를 더욱 쉽게 공유할 수 있습니다. 방법: 각 Windows Form을 별개의 스레드에서 표시하여 COM Interop 지원의 솔루션은 각 폼에 대해 새 스레드를 만듭니다. 이 솔루션을 실행하려면 서로 다른 폼 간에 리소스를 공유하기 위한 추가 스레드 동기화 코드가 필요합니다.

공유 스레드에서 폼을 표시하는 방법이 Windows Forms 응용 프로그램과 더욱 비슷하게 작동하므로 .NET Framework Windows Forms을 사용할 경우 클라이언트 응용 프로그램은 .NET Framework 메시지 루프가 중지될 때 닫힙니다. 이 동작은 사용자가 ApplicationContext의 기본 폼으로 지정된 폼을 닫을 때 발생합니다. ApplicationContext는 메시지 루프를 시작하는 데 사용합니다.

다음 코드 예제에서는 ApplicationContext의 기본 폼을 클라이언트 응용 프로그램에서 처음으로 열리는 폼으로 설정합니다. 그러므로 사용자가 해당 폼 인스턴스를 닫으면 .NET Framework 메시지 루프가 종료되고 다른 모든 Windows Forms도 닫힙니다.

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에서 사용할 어셈블리의 패키징에 설명된 메서드 중 하나를 사용하여 COM interop에 대한 어셈블리를 등록합니다. 이제 어셈블리와 해당 형식 라이브러리 파일(.tlb)을 관리되지 않는 응용 프로그램에서 사용할 수 있습니다. 예를 들어, Visual Basic 6.0 실행 프로젝트에서 형식 라이브러리를 참조로 사용할 수 있습니다.

참고 항목

작업

방법: ShowDialog 메서드로 Windows Form을 표시하여 COM Interop 지원

방법: 각 Windows Form을 별개의 스레드에서 표시하여 COM Interop 지원

개념

.NET Framework 구성 요소를 COM에 노출

COM에서 사용할 어셈블리의 패키징

COM에 어셈블리 등록

Windows Forms 및 관리되지 않는 응용 프로그램 개요