2

i am sending data to a delphi app using WM_COPYDATA from vb6 app. in my system which local is english, i receive the data correctly, but on another system with dutch local, the receive text is garbled.

the receiving app is the delphi, the code is

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;

EDIT

here is the vb6 code that is sending the data, the data am sending is string

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)

can anyone tell me what am doing wrong?

Smith
  • 5,765
  • 17
  • 102
  • 161
  • 1
    How are you sending the data? Depending on the Delphi version you're using, the string could be interpreted as either unicode or ANSI. If you can confirm your VB code sending method, and Delphi version, I can do an appropriate answer. – Deanna Sep 25 '12 at 09:38
  • @Deanna, it has Delphi 7 tag, so you're half a way closer ;-) – TLama Sep 25 '12 at 11:07
  • I saw that which implies that it's doing ANSI conversion. I still need to know the VB6 code before I can give a definite answer. [D7 seems to support wide chars but the UI doesn't](http://stackoverflow.com/a/2281327/588306). – Deanna Sep 25 '12 at 11:14
  • @Deanna, about D7, it's like you say. You can declare `WideString`s but they won't be properly displayed, when you use built-in components whose are ANSI. – TLama Sep 25 '12 at 12:04
  • For beginning it makes sense to find out, which specific part of your data chain (including UI rendering) does not work. If your memo control does not support unicode, then could you try checking the following on the system with Dutch locale? Control Panel > Regional and Language Options > the tab Administrative -> and make sure that "Language for non-Unicode programs" is Dutch. [look at 1-st screenshot here](http://www.sisulizer.com/localization/support/codepages-w7.shtml) – Stan Sep 25 '12 at 13:37
  • @Deanna i have added the vb6 code, that is sending the data. Note that the data am sending is normal us english charactster, which should not be a problem. – Smith Sep 25 '12 at 15:08
  • @stan i mentioned that i can receive the string in the delphi app correctly in my system with us-en locale. but mu dutch friend gets garbled or corrupted string – Smith Sep 25 '12 at 15:11
  • 1
    That code seems to be confusing byte length, character length, and character encodings. I'll try and do an answer shortly explaining what's happening. – Deanna Sep 25 '12 at 15:34
  • Smith, exactly this is why I'm asking you 2 questions: unicode support in the component and language settings on the Windows with Dutch locale. – Stan Sep 25 '12 at 15:58

1 Answers1

3

VB strings are based on the COM BSTR string type, just like Delphi's WideString string type is. A BSTR is a UTF-16 encoded Unicode string. LenB() returns the number of bytes that a VB string occupies when converted to the local machine's current locale. You are not taking that into account. You are not copying the string bytes into your buffer correctly, and you are not setting the cds.cbData field to the correct value, either. Len() returns the number of UTF-16 encoded characters in the String, whereas LenB() returns the number of bytes instead. For an English string, Len() and LenB() will return the same value, but for a foriegn language that is not guaranteed.

I suggest you send the original VB Unicode encoded data as-is, and change your Delphi code to treat the incoming data as Unicode instead of Ansi like it is currently doing (PChar is Ansi in Delphi 7, but is Unicode in Delphi 2009+).

You also need to assign a unique value to the cds.dwData field. WM_COPYDATA is used by the VCL for some of its own internal data, so you have to differentiate between your WM_COPYDATA messages and the VCL's messages.

Try this instead:

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');
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I don't understand then how it's working with English string, a char in a BSTR is always 2 bytes, isn't it? – Sertac Akyuz Sep 25 '12 at 17:51
  • Yes, a `BSTR` character is 2 bytes. However, in VB, passing a string `ByVal` converts it to Ansi for compatibility with `char`-based APIs. Thus, the code is converting the source string to Ansi when calling `CopyMemory()`, but it is using `Len()` instead of `LenB()` as the third parameter. That will only work correctly for single-byte languages, like English and Latin1-based languages. – Remy Lebeau Sep 25 '12 at 18:09
  • thanks. But this still shouldn't be part of the problem since apart from far-eastern languages all of the ansi charsets are single byte per character. As far as I can tell, Dutch use latin-1 (win-1252). – Sertac Akyuz Sep 25 '12 at 20:26
  • @RemyLebeau am using d7, so how does this `s: WideString; // you can use UnicodeString in D2009+` apply? and regarding the `WM_COPYDATA` and VLC thing you talked about, does this example http://delphi.about.com/od/windowsshellapi/a/wm_copydata.htm then becomes improper – Smith Sep 25 '12 at 20:39
  • If you use the code I showed that sends UTF-16 data instead of Ansi data then the use of `WideString` applies. And yes, that article is incomplete. It touches on the need to fill in the `cds.dwData` to identify `WM_COPYDATA` messages when sending them, but then ignores those identifiers when receiving the messages. – Remy Lebeau Sep 25 '12 at 21:41
  • @RemyLebeau can you help me with the receiving part of the vb6 code you posted in vb6? i cant get the message in delphi yet, so i need to debug it in vb6 – Smith Sep 26 '12 at 16:30