簡體   English   中英

如何在VB6和c#之間發送/接收Windows消息?

[英]How do I send/receive windows messages between VB6 and c#?

我知道我可以使用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);
    }

在開始之前,我想說我同意MarkJ。 COM Interop將使您的生活更輕松,不需要您做太多的工作。

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)
    {
            // handling code goes here
    }
    base.WndProc(ref m);
}

從C#Form,Window或Control檢索窗口句柄可以通過.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#庫配置'Register for COM Interop'和'Make Assembly COM-Visible'。

首先是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中的引用添加到C#輸出旁邊的.tlb文件中。 您可以在C#項目下的bin / Debug或bin / Release目錄中找到它。

以下代碼應放入模塊中。 在我的測試項目中,我使用了一個名為“Module1”的模塊。 本模塊中應注明以下定義。

WM_APP - 用作無干擾的自定義消息標識符。
GWL_WNDPROC - 用於請求修改窗口處理程序的SetWindowLong的常量。
SetWindowLong - Win32函數,可以修改Windows上的特殊屬性。
CallWindowProc - Win32函數,可以將Windows消息中繼到指定的窗口處理程序(函數)。
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#?

要發送VB6,您需要使用API​​調用( SendMessage或PostMessage)。 要在VB6中接收,您需要使用子類化(復雜 - 這是我所知道最佳方式 )。

您是否考慮過使用COM Interop 在VB6和C#之間進行通信比在Windows消息中更容易。

使用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.

然后在您的Enter事件中:

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

這是有效的,因為在Windows執行Enter事件的默認處理及其相關的鼠標處理之后,您強制進行自定義處理。 您將請求放在消息隊列中,然后在WndProc事件中依次處理它。 調用事件時,確保當前窗口是文本框,如果是,則選擇它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM