Comment : prendre en charge l'interopérabilité COM en affichant chaque Windows Form sur son propre thread
Vous pouvez résoudre les problèmes d'interopérabilité COM en affichant le formulaire dans une boucle de message .NET Framework, que vous pouvez créer à l'aide de la méthode Application.Run.
Pour qu'un Windows Form fonctionne correctement à partir d'une application cliente COM, vous devez exécuter le formulaire sur une boucle de message Windows Forms. Pour cela, utilisez l'une des approches suivantes :
Utilisez la méthode Form.ShowDialog pour afficher le Windows Form. Pour plus d'informations, consultez Comment : prendre en charge COM Interop en affichant un Windows Form avec la méthode ShowDialog.
Affichez chaque Windows Form sur un thread séparé.
Il existe une prise en charge étendue pour cette fonctionnalité dans Visual Studio.
Pour plus d'informations, consultez Procédure pas à pas : prise en charge de l'interopérabilité COM en affichant chaque Windows Form sur son propre thread et Procédure pas à pas : prise en charge de l'interopérabilité COM en affichant chaque Windows Form sur son propre thread et Procédure pas à pas : prise en charge de l'interopérabilité COM en affichant chaque Windows Form sur son propre thread et Procédure pas à pas : prise en charge de l'interopérabilité COM en affichant chaque Windows Form sur son propre thread et Procédure pas à pas : prise en charge de l'interopérabilité COM en affichant chaque Windows Form sur son propre thread.
Exemple
L'exemple de code suivant montre comment afficher le formulaire sur un thread distinct et appeler la méthode Application.Run pour démarrer une pompe de messages Windows Forms sur ce thread. Pour utiliser cette approche, vous devez marshaler tous les appels passés au formulaire à partir de l'application non managée en utilisant la méthode Invoke.
Cette approche requiert que chaque instance d'un formulaire s'exécute sur son propre thread en utilisant sa propre boucle de message. Plusieurs boucles de message ne peuvent pas s'exécuter par thread. Par conséquent, vous ne pouvez pas modifier la boucle de message de l'application cliente. Toutefois, vous pouvez modifier le composant .NET Framework pour démarrer un nouveau thread qui utilise sa propre boucle de message.
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 = "1b49fe33-7c93-41ae-9dc7-8ac4d823286a"
Public Const InterfaceId As String = "11651e1f-6db0-4c9e-b644-dcb79e6de2f6"
Public Const EventsId As String = "7e61f977-b39d-47a6-8f34-f743c65ae3a3"
#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, 66)
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, 92)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(75, 23)
Me.Button1.TabIndex = 3
Me.Button1.Text = "Command"
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(132, 146)
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
Compilation du code
- Compilez les types COMForm, Form1 et FormManager dans un assembly appelé COMWinform.dll. Enregistrez l'assembly pour COM Interop en utilisant l'une des méthodes décrites dans Empaquetage d'un assembly pour COM. Vous pouvez maintenant utiliser l'assembly et son fichier bibliothèque de types (.tlb) correspondant dans des applications non managées. Par exemple, vous pouvez utiliser la bibliothèque de types en tant que référence dans un projet exécutable Visual Basic 6.0.
Voir aussi
Tâches
Comment : prendre en charge COM Interop en affichant un Windows Form avec la méthode ShowDialog
Concepts
Exposition de composants .NET Framework à COM
Empaquetage d'un assembly pour COM
Inscription d'assemblys dans COM
Vue d'ensemble des applications Windows Forms et non managées