Как отправить пользовательское сообщение из приложения C ++ MF C в приложение WPF C#? - PullRequest
0 голосов
/ 11 июля 2020

Мне нужно отправить настраиваемое сообщение / уведомление из MF C (C ++) в приложение WPF (C#). Есть несколько тем по поводу rnet отправки сообщений из C# в приложение C ++. Я попытался реализовать свой случай, за которым следуют эти статьи, но не могу получить сообщение от WPF.

Все, что я пробовал, приведено ниже:

Из приложения MF C У меня есть пытался отправить сообщение как с помощью PostMessage, так и с помощью SendMessage, но ничего из этого не может быть получено из приложения WPF.

UINT deviceConnected = 0;
deviceConnected = RegisterWindowMessage(L"DEVICE_CONNECTED");
HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), L"DEVICE_CONNECTED_HWND");

const char* message = "This is a custom message";
::PostMessage(dstWnd, deviceConnected, 0, (LPARAM)(LPCTSTR)message);
::SendMessage(dstWnd, deviceConnected, 0, (LPARAM)(LPCTSTR)message);

Я также пробовал с WM_COPYDATA:

LPCTSTR lpszString = (LPCTSTR)L"This is second message";
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.cbData = sizeof(TCHAR) * (_tcslen(lpszString) + 1);
cds.lpData = (PVOID)lpszString;
::PostMessage(dstWnd, WM_COPYDATA, 0, (LPARAM)(LPVOID)&cds); 
::SendMessage(dstWnd, WM_COPYDATA, 0, (LPARAM)(LPVOID)&cds);

Вот пример кода WPF:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
private UInt32 deviceAttachedEvent = 0;
const int WM_COPYDATA = 0x4A;
    
protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    HwndSource hwndSource = HwndSource.FromVisual(this) as HwndSource;
    if (hwndSource != null)
    {
        hwndSource.AddHook(new HwndSourceHook(WndProc));
    }
}

private IntPtr WndProc(IntPtr hwnd, int msgId, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    IntPtr result = IntPtr.Zero;

    //if the deviceAttachedEvent message id has not been registered...
    if (deviceAttachedEvent == 0)
        deviceAttachedEvent  = RegisterWindowMessage("DEVICE_CONNECTED");

    if ((UInt32)msgId == deviceAttachedEvent )
    {
        //string msg = Marshal.PtrToStringAuto(lParam);
        Console.WriteLine("Received message from MFC");
        //Console.WriteLine(msg);
    }

    if (msgId == WM_COPYDATA)
    {
        COPYDATASTRUCT cds = new COPYDATASTRUCT();
        cds = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam,typeof(COPYDATASTRUCT));
        if (cds.cbData > 0)
        {
            byte[] data = new byte[cds.cbData];
            Marshal.Copy(cds.lpData, data, 0, cds.cbData);
            Encoding unicodeStr = Encoding.ASCII;
            char[] myString = unicodeStr.GetChars(data);
            string returnText = new string(myString);
            MessageBox.Show("ACK Received: " + returnText);
        }
    }
    
    return result;
}

Заранее спасибо.

1 Ответ

0 голосов
/ 13 июля 2020

Я могу использовать код, чтобы получить сообщение, отправленное проектом C ++ (как deviceAttachedEvent, так и WM_COPYDATA). Я использовал FindWindow(NULL,L"WPFwindow name") для получения дескриптора hwnd вместо GetProp, поэтому убедитесь, что у вас правильный дескриптор окна. Вы можете использовать EnumPropsEx, чтобы проверить, есть ли у вас свойство "DEVICE_CONNECTED_HWND"

Для WindowMessage deviceConnected: вы отправляете указатель в текущем процессе, обычно это делает другой процесс. у вас нет разрешения на прямой доступ к этому адресу. Вам нужно использовать ReadProcessMemory для чтения строковых данных по этому адресу.

Кроме того, обратите внимание на набор символов проекта. L"***" не нужно приводить к LPCTSTR, если набор символов - UNICODE, и использовать "***", если набор символов - многобайтовый набор символов. Или используйте макрос TEXT("").

Кроме того, вы отправили строку широких байтов L"This is second message", а затем установили Encoding.ASCII при чтении, это приведет к усечению строки, например:

введите описание изображения здесь

Итак, мой пример: C ++:

#include <windows.h>
#include <iostream>
#include <tchar.h>
int main()
{
    UINT deviceConnected = 0;
    deviceConnected = RegisterWindowMessage(L"DEVICE_CONNECTED");
    HWND dstWnd = FindWindow(NULL,L"MainWindow");

    const wchar_t* message = TEXT("This is a custom message");
    ::SendMessage(dstWnd, deviceConnected, 0, (LPARAM)(LPCTSTR)message);

    LPCTSTR lpszString = TEXT("This is second message");
    COPYDATASTRUCT cds;
    cds.dwData = 0;
    cds.cbData = sizeof(TCHAR) * (_tcslen(lpszString) + 1);
    cds.lpData = (PVOID)lpszString;

    ::SendMessage(dstWnd, WM_COPYDATA, 0, (LPARAM)(LPVOID)&cds);

}

в wpf:

   private IntPtr WndProc(IntPtr hwnd, int msgId, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        IntPtr result = IntPtr.Zero;

        //if the deviceAttachedEvent message id has not been registered...
        if (deviceAttachedEvent == 0)
            deviceAttachedEvent = RegisterWindowMessage("DEVICE_CONNECTED");

        if ((UInt32)msgId == deviceAttachedEvent)
        {
            //OpenProcess + PROCESS_VM_READ
            //ReadProcessMemory + lParam
            Console.WriteLine("Received message from MFC");
        }

        if (msgId == WM_COPYDATA)
        {
            COPYDATASTRUCT cds = new COPYDATASTRUCT();
            cds = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
            if (cds.cbData > 0)
            {
                byte[] data = new byte[cds.cbData];
                Marshal.Copy(cds.lpData, data, 0, cds.cbData);
                Encoding unicodeStr = Encoding.Unicode;
                char[] myString = unicodeStr.GetChars(data);
                string returnText = new string(myString);
                MessageBox.Show("ACK Received: " + returnText);
            }
        }

        return result;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...