Прежде чем начать, я хотел бы сказать, что согласен с Марком. COM Interop сделает вашу жизнь намного проще и не потребует от вас работы.
SendMessage - предпочтительный способ вызова одной или другой с помощью обработчиков Windows Message. PostMessage сложно использовать со сложными типами, так как время жизни данных, связанных с сообщением Windows в .NET и VB6, сложно управлять, пока сообщение поставлено в очередь, а завершение сообщения неизвестно, если вы не реализуете какую-либо форму механизма обратного вызова ,
Как бы то ни было, отправка сообщений Windows из любого места в окно C# требует, чтобы вы знали HWND окна C#, которое должно получать сообщение. Ваш фрагмент выглядит корректно как обработчик, за исключением того, что оператор 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# аналогично. Чтобы получить HWND окна в VB6, используйте свойство .hWnd окна в VB6, которое должно получить сообщение.
Как представляется, вы используете свой собственный набор идентификаторов сообщений, есть дополнительные шаги для обработки пользовательских идентификаторов сообщений в VB6. Большинство людей обрабатывают это путем подклассирования окна формы и использования процедуры подкласса для фильтрации этих сообщений. Я включил пример кода для демонстрации C# на VB6, поскольку обработка пользовательских сообщений сложнее в VB6.
Вот исходный код для пары тестовых программ, библиотеки C# и проекта VB6 Forms. Библиотека C# должна быть настроена с помощью «Регистрация для COM-взаимодействия» и «Сделать сборку COM-видимой» в настройках проекта.
Во-первых, библиотека C#. Эта библиотека содержит один COM-компонент, который будет виден для VB6 как тип CSMessageLibrary.TestSenderSimple. Обратите внимание, что вам нужно включить подпись P/Invoke (например, метод VB6) для 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, вам нужно будет добавить поддержку подкласса окна. Помимо лучших решений, которые можно применять для каждого окна, мы просто перейдем к чему-то, что показывает, как настроить одно окно.
Прежде всего, чтобы запустить этот образец, убедитесь, что вы создали приложение C# и правильно зарегистрировали его с помощью COM. Затем добавьте ссылку из VB6 в файл .tlb, который находится рядом с выходом C#. Вы найдете это в каталоге bin/Debug или bin/Release в проекте C#.
Следующий код следует поместить в модуль. В моем тестовом проекте я использовал модуль под названием «Module1». В этом модуле должны быть указаны следующие определения.
WM_APP - Используется как пользовательский идентификатор сообщения, который будет без помех.
GWL_WNDPROC - Константа, которая используется для SetWindowLong, чтобы запросить модификацию обработчика окна.
SetWindowLong - функция Win32, которая может изменять специальные атрибуты в окнах.
CallWindowProc - функция Win32, которая может передавать сообщения Windows в назначенный обработчик окна (функция).
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# в качестве члена формы. Форма включает кнопку с идентификатором «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. Существует более «объективный» способ сделать подкласс VB6, хотя http://visualstudiomagazine.com/articles/2009/07/16/subclassing-the-xp-way.aspx – MarkJ
Я пошел с этим методом, чтобы сохранить образец короче. Тем не менее, техника на этой линии определенно выше. – meklarian
Отличная статья! +1 – used2could