Как мне отправлять / получать сообщения Windows между VB6 и c #?

StackOverflow https://stackoverflow.com/questions/1645204

  •  10-07-2019
  •  | 
  •  

Вопрос

Я знаю, что могу получать сообщения с приведенным ниже кодом на 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);
    }
Это было полезно?

Решение

Прежде чем я начну, я хотел бы сказать, что я согласен с Марком Джеем.COM-взаимодействие значительно облегчит вашу жизнь и не потребует от вас выполнения такого большого объема работы.

SendMessage - это предпочтительный способ вызова той или иной стороны через обработчики сообщений Windows.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.

Элемент управления.Обрабатывать свойство @ 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 # должна быть настроена с помощью 'Register for COM Interop' и 'Make Assembly COM-Visible' в настройках проекта.

Во-первых, библиотека 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, вам нужно будет добавить поддержку для подкласса window.Помимо улучшенных решений, которые можно применять для каждого окна, мы просто рассмотрим кое-что, что показывает, как настроить одно окно.

Во-первых, чтобы запустить этот пример, убедитесь, что вы создали приложение на C # и правильно зарегистрировали его в COM.Затем добавьте ссылку из VB6 в файл .tlb, который находится рядом с выводом C #.Вы найдете это в каталоге bin /Debug или bin / Release в проекте C #.

Следующий код должен быть помещен в модуль.В моем тестовом проекте я использовал модуль под названием "Module1".В этом Модуле следует отметить следующие определения.

WM_APP - используется в качестве пользовательского идентификатора сообщения, который не будет создавать помех.
GWL_WNDPROC - константа, которая используется для SetWindowLong для запроса изменения обработчика окна.
SetWindowLong - функция Win32, которая может изменять специальные атрибуты в Windows.
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

В тестовой форме я подключил экземпляр объекта test 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 .Однако отправка сложных типов и строк намного сложнее.Я вижу, что вы создали для этого отдельный вопрос, поэтому я приведу ответы на него там.

ССЫЛКА:Как мне отправить структуру из C # в VB6, а из VB6 - в C #?

Другие советы

Для отправки в VB6 вам необходимо использовать вызов API ( SendMessage или PostMessage). Чтобы получить в VB6 вам нужно использовать подклассы (сложный - вот лучший способ, которым я знаю ).

Рассматривали ли вы возможность использования COM-взаимодействия вместо? Это намного более простой способ связи между 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 с атрибуция
Не связан с StackOverflow
scroll top