I'm writting a simple wrapper of the Subtitle Workshop library, but I get stuck translating this Delphi export to C# or Vb.Net:
procedure GetSubtitleText(Time: Integer; Text: {$IFDEF UTF8}PWideChar{$ELSE}PChar{$ENDIF}; var BufferLen: Integer); stdcall;
var
FText : {$IFDEF UTF8}WideString{$ELSE}String{$ENDIF};
begin
FText := DisplaySubtitle(Subtitles, Time);
if BufferLen > 0 then
{$IFDEF UTF8}
// Text := Copy(FText, 1, BufferLen)
Text := StringToWideChar(FText, Text, BufferLen)
{$ELSE}
StrLCopy(Text, PChar(FText), BufferLen)
{$ENDIF}
else
BufferLen := Length(FText);
end;
I'm not understanding how to translate the conditionals of the Text
parameter.
This is what I did:
<SuppressUnmanagedCodeSecurity>
<DllImport("SubtitleAPI.dll", EntryPoint:="GetSubtitleText", CharSet:=CharSet.Ansi)>
Friend Shared Sub GetSubtitleText(
<MarshalAs(UnmanagedType.I4)> ByVal time As Integer,
<MarshalAs(UnmanagedType.LPStr)> ByVal text As StringBuilder,
<MarshalAs(UnmanagedType.I4)> ByRef bufferLength As Integer
)
End Sub
It seems to work as expected, however, I would like to ensure that I wrote it correctly.
Your translation is fine, so long as UTF8
is not defined when the Delphi code was compiled. If UTF8
is defined then you would need to marshal as LPWStr
. And I have to assume that the Delphi code is compiled with an ANSI version of Delphi, so that PChar
maps to PAnsiChar
. The Delphi code will be totally broken if you try to compile it with Delphi 2009 or later.
There's not much point in specifying CharSet.Ansi
if you explicitly mark every parameter with an explicit MarshalAs
attribute.
The Delphi code is quite odd. The author seems not to know the difference between UTF-8 and UTF-16. In Delphi PWideChar
and WideString
are UTF-16 encoded. The call to StrLCopy
passes the wrong buffer length, it should pass BufferLen - 1
due to a very poor design of that RTL function. The code should also set BufferLen
to the number of characters copied, but does not.
You can work around that in your .net code. I'll write C# because that's what I know. I'm sure that you will understand it:
int len = 0;
GetSubtitleText(time, null, len);
StringBuilder sb = new StringBuilder(len);
len++; // work around poor design/use of StrLCopy
GetSubtitleText(time, sb, len);
On the face of it, I would be somewhat sceptical of this Delphi code. You should be on your guard. At least you have the source code for it!