如何在 VB6 和 c# 之间发送/接收 windows 消息? [英] How do I send/receive windows messages between VB6 and c#?

查看:15
本文介绍了如何在 VB6 和 c# 之间发送/接收 windows 消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道我可以在c#中使用下面的代码接收消息,我如何发送到vb6,在vb6中接收,从vb6发送?

I know I can receive messages with the code below in c#, how do I send to vb6, and receive in vb6, and send from 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);
    }

推荐答案

在开始之前,我想说我同意 MarkJ.COM Interop 将使您的生活更轻松,并且不需要您做太多的工作.

Before I start, I'd like to say that I concur with MarkJ. COM Interop will make your life much easier and will not require you to do as much work.

SendMessage 是通过 Windows 消息处理程序调用一侧或另一侧的首选方式.PostMessage 很难用于复杂类型,因为在 .NET 和 VB6 中与 Windows 消息关联的数据的生命周期在消息排队时很难管理,并且除非您实现某种形式的回调机制,否则消息的完成是未知的.

SendMessage is the preferred way to call one side or the other via Windows Message handlers. PostMessage is tough to use with complex types, as the lifetime of data associated with a windows message in both .NET and VB6 is difficult to manage while the message is queued, and completion of the message is unknown unless you implement some form of callback mechanism.

无论如何,从任何地方向 C# 窗口发送 windows 消息只需要您知道要接收消息的 C# 窗口的 HWND.您的代码段作为处理程序看起来是正确的,除了 switch 语句应首先检查 Msg 参数.

Anyhow, sending windows messages from anywhere to a C# window merely requires that you know the HWND of the C# window that is to receive the message. Your snippet looks to be correct as a handler, except that the switch statement should check against the Msg parameter first.

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);
}

可以通过 .Handle 属性从 C# 窗体、窗口或控件中检索窗口句柄.

Retrieving a window handle from a C# Form, Window, or Control can be done via the .Handle property.

Control.Handle 属性@MSDN

我们在这里假设您有某种方法可以将窗口句柄从 C# 传输到 VB6.

We'll assume here that you have some way of transferring the window handle from C# to VB6.

从 VB6 开始,SendMessage 窗口的签名如下:

From VB6, the signature of the SendMessage window is the following:

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:

To call it, you would do something like the following. For brevity, uMsg is WM_APP (32768), wParam/lParam are 0:

Dim retval As Long
retval = SendMessage(hWnd, 32768, 0, 0)

同样,从 C# 发送消息也是类似的.要在 VB6 中获取窗口的 HWND,请使用 VB6 中应接收消息的窗口的 .hWnd 属性.

Likewise, sending a message from C# is similar. To get the HWND of a window in VB6, use the .hWnd property of the window in VB6 that should receive the message.

由于您似乎在使用自己的一组消息标识符,因此在 VB6 中处理自定义消息标识符有额外的步骤.大多数人通过子类化表单窗口并使用子类过程来过滤这些消息来处理这个问题.因为在 VB6 中处理自定义消息比较棘手,所以我已经包含了示例代码来演示 C# 到 VB6.

As it appears that you are using your own set of message identifiers, there are extra steps to handle custom message identifiers in VB6. Most people handle this by subclassing a form window, and using the subclass procedure to filter those message. I've included sample code to demonstrate C# to VB6 since handling custom messages is trickier in VB6.

这里是这对测试程序、一个 C# 库和一个 VB6 Forms 项目的源代码.C# 库应在项目设置中使用Register for COM Interop"和Make Assembly COM-Visible"进行配置.

Here is the source code for the pair of test programs, a C# library and a VB6 Forms Project. The C# library should be configured with 'Register for COM Interop' and 'Make Assembly COM-Visible' in the Project settings.

首先,C# 库.这个库包含一个单一的 COM 组件,它对 VB6 可见,类型为CSMessageLibrary.TestSenderSimple".请注意,您需要为 SendMessage 包含一个 P/Invoke 签名(如 VB6 方法).

First, the C# library. This library contains a single COM component that will be visible to VB6 as the type 'CSMessageLibrary.TestSenderSimple'. Note that you need to include a P/Invoke signature (like the VB6 method) for 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);
    }
}

现在,在 VB6 方面,您需要添加对子类窗口的支持.除了可以在每个窗口中应用的更好的解决方案之外,我们还将介绍如何设置单个窗口.

Now, on the VB6 side, you will need to add support to subclass a window. Aside from better solutions that can be applied per-window, we'll just go with something that shows how to setup a single window.

首先,要运行此示例,请确保您已构建 C# 应用程序并已将其正确注册到 COM.然后将 VB6 中的引用添加到 C# 输出旁边的 .tlb 文件.您可以在 C# 项目下的 bin/Debug 或 bin/Release 目录中找到它.

First, to run this sample, make sure you have built the C# application and properly registered it with COM. Then add a reference from VB6 to the .tlb file that is alongside the C# output. You'll find this in the bin/Debug or bin/Release directory under the C# project.

以下代码应放入模块中.在我的测试项目中,我使用了一个名为Module1"的模块.本模块中应注意以下定义.

The following code should be placed into a Module. In my test project I used a module called 'Module1'. The following definitions should be noted in this Module.

WM_APP - 用作不受干扰的自定义消息标识符.
GWL_WNDPROC - SetWindowLong 用于请求修改窗口处理程序的常量.
SetWindowLong - Win32 函数,可以修改窗口的特殊属性.
CallWindowProc - Win32 函数,可以将窗口消息中继到指定的窗口处理程序(函数).
SubclassWindow - 为指定窗口设置子类的模块函数.
UnsubclassWindow - 用于拆除指定窗口的子类化的模块函数.
SubWndProc - 将通过子类化插入的模块函数,以允许我们拦截自定义窗口消息.

WM_APP - Used as a custom message identifier that will be interference-free.
GWL_WNDPROC - Constant that is used for SetWindowLong to request modification to the window handler.
SetWindowLong - Win32 function that can modify special attributes on windows.
CallWindowProc - Win32 function that can relay windows messages to a designated window handler (function).
SubclassWindow - Module function to setup subclassing for a designated window.
UnsubclassWindow - Module function to tear down subclassing for a designated window.
SubWndProc - Module function that will be inserted via subclassing, to allow us to intercept custom windows messages.

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"的按钮.子类在表单加载时设置,然后在表单关闭时删除.

In the test form, I've wired up an instance of the test C# object as a member of the form. The form includes a button whose id is 'Command1'. The subclass is setup when the form loads, and then removed when the form is closed.

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.但是,发送复杂的类型和字符串要困难得多.我看到你为此创建了一个单独的问题,所以我会在那里提供答案.

Sending numeric arguments that fit in 4 bytes is trivial, either as the wParam or lParam. However, sending complex types and strings is much tougher. I see that you've created a separate question for that, so I will provide answers to that over there.

REF:如何将结构从 C# 发送到 VB6,从 VB6 发送到 C#?

这篇关于如何在 VB6 和 c# 之间发送/接收 windows 消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