在我開始之前,我想說我贊同MarkJ。 COM Interop將讓你的生活變得更加輕鬆,並且不會要求你做很多工作。
SendMessage是通過Windows消息處理程序調用一方或另一方的首選方法。 PostMessage很難與複雜類型一起使用,因爲在消息排隊時,與.NET和VB6中的Windows消息相關聯的數據的生命週期難以管理,並且消息的完成未知,除非您實現某種形式的回調機制。
無論如何,從任何位置將窗口消息發送到C#窗口只需要知道接收消息的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#表單窗口句柄,窗口,或控制可通過.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中的自定義消息標識符。大多數人通過子窗體窗口來處理這個問題,並使用子類過程來過濾這些消息。因爲在VB6中處理自定義消息比較棘手,所以我已經包含了演示C#到VB6的示例代碼。
這是一對測試程序,C#庫和VB6 Forms項目的源代碼。 C#庫應該在項目設置中配置'Register for COM Interop'和'Make Assembly COM-Visible'。
首先是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
{
// 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函數,可以修改窗口上的特殊屬性。
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: How do I send a struct from C# to VB6, and from VB6 to C#?
+1。通過http://visualstudiomagazine.com/articles/2009/07/16/subclassing-the-xp-way進行VB6子類化有一個更「對象」的方法。aspx – MarkJ
我採用這種方法只是爲了縮短樣本。儘管如此,該環節的技術絕對優越。 – meklarian
真是太棒了! +1 – used2could