Как решить проблему с тем, что приложение Receiver получает пустое сообщение через WM_COPYDATA? - PullRequest
0 голосов
/ 08 января 2019

Я пишу приложение на C ++, которое отправит сообщение приложению, написанному на Delphi.

Это приложение для моего приемника:

image

При нажатии кнопки Edit1.Text будет отправлено через ShellExecute() в качестве параметра командной строки приложению-отправителю (C ++).

Приложение отправителя отправит параметр в виде сообщения WM_COPYDATA приложению получателя, которое отобразит его в текстовом поле Edit2.

Это код приложения Delphi (Delphi 10.3 Rio):

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(0, 'open', 'deneme.exe', PWideChar(Edit1.Text), nil, SW_HIDE);
end;

procedure TForm1.MesajAl(var Mesaj: TMessage);
var
  Veri: PCopyDataStruct;
begin
  Veri := Pointer(Mesaj.LParam);
  Edit2.Text := PChar(Veri^.lpData);
end;

Это код моего приложения C ++ (Code :: Blocks IDE):

#include <iostream>
#include <windows.h>
#include <tchar.h>
using namespace std;

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        return 0;
    }
    else
    {
        HWND hwnd = FindWindow(NULL, "Form1");

        string alinanMesaj;

        LPCTSTR gonderilecekMesaj = alinanMesaj.c_str();

        COPYDATASTRUCT cds;
        cds.cbData = sizeof(TCHAR)*(_tcslen(gonderilecekMesaj) + 1);
        cds.dwData = 1;
        cds.lpData = (PVOID)gonderilecekMesaj;

        SendMessage(hwnd, WM_COPYDATA, (WPARAM)hwnd, (LPARAM)(LPVOID)&cds);

        return 0;
    }
}

Проблема в том, что текстовое поле Edit2 ничего не показывает.

Кстати, я провел исследование на этом сайте о WM_COPYDATA. Но, несмотря на то, что в этой ситуации я не смог решить свою проблему самостоятельно.

Итак, что мне делать, чтобы исправить мою проблему?

1 Ответ

0 голосов
/ 08 января 2019

Я вижу три проблемы с этим кодом:

  • Отправитель отправляет пустые данные, поскольку alinanMesaj не назначено никакое значение.

  • Существует несоответствие ANSI / UNICODE между двумя приложениями. Код Delphi работает со строками Unicode, а код C ++ вместо этого работает со строками ANSI. WM_COPYDATA работает с байтами, а не с символами. Вы должны выбрать байтовую кодировку для ваших строковых данных и соответствовать ей с обеих сторон.

  • VCL использует WM_COPYDATA для внутреннего использования, поэтому отправителю необходимо установить для поля cds.dwData уникальное значение, например, от RegisterWindowMessage(), которое получатель должен проверить, прежде чем интерпретировать данные cds.lpData .

С помощью at, попробуйте это вместо:

var
  MY_CDS_ID: UINT;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MY_CDS_ID := RegisterWindowMessage('MYCDSID'); // use whatever unique name you want
  if MY_CDS_ID = 0 then
    RaiseLastOSError;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // you really should be using CreateProcess() instead...
  ShellExecute(0, nil, 'deneme.exe', PChar(AnsiQuotedStr(Edit1.Text, '"')), nil, SW_HIDE);
end;

procedure TForm1.MesajAl(var Mesaj: TMessage);
var
  Veri: PCopyDataStruct;
  s: UnicodeString;
begin
  Veri := Pointer(Mesaj.LParam);
  if Veri^.dwData = MY_CDS_ID then
  begin
    SetString(s, PWideChar(Veri^.lpData), Veri^.cbData div SizeOf(WideChar));
    Edit2.Text := s;
  end else
    inherited;
end;
#include <iostream>
#include <windows.h>
#include <string>

int main(int argc, char* argv[])
{
    if (argc < 2)
        return 0;

    HWND hwnd = FindWindow("TForm1", "Form1");
    if (!hwnd)
        return 0;

    UINT MY_CDS_ID = RegisterWindowMessage("MYCDSID"); // must match the named used by the Delphi code
    if (!MY_CDS_ID)
        return 0;

    std::wstring alinanMesaj;

    int arglen = lstrlenA(argv[1]);
    int wlen = MultiByteToWideChar(CP_ACP, 0, argv[1], arglen, NULL, 0);
    if (wlen > 0)
    {
        alinanMesaj.resize(wlen);
        MultiByteToWideChar(CP_ACP, 0, argv[1], arglen, &alinanMesaj[0], wlen);
    }

    COPYDATASTRUCT cds;
    cds.cbData = sizeof(wchar_t) * alinanMesaj.size();
    cds.dwData = MY_CDS_ID;
    cds.lpData = const_cast<wchar_t*>(alinanMesaj.c_str());

    SendMessage(hwnd, WM_COPYDATA, reinterpret_cast<WPARAM>(hwnd), reinterpret_cast<LPARAM>(&cds));

    return 0;
}
...