Пошаговое руководство. Поддержка COM-взаимодействия путем отображения каждой формы Windows Forms в отдельном потоке
Обновлен: Ноябрь 2007
Проблемы COM-взаимодействия можно устранить путем отображения формы в цикле обработки сообщений .NET Framework, который создается с помощью метода Application.Run.
Чтобы исправить работу формы Windows Forms из клиентского приложения COM, необходимо запустить его в цикле обработки сообщений Windows Forms. Для этого воспользуйтесь одним из перечисленных ниже подходов.
Используйте метод Form.ShowDialog для отображения формы Windows Form. Дополнительные сведения см. в разделе Практическое руководство. Поддержка COM-взаимодействия путем отображения формы Windows Forms с помощью метода ShowDialog.
Отображайте каждую форму Windows Forms в отдельном потоке.
Создайте общий цикл обработки сообщений в новом потоке компонента .NET Framework. Дополнительные сведения см. в разделе Пошаговое руководство. Поддержка COM-взаимодействия путем отображения форм Windows Forms в совместно используемом потоке.
В следующем примере демонстрируется способ отображения форм Windows Forms в отдельном потоке.
Чтобы скопировать весь текст кода из этой темы, см. раздел Практическое руководство. Поддержка COM-взаимодействия путем отображения каждой формы Windows Forms в отдельном потоке.
Процедура
Поместите форму в отдельный поток и вызовите метод Application.Run для запуска загрузки сообщений Windows Forms для этого потока. Чтобы использовать этот подход, необходимо упаковать все вызовы в форму из неуправляемого приложения с помощью метода Invoke.
Для этого подхода требуется, чтобы каждый экземпляр формы выполнялся в своем собственном потоке с помощью своего собственного цикла обработки сообщений. Нельзя использовать более одного цикла обработки сообщений в каждом потоке. Таким образом, изменение цикла обработки сообщений клиентского приложения невозможно. Однако можно изменить компонент .NET Framework для запуска нового потока, использующего собственный цикл обработки сообщений.
Создание отдельного экземпляра формы Windows Forms в новом потоке
Создайте новый проект библиотеки классов и назовите его COMWinform.
Удалите файл Class1.vb по умолчанию.
В меню Проект выберите команду Добавить класс.
Выберите шаблон COM-класс.
В поле Имя введите COMForm.vb и нажмите кнопку Добавить.
Вставьте следующие операторы в верхней части файла COMForm над определением класса.
Imports System.Windows.Forms Imports System.Runtime.InteropServices
В 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
В меню Проект щелкните Добавить класс и выберите шаблон Класс.
В поле Имя введите FormManager.vb и нажмите кнопку Добавить.
Замените код в файле 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
В меню Проект выберите Добавить форму Windows, затем щелкните Добавить.
Дважды щелкните Button1, чтобы добавить обработчик события Click.
В обработчик события Click добавьте следующий код.
Private Sub Button1_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click MessageBox.Show("Clicked button") End Sub
Выполните сборку решения.
На этом шаге проект также регистрируется для COM-взаимодействия на данном компьютере.
Чтобы создать исполняемый файл, демонстрирующий COM-взаимодействие
Запустите Microsoft Visual Basic 6.0
Создайте новый проект EXE.
В меню Проект щелкните Ссылки.
Добавьте ссылку на библиотеку типов COMWinform, которая была создана при построении решения Visual Basic 2005.
-либо-
Если библиотека отсутствует в списке, нажмите кнопку Обзор, чтобы вручную найти файл библиотеки (с расширением TLB).
Добавьте в форму кнопку.
В меню Вид выберите Код и добавьте следующий код в модуль формы.
[Visual Basic]
Option Explicit
Private Sub Command1_Click()
Dim frm As COMWinform.COMForm
Set frm = New COMWinform.COMForm
frm.ShowForm1
End Sub
См. также
Задачи
Основные понятия
Предоставление COM-клиентам доступа к компонентам .NET Framework