c# - usados - formulas de visual basic
¿Cómo envío/recibo mensajes de Windows entre VB6 y c#? (3)
Antes de comenzar, me gustaría decir que estoy de acuerdo con MarkJ. COM Interop hará su vida mucho más fácil y no le exigirá que haga tanto trabajo.
SendMessage es la forma preferida de llamar a un lado u otro a través de los manejadores de mensajes de Windows. PostMessage es difícil de usar con tipos complejos, ya que la vida de los datos asociados con un mensaje de Windows en .NET y VB6 es difícil de administrar mientras el mensaje está en cola, y la finalización del mensaje es desconocida a menos que implemente alguna forma de mecanismo de devolución de llamada .
De todos modos, enviar mensajes de Windows desde cualquier lugar a una ventana de C # simplemente requiere que conozca el HWND de la ventana de C # que recibirá el mensaje. Su fragmento parece correcto como manejador, excepto que la declaración de cambio debe verificar primero contra el parámetro Msg .
protected override void WndProc(ref Message m)
{
int _iWParam = (int)m.WParam;
int _iLParam = (int)m.LParam;
switch ((ECGCardioCard.APIMessage)m.Msg)
{
// handling code goes here
}
base.WndProc(ref m);
}
La recuperación de un identificador de ventana desde un formulario, ventana o control C # se puede realizar a través de la propiedad .Handle.
Propiedad Control.Handle @ MSDN
Asumiremos aquí que tiene alguna forma de transferir el controlador de ventana de C # a VB6.
Desde VB6, la firma de la ventana SendMessage es la siguiente:
Private Declare Function SendMessage Lib "USER32.DLL" _
(ByVal hWnd As Long, ByVal uMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Para llamarlo, harías algo como lo siguiente. Para abreviar, uMsg es WM_APP (32768), wParam / lParam son 0:
Dim retval As Long
retval = SendMessage(hWnd, 32768, 0, 0)
Del mismo modo, enviar un mensaje desde C # es similar. Para obtener el HWND de una ventana en VB6, use la propiedad .hWnd de la ventana en VB6 que debería recibir el mensaje.
Como parece que está utilizando su propio conjunto de identificadores de mensaje, hay pasos adicionales para manejar los identificadores de mensajes personalizados en VB6. La mayoría de las personas manejan esto subclasificando una ventana de formulario y usando el procedimiento de la subclase para filtrar esos mensajes. He incluido código de muestra para demostrar C # a VB6, ya que manejar mensajes personalizados es más complicado en VB6.
Aquí está el código fuente para el par de programas de prueba, una biblioteca C # y un proyecto de formularios VB6. La biblioteca C # debe configurarse con ''Registrar para Interoperabilidad COM'' y ''Hacer ensamblado COM-Visible'' en la configuración del Proyecto.
Primero, la biblioteca C #. Esta biblioteca contiene un único componente COM que será visible para VB6 como el tipo ''CSMessageLibrary.TestSenderSimple''. Tenga en cuenta que debe incluir una firma P / Invoke (como el método VB6) para SendMessage.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace CSMessageLibrary
{
[ComVisible(true)]
public interface ITestSenderSimple
{
// NOTE: Can''t use IntPtr because it isn''t VB6-compatible
int hostwindow { get; set;}
void DoTest(int number);
}
[ComVisible(true)]
public class TestSenderSimple : ITestSenderSimple
{
public TestSenderSimple()
{
m_HostWindow = IntPtr.Zero;
m_count = 0;
}
IntPtr m_HostWindow;
int m_count;
#region ITestSenderSimple Members
public int hostwindow
{
get { return (int)m_HostWindow; }
set { m_HostWindow = (IntPtr)value; }
}
public void DoTest(int number)
{
m_count++;
// WM_APP is 0x8000 (32768 decimal)
IntPtr retval = SendMessage(
m_HostWindow, 0x8000, (IntPtr)m_count, (IntPtr)number);
}
#endregion
[DllImport("user32.dll", CharSet = CharSet.Auto)]
extern public static IntPtr SendMessage(
IntPtr hwnd, uint msg, IntPtr wparam, IntPtr lparam);
}
}
Ahora, en el lado de VB6, deberá agregar soporte para subclase de una ventana. Además de mejores soluciones que se pueden aplicar por ventana, vamos a ir con algo que muestra cómo configurar una sola ventana.
Primero, para ejecutar esta muestra, asegúrese de haber creado la aplicación C # y haberla registrado correctamente con COM. A continuación, agregue una referencia de VB6 al archivo .tlb que se encuentra junto a la salida C #. Lo encontrará en el directorio bin / Debug o bin / Release en el proyecto C #.
El siguiente código debe colocarse en un Módulo. En mi proyecto de prueba usé un módulo llamado ''Module1''. Las siguientes definiciones deben anotarse en este Módulo.
WM_APP: se utiliza como un identificador de mensaje personalizado que no tendrá interferencias.
GWL_WNDPROC: constante que se utiliza para SetWindowLong para solicitar modificaciones al manejador de ventana.
SetWindowLong - Función Win32 que puede modificar atributos especiales en Windows.
CallWindowProc - Función Win32 que puede retransmitir mensajes de Windows a un manejador de ventana designado (función).
SubclassWindow - Función de módulo para configurar subclases para una ventana designada.
UnsubclassWindow - Función de módulo para eliminar subclases para una ventana designada.
SubWndProc - Función de módulo que se insertará a través de subclases, para permitirnos interceptar mensajes personalizados de Windows.
Public Const WM_APP As Long = 32768
Private Const GWL_WNDPROC = (-4)
Private procOld As Long
Private Declare Function CallWindowProc Lib "USER32.DLL" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal uMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetWindowLong Lib "USER32.DLL" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Sub SubclassWindow(ByVal hWnd As Long)
procOld = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf SubWndProc)
End Sub
Public Sub UnsubclassWindow(ByVal hWnd As Long)
procOld = SetWindowLong(hWnd, GWL_WNDPROC, procOld)
End Sub
Private Function SubWndProc( _
ByVal hWnd As Long, _
ByVal iMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
If hWnd = Form1.hWnd Then
If iMsg = WM_APP Then
Dim strInfo As String
strInfo = "wParam: " & CStr(wParam) & vbCrLf & "lParam: " & CStr(lParam)
Call MsgBox(strInfo, vbOKOnly, "WM_APP Received!")
SubWndProc = True
Exit Function
End If
End If
SubWndProc = CallWindowProc(procOld, hWnd, iMsg, wParam, lParam)
End Function
En el formulario de prueba, conecté una instancia del objeto C # de prueba como miembro del formulario. El formulario incluye un botón cuyo id es ''Command1''. La subclase se configura cuando se carga el formulario, y luego se elimina cuando se cierra el formulario.
Dim CSharpClient As New CSMessageLibrary.TestSenderSimple
Private Sub Command1_Click()
CSharpClient.DoTest (42)
End Sub
Private Sub Form_Load()
CSharpClient.hostwindow = Form1.hWnd
Module1.SubclassWindow (Form1.hWnd)
End Sub
Private Sub Form_Unload(Cancel As Integer)
CSharpClient.hostwindow = 0
Module1.UnsubclassWindow (Form1.hWnd)
End Sub
El envío de argumentos numéricos que caben en 4 bytes es trivial, ya sea como wParam o lParam. Sin embargo, enviar tipos complejos y cadenas es mucho más difícil. Veo que ha creado una pregunta separada para eso, por lo que daré respuestas a eso allí.
REF: ¿Cómo envío una estructura de C # a VB6, y de VB6 a C #?
Sé que puedo recibir mensajes con el siguiente código en c #, ¿cómo puedo enviarlos a vb6, recibirlos en vb6 y enviarlos desde vb6?
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
int _iWParam = (int)m.WParam;
int _iLParam = (int)m.LParam;
switch ((ECGCardioCard.APIMessage)m.WParam)
{
// handling code goes here
}
base.WndProc(ref m);
}
Para enviar VB6, necesita usar una llamada API ( SendMessage o PostMessage). Para recibir en VB6 necesita usar subclases (complicado: esta es la mejor manera que conozco ).
¿Ha considerado usar COM Interop en su lugar? Es una forma mucho más fácil de comunicarse entre VB6 y C # que los mensajes de Windows.
Use la función API PostMessage de Windows.
Al comienzo de tu clase:
[DllImport("User32.dll", EntryPoint="PostMessage")]
private static extern int PostMessage(int hWnd, int Msg, int wParam, int lParam);
const int WM_USER = 0x0400;
const int CM_MARK = WM_USER + 1;
Luego maneje el mensaje anulando el WndProc de la clase.
protected override void WndProc(ref Message m)
{
if (m.Msg == CM_MARK) {
if (this.ActiveControl is TextBox) {
((TextBox)this.ActiveControl).SelectAll();
}
}
base.WndProc(ref m);
} // end sub.
Luego en tu evento Enter:
private void txtMedia_Enter(object sender, EventArgs e)
{
PostMessage(Handle.ToInt32(), CM_MARK, 0, 0);
} // end sub.
Esto funciona porque obliga a que su procesamiento personalizado se produzca después de que Windows realiza su procesamiento predeterminado del evento Enter y se asocia con el manejo del mouse. Pones tu solicitud en la cola de mensajes y se maneja sucesivamente en el evento WndProc. Cuando se llama a su evento, se asegura de que la ventana actual sea un cuadro de texto y lo selecciona si es así.