Послать сообщение с WM_COPYDATA из vb6 в delphi искажено

Я отправляю данные в приложение Delphi, используя WM_COPYDATA из приложения VB6. в моей системе, которая является английской, я получаю данные правильно, но в другой системе с голландским локальным, получаемый текст искажен.

принимающее приложение - Delphi, код -

procedure TReceiverMainForm.WMCopyData(var Msg: TWMCopyData);
var
  copyDataType: TCopyDataType;
begin
  copyDataType := TCopyDataType(Msg.CopyDataStruct.dwData);

  //Handle of the Sender
  mmoResult.Lines.Add(Format('WM_CopyData from: %d', [msg.From]));

  case copyDataType of
    cdtString: HandleCopyDataString(Msg.CopyDataStruct);
  end;

  //Send something back
  msg.Result := mmoResult.Lines.Count;
end;

procedure TReceiverMainForm.HandleCopyDataString(
  copyDataStruct: PCopyDataStruct);
var
  s: string;
begin
  s := PChar(copyDataStruct.lpData);
  mmoResult.Lines.Add(s);
end;

РЕДАКТИРОВАТЬ

вот код vb6, который отправляет данные, данные, которые я посылаю, - строка

Dim buf() As Byte
ReDim buf(1 To LenB(Message))
Call CopyMemory(buf(1), ByVal Message, Len(Message))
cds.dwData = 0
cds.cbData = Len(Message) + 1
cds.lpData = VarPtr(buf(1))
' Send the string.
Dim i As Long
i = SendMessage(lHwnd, WM_COPYDATA, MainForm.hwnd, cds)

Может кто-нибудь сказать мне, что я делаю не так?

1 ответ

Решение

Строки VB основаны на COM BSTR строковый тип, как у Delphi WideString тип строки BSTR является строкой Unicode в кодировке UTF-16. LenB() возвращает количество байтов, которое занимает строка VB при преобразовании в текущий языковой стандарт локального компьютера. Вы не принимаете это во внимание. Вы неправильно копируете строковые байты в буфер и не устанавливаете cds.cbData поле к правильному значению, либо. Len() возвращает количество символов в кодировке UTF-16 в строке, тогда как LenB() вместо этого возвращает количество байтов. Для английской строки Len() а также LenB() вернет то же значение, но для иностранного языка, который не гарантируется.

Я предлагаю вам отправить исходные данные в кодировке VB Unicode как есть, и изменить код Delphi, чтобы обрабатывать входящие данные как Unicode вместо Ansi, как это происходит в настоящее время (PChar это Ansi в Delphi 7, но Unicode в Delphi 2009+).

Вам также необходимо присвоить уникальное значение cds.dwData поле. WM_COPYDATA используется VCL для некоторых собственных внутренних данных, поэтому вы должны различать WM_COPYDATA сообщения и сообщения VCL.

Попробуйте это вместо этого:

cds.dwData = RegisterWindowMessage("MyWMCopyData")
If cds.dwData <> 0 Then
  cds.cbData = Len(Message) * 2 ' characters are 2-bytes each
  cds.lpData = StrPtr(Message) ' access the string's character buffer directly
  ' Send the string. 
  Dim i As Long 
  i = SendMessage(lHwnd, WM_COPYDATA, MainForm.hwnd, cds) 
End If

,

var
  uMyWMCopyDataMsg: UINT = 0;

procedure TReceiverMainForm.WMCopyData(var Msg: TWMCopyData); 
var 
  s: WideString; // you can use UnicodeString in D2009+ 
begin 
  if (uMyWMCopyDataMsg = 0) or (Msg.CopyDataStruct.dwData <> uMyWMCopyDataMsg) then
  begin
    inherited;
    Exit;
  end;

  mmoResult.Lines.Add(Format('WM_CopyData from: %d', [msg.From])); 

  SetString(s, PWideChar(Msg.CopyDataStruct.lpData), Msg.CopyDataStruct.cbData div SizeOf(WideChar)); 
  mmoResult.Lines.Add(s); 

  msg.Result := mmoResult.Lines.Count; 
end; 

initialization
  uMyWMCopyDataMsg := RegisterWindowMessage('MyWMCopyData');
Другие вопросы по тегам