Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi How to - string in DLL (https://www.delphipraxis.net/161104-how-string-dll.html)

WojTec 16. Jun 2011 18:54

Delphi-Version: 2010

How to - string in DLL
 
This is the bigest problem I currently have: how to use strings in DLL.

I know have to use PChar in exports. How about internal code that operates on Delphi's strings? I want to share this DLL with any language, so I can't use external memory manager (as I did with DLLs that can be used by my software only). For example function returns string or parameter is string or variable or constant is string - what to do whit this?

With numbers there is no problem. Please help me with strings :cry:

Luckie 16. Jun 2011 18:56

AW: How to - string in DLL
 
Here you go: http://www.michael-puff.de/Programmi...tringDLL.shtml

geskill 16. Jun 2011 23:04

AW: How to - string in DLL
 
i always use the WideString type, it is fully COM compatible and i don't have to cast. for me the most easiest way!

jaenicke 17. Jun 2011 04:58

AW: How to - string in DLL
 
You can use PWideChar or PAnsiChar just as the Windows API internally uses too.

If you want to return such a value:
Just give a PWideChar and its size as variable parameter. If the size is not sufficient, you return the size you need. If the size is sufficient you copy the data into the buffer.

This is the way the API manages it. And it works well.

himitsu 17. Jun 2011 06:38

AW: How to - string in DLL
 
WideString = MSDN-Library durchsuchenSysAllocStringLen, MSDN-Library durchsuchenSysReAllocStringLen, MSDN-Library durchsuchenSysFreeString and MSDN-Library durchsuchenSysStringLen

- no delphi type > OLE-String
- no delphi memory manager
- no RTTI required
- no problems

- without reference counting

WojTec 17. Jun 2011 13:11

Re: How to - string in DLL
 
Thanks @Luckie!

Can I ask for example how to use functions @himitsu listed? Or just use WideString as Delphi's string?

WojTec 19. Jun 2011 16:49

Re: How to - string in DLL
 
I tested @Luckies code and it working in example, but don't work in this case:

Delphi-Quellcode:
function func1(s: PChar; Buffer: PChar; lenBuffer: Integer): Integer; external 'StringDLL.dll';

var
  Buffer: array [0..MAX_PATH] of Char;
  BufferSize: DWORD;
begin
  BufferSize := High(Buffer);
  func1('bar', Buffer, BufferSize);
  ShowMessage(Buffer);
end;
Raises AV. Windows functions working, this one not. Why?

jaenicke 19. Jun 2011 17:57

AW: How to - string in DLL
 
One inportant issue first:
Always use PWideChar or PAnsiChar in DLL interfaces. Otherwise it depends on the Delphi version and what PChar means in it whether your program works or not...

Regarding your problem:
I don't see an error handling (you ignore the return value). And where does the exception occur? Inside the DLL function?

And could you please post the source of the function inside the DLL too?

WojTec 19. Jun 2011 19:14

Re: How to - string in DLL
 
Code (function from @Luckie article).

Delphi-Quellcode:
library StringDLL;

uses
  SysUtils;

function func1(s: PWideChar; Buffer: PWideChar; lenBuffer: Integer): Integer; stdcall;
var
  foo: String;
begin
  foo := 'foo'+ s;
  if Assigned(Buffer) then
    StrLCopy(Buffer, PWideChar(foo), lenBuffer);
  Result := Length(foo);
end;

exports
  func1;

begin
end.

function func1(s: PWideChar; Buffer: PWideChar; lenBuffer: Integer): Integer; external 'StringDLL.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
  Buffer: array [0..MAX_PATH] of Char;
  BufferSize: DWORD;
begin
  BufferSize := High(Buffer);
  func1('bar', Buffer, BufferSize);
  ShowMessage(Buffer);
end;
Windows functions I'm using in the sam way, exception in DLL.

Original example is working:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  hLib: THandle;
  s: String;
  foo1: function(s: PChar; Buffer: PChar; lenBuffer: Integer): Integer; stdcall;
  len: Integer;
  Buffer: PChar;
begin
  Buffer := nil;
  hLib := LoadLibrary('StringDLL.dll');
  if hLib = 0 then
  begin
    Str(GetLastError, s);
    ListBox1.Items.Add('LE: ' + s);
    exit;
  end;
  Str(hLib, s);
  ListBox1.Items.Add('hlib: ' + s);
  @foo1 := GetProcAddress(hLib, 'func1');
  if (not Assigned(foo1)) then
  begin
    Str(GetLastError, s);
    ListBox1.Items.Add('AE: ' + s);
    exit;
  end;
  Str(Integer(@foo1), s);
  ListBox1.Items.Add('@func1: ' + s);
  len := foo1('', nil, 0);
  Str(len, s);
  ListBox1.Items.Add('len: ' + s);
  try
    GetMem(Buffer, len + 1);
    len := foo1('', Buffer, len + 1);
    Str(len, s);
    ListBox1.Items.Add(String(Buffer)+ ' [' + s + ']');
  finally
    FreeMem(Buffer);
  end;
end;
I prefer 1st method (as in WinAPI). Why it don't working? :(

jaenicke 19. Jun 2011 19:45

AW: Re: How to - string in DLL
 
Zitat:

Zitat von WojTec (Beitrag 1107352)
Delphi-Quellcode:
  foo := 'foo'+ s;
  if Assigned(Buffer) then
    StrLCopy(Buffer, PWideChar(foo), lenBuffer);

You try to copy lenBuffer Bytes from foo, but it does not have so many Bytes. ;-)

