如何发送VB6和C#之间/接收窗口消息?(How do I send/receive windows

2019-09-02 07:57发布

我知道我可以在C#中的代码接收到下面的消息,我怎么送VB6,并在VB6接收,并从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);
    }

Answer 1:

我开始之前,我想说,我同意MarkJ。 COM互操作会让你的生活变得更轻松,也不会要求你做尽可能多的工作。

SendMessage消息是调用一个一侧或另一侧通过Windows消息处理程序的首选方式。 PostMessage的是艰难与复杂类型使用,与Windows消息在相关的数据的生命周期.NET和VB6是难以管理,而该消息在排队,除非你实现了某种形式的回调机制的消息完成未知。

总之,从任何地方到一个C#窗口发送消息窗口只要求你知道这是接收消息的C#窗口的HWND。 您的片段看起来是正确的,因为一个处理程序,除了switch语句应该检查对消息参数第一。

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

从C#形式检索窗口句柄,窗口或控制可以通过.Handle属性来完成。

Control.Handle物业@ 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窗体项目的源代码。 C#的图书馆应以“注册为COM互操作”,并配置“让大会COM可见”在项目设置。

首先,C#库。 这个库包含了一个COM组件,这将是可见的VB6作为类型“CSMessageLibrary.TestSenderSimple”。 请注意,您需要包括一个SendMessage函数的P / Invoke签名(如VB6方法)。

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的一面,你将需要添加支持的子类的窗口。 除了更好的解决方案,可以为每个窗口的应用,我们还是要的东西,展示了如何建立一个窗口。

首先,运行此示例,请确保您已经建立了C#应用程序,并正确地与COM注册它。 然后从VB6添加引用.tlb文件是沿着C#输出。 您将在C#项目下的bin / Debug或Bin / Release目录中找到它。

下面的代码应放置成模块。 在我的测试项目中,我使用了一种叫做“模块1”模块。 以下定义应在此模块中注明。

WM_APP - 用作一个自定义的消息标识符,这将是无干扰的。
GWL_WNDPROC - 常量,其用于SetWindowLong函数来请求修改的窗口处理。
SetWindowLong函数 - Win32函数可在Windows修改的特殊属性。
CallWindowProc的 - 即可以中继窗口信息发送到指定的窗口句柄(函数)Win32函数。
调用SubclassWindow - 模块功能设置为子类指定的窗口。
UnsubclassWindow - 模块功能推倒继承了指定的窗口。
SubWndProc - 将通过子类插入模块功能,让我们截取自定义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

在测试形式,我已经有线了测试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#?



Answer 2:

要在VB6送你需要使用一个API调用( SendMessage函数或PostMessage的)。 为了接收VB6,你需要使用子类(复杂-这里是我知道的最好的方式 )。

你有没有考虑使用COM互操作呢? 这是一个容易得多VB6和C#比Windows消息之间的沟通方式。



Answer 3:

使用PostMessage的Windows API函数。

在类的开头:

[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;

然后通过覆盖类的WndProc处理消息。

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.

然后在您输入的事件:

private void txtMedia_Enter(object sender, EventArgs e)
{
  PostMessage(Handle.ToInt32(), CM_MARK, 0, 0);
} // end sub.

这工作,因为你强迫你的自定义处理Windows不会Enter事件的它的默认处理后,会出现与它相关的鼠标操作。 你把消息队列您的请求,并依次进行处理,在WndProc中的事件。 当您的活动被调用时,你要确保当前窗口是一个文本框,然后选择它,如果它是。



文章来源: How do I send/receive windows messages between VB6 and c#?
标签: c# vb6 wndproc