Пошаговое руководство. Поддержка COM-взаимодействия путем отображения каждой формы Windows Forms в отдельном потоке

Обновлен: Ноябрь 2007

Проблемы COM-взаимодействия можно устранить путем отображения формы в цикле обработки сообщений .NET Framework, который создается с помощью метода Application.Run.

Чтобы исправить работу формы Windows Forms из клиентского приложения COM, необходимо запустить его в цикле обработки сообщений Windows Forms. Для этого воспользуйтесь одним из перечисленных ниже подходов.

В следующем примере демонстрируется способ отображения форм Windows Forms в отдельном потоке.

Чтобы скопировать весь текст кода из этой темы, см. раздел Практическое руководство. Поддержка COM-взаимодействия путем отображения каждой формы Windows Forms в отдельном потоке.

Процедура

Поместите форму в отдельный поток и вызовите метод Application.Run для запуска загрузки сообщений Windows Forms для этого потока. Чтобы использовать этот подход, необходимо упаковать все вызовы в форму из неуправляемого приложения с помощью метода Invoke.

Для этого подхода требуется, чтобы каждый экземпляр формы выполнялся в своем собственном потоке с помощью своего собственного цикла обработки сообщений. Нельзя использовать более одного цикла обработки сообщений в каждом потоке. Таким образом, изменение цикла обработки сообщений клиентского приложения невозможно. Однако можно изменить компонент .NET Framework для запуска нового потока, использующего собственный цикл обработки сообщений.

Создание отдельного экземпляра формы Windows Forms в новом потоке

  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. Добавьте ссылку на библиотеку типов COMWinform, которая была создана при построении решения Visual Basic 2005.

    -либо-

    Если библиотека отсутствует в списке, нажмите кнопку Обзор, чтобы вручную найти файл библиотеки (с расширением 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

См. также

Задачи

Практическое руководство. Поддержка COM-взаимодействия путем отображения формы Windows Forms с помощью метода ShowDialog

Пошаговое руководство. Поддержка COM-взаимодействия путем отображения форм Windows Forms в совместно используемом потоке

Основные понятия

Предоставление COM-клиентам доступа к компонентам .NET Framework

Упаковка сборки для модели COM

Регистрация сборок в COM

Общие сведения о Windows Forms и неуправляемых приложениях