By the way: I prefer the way most of the API functions work:
First I ask for the buffer size needed, then I reserve enough memory and ask for the data itself.

WojTec 19. Jun 2011 20:11

Re: How to - string in DLL
 
Delphi-Quellcode:
library StringDLL;

uses
  SysUtils;

function Foonction(Data: PWideChar; Buffer: PWideChar; lenBuffer: Cardinal): Cardinal; stdcall;
var
  S: string;
begin
  S := 'foo' + Data;

  if Assigned(Buffer) then
    StrLCopy(Buffer, PWideChar(S), lenBuffer)
  ;

  Result := Length(S);
end;

exports
  Foonction;

begin
end.
Dynamic - working:

Delphi-Quellcode:
var
  hLib: THandle;
  func1: function(s: PChar; Buffer: PChar; lenBuffer: Integer): Integer; stdcall;
  len: Integer;
  Buffer: PChar;
begin
  Buffer := nil;
  hLib := LoadLibrary('StringDLL.dll');
  if hLib <> 0 then
  begin
    ListBox1.Items.Add('hlib: ' + IntToStr(hLib));
    @func1 := GetProcAddress(hLib, 'Foonction');
    if Assigned(func1) then
    begin
      ListBox1.Items.Add('@func1: ' + IntToStr(Integer(@func1)));
      len := func1('bar', nil, 0);
      ListBox1.Items.Add('len: ' + IntToStr(len));
      try
        GetMem(Buffer, len + 1);
        len := func1('bar', Buffer, len + 1);
        ListBox1.Items.Add(String(Buffer)+ ' [' + IntToStr(len) + ']');
      finally
        FreeMem(Buffer);
      end;
    end;
  end;
end;
Static - don't working:

Delphi-Quellcode:
function Foonction(Data: PWideChar; Buffer: PWideChar; lenBuffer: Cardinal): Cardinal; external 'StringDLL.dll';

var
  Buffer: PWideChar;
  BufferSize: DWORD;
begin
  BufferSize := Foonction('bar', nil, 0);
  ShowMessage(IntToStr(BufferSize));

  GetMem(Buffer, BufferSize + 1);
  try
    Foonction('bar', Buffer, BufferSize + 1);
    ShowMessage(Buffer);
  finally
    FreeMem(Buffer);
  end;
end;
Now I have identical sizes, what's wrong? :cry:

Luckie 19. Jun 2011 20:18

AW: How to - string in DLL
 
Does Length return the count of characters or the count of Bytes? If it returns the count of characters you have to multiply it by 2 if it's a WideChar.

jaenicke 19. Jun 2011 21:25

AW: How to - string in DLL
 
What about this:
Delphi-Quellcode:
function Foonction(Data: PWideChar; Buffer: PWideChar; lenBuffer: Cardinal): Cardinal; external 'StringDLL.dll';

var
  Buffer: string;
  BufferSize: DWORD;
begin
  BufferSize := Foonction('bar', nil, 0);
  if BufferSize > 0 then
  begin
    SetLength(Buffer, BufferSize);
    Foonction('bar', PWideChar(Buffer), BufferSize);
  end
  else
    Buffer := '';
  ShowMessage(Buffer);
end;
But it would be better if you made lenBuffer a variable parameter. This way you can return the buffer size and a return value.

himitsu 20. Jun 2011 00:44

AW: How to - string in DLL
 
Delphi-Quellcode:
                                                                              vvvvvvv
function func1(s: PWideChar; Buffer: PWideChar; lenBuffer: Integer): Integer; stdcall;
begin
end

function func1(s: PWideChar; Buffer: PWideChar; lenBuffer: Integer): Integer; external 'StringDLL.dll';
                                                                              ^^^^???

jaenicke 20. Jun 2011 04:42

AW: How to - string in DLL
 
Oh ja, darauf hatte ich gar nicht geachtet... :oops:

WojTec 20. Jun 2011 09:24

Re: How to - string in DLL
 
DLL:
Delphi-Quellcode:
library StringDLL;

uses
  SysUtils;

function Foonction(Data: PWideChar; Buffer: PWideChar; lenBuffer: Cardinal): Cardinal; stdcall;
var
  S: string;
begin
  S := 'foo' + Data;

  if Assigned(Buffer) then
    StrLCopy(Buffer, PWideChar(S), lenBuffer)
  ;

  Result := Length(S);
end;

exports
  Foonction;

begin
end.
@Luckie, Length() is function from Delphi :)

Here you are complete code with variants I tried to static load and call StringDLL.dll-->Foonction():

Delphi-Quellcode:
function Foonction(Data: PWideChar; Buffer: PWideChar; lenBuffer: Cardinal): Cardinal; external 'StringDLL.dll';

