Cómo: Admitir la interoperabilidad COM al mostrar cada formulario Windows Forms en su propio subproceso
Puede resolver problemas de interoperabilidad COM mostrando el formulario en un bucle de mensajes de .NET Framework, que puede crear utilizando el método Application.Run.
Para que un formulario Windows Forms funcione correctamente desde una aplicación cliente COM, debe ejecutar el formulario en un bucle de mensajes de formularios Windows Forms. Para ello, utilice uno de los enfoques siguientes:
Utilice el método Form.ShowDialog para mostrar el formulario Windows Forms. Para obtener más información, vea Cómo: Admitir la interoperabilidad COM al mostrar un formulario Windows Forms con el método ShowDialog.
Muestre cada formulario Windows Forms en un subproceso independiente.
Visual Studio ofrece una amplia compatibilidad para esta característica.
Para obtener más información, vea Tutorial: Admitir la interoperabilidad COM al mostrar cada formulario Windows Forms en su propio subproceso y Tutorial: Admitir la interoperabilidad COM al mostrar cada formulario Windows Forms en su propio subproceso y Tutorial: Admitir la interoperabilidad COM al mostrar cada formulario Windows Forms en su propio subproceso y Tutorial: Admitir la interoperabilidad COM al mostrar cada formulario Windows Forms en su propio subproceso y Tutorial: Admitir la interoperabilidad COM al mostrar Windows Forms en su propio subproceso.
Ejemplo
En el ejemplo de código siguiente se muestra cómo visualizar el formulario en un subproceso independiente y llamar al método Application.Run para iniciar el suministro de mensajes de formularios Windows Forms en ese subproceso. Para utilizar este enfoque, debe calcular referencias de cualquier llamada al formulario desde la aplicación no administrada utilizando el método Invoke.
Este enfoque requiere que cada instancia de un formulario se ejecute en su propio subproceso utilizando su propio bucle de mensajes. No puede tener más de un bucle de mensajes en ejecución por subproceso. Por consiguiente, no puede cambiar el bucle de mensajes de la aplicación cliente. Sin embargo, puede modificar el componente .NET Framework para iniciar un nuevo subproceso que utiliza su propio bucle de mensajes.
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
Compilar el código
- Compile los tipos: COMForm, Form1 y FormManager a un ensamblado llamado COMWinform.dll. Registre el ensamblado para la interoperabilidad COM utilizando uno de los métodos descritos en Empaquetar un ensamblado para COM. Ahora puede utilizar el ensamblado y el archivo de biblioteca de tipos correspondiente (.tlb) en aplicaciones no administradas. Por ejemplo, puede utilizar la biblioteca de tipos como una referencia en un proyecto ejecutable de Visual Basic 6.0.
Vea también
Tareas
Conceptos
Exponer componentes de .NET Framework en COM
Empaquetar un ensamblado para COM
Información general sobre formularios Windows Forms y aplicaciones no administradas