SendMessage COPYDATASTRUCT неправильная строка при получении в delphi

Я отправляю следующий запрос приложения С++:

string data_to_send = "Hello World";
PCSTR lpszString = data_to_send.c_str();
COPYDATASTRUCT cds;
cds.dwData = 0; // can be anything
cds.cbData = sizeof(TCHAR) * (data_to_send.size());
cds.lpData = &lpszString;
cout << lpszString << endl;
SendMessage(Output, WM_COPYDATA, (WPARAM)Output, (LPARAM)(PVOID)&cds);

Я получаю структуру, используя следующий код в Delphi

var
  p : PCopyDataStruct;
  s : UTF8String;
begin
  p := PCopyDataStruct(Message.lParam);
  if (p <> nil) then
  begin
    SetString(s, PAnsiChar(p^.lpData), p^.cbData);
    ShowMessage(s);
  end else
    inherited;
end;

Строка выглядит неправильно. В отладчике он равен следующему

'l'#$FE#$F6#2'Hello World'#0#$10#3#$88'u'#$B#0

Мы видим 22 байта с дополнительными 4 байтами перед сообщением. Если мы используем CHAR вместо TCHAR, то видим 11 байт, но опять же со смещением в 4 байта

#$18#$F9#$1B#3'Hello W'

Пожалуйста помоги!!!

ОБНОВИТЬ:

Спасибо Реми Лебо за помощь, его код делает все так, как было задумано изначально и Дэвиду Хеффернану за правильное замечание! Они спасли меня. Вот рабочий код.

Похоже, вы смешиваете строки Unicode и ansi.

Daniel A. White 03.11.2022 22:08

Отправьте lpszString, а не &lpszString. Также прекратите использовать TCHAR. Вы отправляете массив символов.

David Heffernan 03.11.2022 22:13

@ Дэниел А. Уайт, я согласен с тобой. Отправка сообщений в обратном направлении работает корректно. ToSend := 'Hello World'; s := UTF8String(ToSend); copyDataStruct.dwData := MyDataID; //use it to identify the message contents copyDataStruct.cbData := Length(s) * SizeOf(AnsiChar); copyDataStruct.lpData := PAnsiChar(s); res := SendMessage(receiverHandle, WM_COPYDATA, WPARAM(Handle), LPARAM(@copyDataStruct));

Agnius Igres 03.11.2022 22:18

@AgniusIgres После вашего обновления вы теперь отправляете все 1024 chars, хотя вы заполняете только 11 chars. Если вы собираетесь использовать фиксированный массив char[] вместо std::string, рассмотрите возможность использования strlen() для cds.cbData

Remy Lebeau 03.11.2022 23:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На стороне С++:

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

  • sizeof(TCHAR) вместо этого должно быть sizeof(char) (или полностью опущено, поскольку sizeof(char) всегда равно 1).

  • cds.lpData = &lpszString; должно быть cds.lpData = lpszString; вместо этого. Вы отправляете адрес самой переменной lpszString, а не адрес символьных данных, на которые она указывает. Вот почему вы видите мусор на другом конце — вы видите случайные байты из стека вызовов, где находится lpszString, который в вашем случае включает объект std::string (внутренние члены которого включают буфер оптимизации коротких строк, который почему вы тоже видите своих персонажей).

Со стороны Делфи:

  • вы должны подтвердить, что p^.dwData является вашим уникальным номером перед дальнейшей обработкой сообщения. Если число не соответствует ожидаемому, передайте сообщение обработчику inherited и продолжайте.

  • UTF8String должен быть AnsiString, если std::string отправителя на самом деле не закодирован в UTF-8.

Попробуй это:

const UINT uMyDataID = RegisterWindowMessage(TEXT("MyDataID"));
...
if (uMyDataID != 0)
{
    string data_to_send = u8"Hello World";
    COPYDATASTRUCT cds;
    cds.dwData = uMyDataID;
    cds.cbData = sizeof(char) * data_to_send.size();
    cds.lpData = const_cast<char*>(data_to_send.c_str());
    // or: cds.lpData = data_to_send.data(); in C++17 and later
    SendMessage(Output, WM_COPYDATA, reinterpret_cast<WPARAM>(Output), reinterpret_cast<LPARAM>(&cds));
}
var
  uMyDataID: UINT = 0;
...
procedure TMyForm.WMCopyData(var Message: TMessage);
var
  p : PCopyDataStruct;
  s : UTF8String;
begin
  p := PCopyDataStruct(Message.lParam);
  if (uMyDataID <> 0) and (p <> nil) and (p^.dwData = uMyDataID) then
  begin
    SetString(s, PAnsiChar(p^.lpData), p^.cbData);
    ShowMessage(s);
  end else
    inherited;
end;
...
initialization
  uMyDataID := RegisterWindowMessage('MyDataID');
cds.lpData = data_to_send.c_str(); Ошибка компиляции: значение типа "const char *" не может быть присвоено сущности типа "PVOID". Проблема уже решена и пост обновлен, но я добавлю ваши правки по поводу p^.dwData. Большое спасибо!
Agnius Igres 03.11.2022 23:08

@AgniusIgres Я уже исправил проблему c_str до того, как вы опубликовали этот комментарий.

Remy Lebeau 03.11.2022 23:09

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