在我开始之前,我想说我同意MarkJ的观点。COM互操作将使您的生活更加轻松,并且不需要您做太多工作。
使用SendMessage是通过Windows消息处理程序调用一侧或另一侧的首选方法。对于复杂类型,PostMessage很难使用,因为在.NET和VB6中与Windows消息相关联的数据的生命周期在消息排队时很难管理,并且除非您实现某种形式的回调机制,否则无法完成消息。
无论如何,从任何地方向C#窗口发送Windows消息只需要知道接收消息的C#窗口的HWND。您的片段作为处理程序看起来是正确的,只是switch语句应该首先检查Msg参数。
protected override void WndProc(ref Message m)
{
int _iWParam = (int)m.WParam;
int _iLParam = (int)m.LParam;
switch ((ECGCardioCard.APIMessage)m.Msg)
{
}
base.WndProc(ref m);
}
从 C# 窗体、窗口或控件中获取窗口句柄可以通过 .Handle 属性完成。
Control.Handle Property @ MSDN
我们假设您已经有了一种将窗口句柄从 C# 传输到 VB6 的方法。
从 VB6 中,SendMessage 窗口的签名如下:
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
要调用它,您需要执行类似以下的操作。为了简洁起见,uMsg是WM_APP(32768),wParam / lParam均为0:
Dim retval As Long
retval = SendMessage(hWnd, 32768, 0, 0)
同样地,从C#发送消息也是相似的。在VB6中获取窗口的HWND,请使用应该接收消息的VB6窗口的.hWnd属性。
由于您正在使用自己的一组消息标识符,因此在VB6中处理自定义消息标识符需要额外的步骤。大多数人通过子类化表单窗口来处理此问题,并使用子类过程来过滤这些消息。我已经包含了示例代码,以演示C#到VB6的转换,因为在VB6中处理自定义消息更加棘手。
这是测试程序对的源代码,一个C#库和一个VB6 Forms项目。C#库应该在项目设置中配置为“注册为COM互操作”和“使程序集COM可见”。
首先是C#库。该库包含一个单独的COM组件,将作为类型“CSMessageLibrary.TestSenderSimple”对VB6可见。请注意,您需要为SendMessage包括一个P/Invoke签名(就像VB6方法)。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace CSMessageLibrary
{
[ComVisible(true)]
public interface ITestSenderSimple
{
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++;
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);
}
}
现在,在VB6端,您需要添加支持子类化窗口的功能。除了可以针对每个窗口应用更好的解决方案之外,我们将仅使用一些演示如何设置单个窗口的内容。
首先,要运行此示例,请确保您已构建了C#应用程序并正确地将其注册到COM中。然后,从VB6添加对与C#输出相邻的.tlb文件的引用。您会在C#项目的bin / Debug或bin / Release目录下找到这个文件。
以下代码应该放置在一个模块中。在我的测试项目中,我使用了一个名为“Module1”的模块。此模块中应注意以下定义。
WM_APP - 用作自定义消息标识符,不会受到干扰。
GWL_WNDPROC - SetWindowLong所用的常量,用于请求修改窗口处理程序。
SetWindowLong - Win32函数,可修改窗口上的特殊属性。
CallWindowProc - Win32函数,可将窗口消息转发到指定的窗口处理程序(函数)。
SubclassWindow - 模块函数,用于为指定的窗口设置子类化。
UnsubclassWindow - 模块函数,用于拆除指定窗口的子类化。
SubWndProc - 模块函数,将通过子类化插入,以允许我们拦截自定义窗口消息。
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
在测试表单中,我已经将测试C#对象实例作为表单的成员进行了连接。该表单包括一个id为'Command1'的按钮。子类在表单加载时设置,然后在表单关闭时移除。
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
发送适合4字节的数字参数很简单,可以作为wParam或lParam。然而,发送复杂类型和字符串则更加困难。我看到您已经为此创建了一个单独的问题,所以我会在那里提供答案。
REF: 如何将结构体从C#发送到VB6,并从VB6发送到C#?
this
一样)。 - meklarian