// 1:

var
  Buffer: string;
  BufferSize: DWORD;
begin
  BufferSize := Foonction('bar', nil, 0);
  if BufferSize > 0 then
  begin
    SetLength(Buffer, BufferSize);
    Foonction('bar', PWideChar(Buffer), BufferSize);
  end
  else
    Buffer := '';
  ShowMessage(Buffer);
end;

// 2:

var
  Buffer: PWideChar;
  BufferSize: DWORD;
begin
  BufferSize := Foonction('bar', nil, 0);
  ShowMessage(IntToStr(BufferSize));

  GetMem(Buffer, BufferSize + 1);
  try
    Foonction('bar', Buffer, BufferSize + 1);
    ShowMessage(Buffer);
  finally
    FreeMem(Buffer);
  end;
end;

// 3:

var
  Buffer: array [0..MAX_PATH - 1] of Char;
  BufferSize: DWORD;
begin
  BufferSize := High(Buffer);
  ShowMessage(IntToStr(Foonction('bar', Buffer, BufferSize)));
  Caption := Buffer;
end;
All of them working when Foonction() is in EXE, none of them working if Foonction() is in DLL - raises AV in DLL. :cry:

Luckie 20. Jun 2011 09:36

AW: How to - string in DLL
 
I know that it is a Delphi function. But I don't know its result, if you use Unicode. I assume it returns the number of characters. So if you allocate the memory you have to double the result of Length.

And there is still the error with the calling convention in your code. Before you try something else correct it. The calling convention for the function in the DLL is stdcall, but in your program it is external!

WojTec 20. Jun 2011 10:48

Re: How to - string in DLL
 
Oh gosh, I forgot add stdcall before external in app. Ah :( Now working! Thanks :D

Also a few of you told that better is using WideChar. I tried this:

Delphi-Quellcode:
// In DLL

function FooncUni(Data: WideString): WideString; stdcall;
var
  S: string;
begin
  S := 'foo' + Data;

  Result := S;
end;

// In app:

function FooncUni(Data: WideString): WideString; stdcall external 'StringDLL.dll';

Caption := FooncUni('bar'); // Caption is 'foobar'
and working without any problems (as normal string type in EXE, that's cool :D). But early @himitsu told:

Zitat:

Zitat von himitsu (Beitrag 1106890)

How to use the functions, they are required to something in this case?

Also another think: to use Ansii or Unicode I have to write 2 functions with PWideChar and PAnsiChar parameters? Or one lets say Unocode version and second to convert Unicode Buffer to Ansi - how? And WideString - it is always Unicode?

jaenicke 20. Jun 2011 15:53

AW: How to - string in DLL
 
Zitat:

Zitat von WojTec (Beitrag 1107417)
Also another think: to use Ansii or Unicode I have to write 2 functions with PWideChar and PAnsiChar parameters? Or one lets say Unocode version and second to convert Unicode Buffer to Ansi - how?

Well, for the version with PAnsiChar you append an A, and for PWideChar a W.
For example the API has ShellExecuteA and ShellExecuteW. Delphi itself maps ShellExecute to ShellExecuteA (Delphi 1 - 2007) or to ShellExecuteW (Delphi 2009+). So you don't see that you call one of the other functions. ;-)

Zitat:

Zitat von WojTec (Beitrag 1107417)
And WideString - it is always Unicode?

Yes it is.

I myself do not want to use it because it relies on OLE and the operating system. That's why it is much slower. Of course this doesn't matter unless you call such a method often.

For COM WideStrings are very useful (I also used them to interact with .NET libraries with exported native functions), but for other purposes I do not use them.

But it is your decision, both ways work.

WojTec 20. Jun 2011 17:54

Re: How to - string in DLL
 
Thanks guys, you helped me so much! :D

WojTec 22. Jun 2011 15:32

Re: How to - string in DLL
 
There is another problem - compatibility Ansii/Unicode.
DLL is compiled with D2010, it uses unit with string type.
In API unit I strings declared as AnsiString:

Delphi-Quellcode:
S: AnsiString;
S := FuncReturnsString();
StrLCopy(lpBuffer, PAnsiChar(AnsiString(S)), nSize) // second typecast is from old version
If both DLL and app are compiled in Ansii compiler (D7) - it working, if in Unicode (D2010) - also working. Of one compiled in Ansii and second in Unicode, then raises invalid pionter operation exception, but buffers has correct data. I don't understand. What I'm doing wrong?

jaenicke 22. Jun 2011 16:36

AW: How to - string in DLL
 
I think this is a problem with the size parameter.

You always have to have in mind that one character is one byte in Delphi 7 and two bytes in Delphi 2010.

How does the code for reserving the memory, ... look like?

WojTec 22. Jun 2011 19:28

Re: How to - string in DLL
 
Hm, my functions working as in example on 1st page in this thread, size is length of S, in Ansii should be S length, but in Unicode length * 2 if we talking about bytes nor string length, but the same code working if both EXE and DLL are Ansii OR Unicode. So, what I should to do?


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:59 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz