Пошаговое руководство. Поддержка COM-взаимодействия путем отображения форм Windows Forms в совместно используемом потоке
Обновлен: Ноябрь 2007
Проблемы COM-взаимодействия можно устранить путем отображения формы в цикле обработки сообщений .NET Framework, который создается с помощью метода Application.Run.
Чтобы исправить работу формы Windows Forms из клиентского приложения COM, необходимо запустить его в цикле обработки сообщений Windows Forms. Для этого воспользуйтесь одним из перечисленных ниже подходов.
Используйте метод Form.ShowDialog для отображения формы Windows Forms. Дополнительные сведения см. в разделе Практическое руководство. Поддержка COM-взаимодействия путем отображения формы Windows Forms с помощью метода ShowDialog.
Отображайте каждую форму Windows Forms в отдельном потоке. Дополнительные сведения см. в разделе Пошаговое руководство. Поддержка COM-взаимодействия путем отображения каждой формы Windows Forms в отдельном потоке.
Создайте общий цикл обработки сообщений в новом потоке компонента .NET Framework.
В следующем примере демонстрируется способ отображения форм Windows Forms в новом потоке с помощью общего цикла обработки сообщений.
Чтобы скопировать весь текст кода из этой темы, см. раздел Практическое руководство. Поддержка COM-взаимодействия путем отображения Windows Forms в общем потоке.
Процедура
Этот подход аналогичен процедуре, описанной в разделе Пошаговое руководство. Поддержка COM-взаимодействия путем отображения каждой формы Windows Forms в отдельном потоке. Однако вместо отображения каждой формы в своем собственном потоке с помощью собственного цикла обработки сообщений создается общий цикл обработки сообщений, который будет выполняться только в одном новом потоке в компоненте .NET Framework.
Этот подход более точно представляет поведение стандартного приложения Windows Forms. Он также упрощает совместное использование ресурсов между несколькими формами, так как все формы выполняются в одном и том же потоке. Решение из раздела Пошаговое руководство. Поддержка COM-взаимодействия путем отображения каждой формы Windows Forms в отдельном потоке создает новый поток для каждой формы. Для этого решения требуется дополнительный код синхронизации потоков для совместного использования ресурсов различными формами.
Поскольку отображение форм в общем потоке больше напоминает поведение приложения Windows Forms, будет показано, что с помощью .NET Framework Windows Forms клиентское приложение закрывается при остановке цикла обработки сообщений .NET Framework. Такое поведение наблюдается, когда пользователь закрывает форму, которая обозначается как главная форма для класса ApplicationContext. Класс ApplicationContext используется для запуска цикла обработки сообщений.
В следующих примерах кода главная форма класса ApplicationContext присваивается первой форме, которая открывается клиентским приложением. Таким образом, когда пользователь закрывает этот экземпляр формы, происходит выход из цикла обработки сообщений .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).
Добавьте в форму кнопку.
В меню Вид выберите Код и добавьте следующий код в модуль формы.
Option Explicit
Private Sub Command1_Click()
Dim frm As COMWinform.COMForm
Set frm = New COMWinform.COMForm
frm.ShowForm1
End Sub
Чтобы скомпилировать проект, в меню Файл выберите команду Создать EXE.
Запустите скомпилированный исполняемый файл Visual Basic 6.0.
Для отображения формы Windows Forms из созданной ранее библиотеки классов нажмите кнопку.
Установите фокус на один из элементов управления TextBox на форме Windows Forms и нажмите клавишу TAB для переключения элементов управления.
Обратите внимание, что клавиша TAB перемещает фокус с одного элемента управления на другой. Имейте также в виду, что событие кнопки Click возникает при нажатии клавиши ВВОД.
См. также
Задачи
Основные понятия
Предоставление COM-клиентам доступа к компонентам .NET Framework