-2

Delphi Xe.

It is given:

1.dll, in it a unit

unit DllUnit; interface

uses windows, sysutils;

Procedure GuPrcA(var p:PAnsiChar;const l:integer); StdCall;
Procedure GuPrcW(var p:PWideChar;const l:integer); StdCall;

Exports GuPrcA,GuPrcW;

implementation

procedure GuMes(s:string);
begin
MessageBox(0,pchar(s),'From dll',mb_iconinformation);
end;

Procedure GuPrcW(var p:PWideChar;const l:integer); // wide
var s:widestring;
begin
if (p=nil)or(l<1) then begin p:=nil;exit;end;
SetLength(s,trunc(l/sizeof(widechar)));Move(p^,Pointer(s)^,l);
gumes('l: '+inttostr(l)+', nl: '+inttostr(length(s))+#10+'-'+s+'-');
s:=widestring(Uppercase(s));Move(Pointer(s)^,p^,l);
end;

Procedure GuPrcA(var p:Pansichar;const l:integer); // ansi
var s:ansistring;
begin
if (p=nil)or(l<1) then begin p:=nil;exit;end;
SetLength(s,l);Move(p^,Pointer(s)^,l);
gumes('l: '+inttostr(l)+', nl: '+inttostr(length(s))+#10+'-'+s+'-');
s:=ansistring(AnsiUppercase(s));Move(Pointer(s)^,p^,l);
end;

Initialization

ReportMemoryLeaksOnShutdown:=true;

end.

2.The program, at a window memo and 2 buttons

...
implementation

{$R *.dfm}

Procedure GuPrcA(var p:PansiChar;const l:cardinal); StdCall; external 'mydll.dll' name 'GuPrcA';
Procedure GuPrcW(var p:PwideChar;const l:cardinal); StdCall; external 'mydll.dll' name 'GuPrcW';

procedure TForm1.Button6Click(Sender: TObject);
var p:pwidechar;c:cardinal;s:widestring;
begin
s:=widestring(memo1.Text);
c:=length(s)*sizeof(widechar);
p:=allocmem(c);
Move(Pointer(s)^,p^,c);
GuPrcW(p,c);
s:='';setlength(s,trunc(c/sizeof(widechar)));
Move(p^,Pointer(s)^,c);
Freemem(p,c);
memo1.Text:='='+s+'= l:'+inttostr(c);
end;

procedure TForm1.Button7Click(Sender: TObject);
var p:pansichar;c:cardinal;s:ansistring;
begin
s:=ansistring(memo1.text);
c:=length(s);
p:=allocmem(c);
Move(Pointer(s)^,p^,c);
GuPrcA(p,c);
s:='';setlength(s,c);
Move(p^,Pointer(s)^,c);
Freemem(p,c);
memo1.Text:='='+s+'= l:'+inttostr(c);
end;

Initialization

ReportMemoryLeaksOnShutdown:=true;

end.

To download an source code both it is possible here: http://www.multiupload.com/WSZKF8IGP1

By pressing buttons there is a transfer in dll lines (ansi or wide string), its display in msgbox dll, its processing there (idle time uppercase) and return to the program. The manager of memory is not used (fast - simple - sharemem). Both in a program and in dll are included ReportMemoryLeaksOnShutdown (display of events about memory losses) which both are silent, i.e. like all would work also lengths of lines too everywhere coincide.

That is necessary:

  1. To look, whether there are no there errors (to check up on errors)

  2. Whether it is possible to optimise or offer a way better or easier

  3. Whether it is possible to address to this DLL with such procedures from VB or C++/C# ?

Thanks

Johan
  • 74,508
  • 24
  • 191
  • 319
Gu.
  • 1,947
  • 4
  • 30
  • 49

3 Answers3

4

If you do not want to use the heap manager for you transmission of data, just use WideString kind of string.

It will be (a bit) slower, but it will allow you to change the string length on every side.

And it will be true Unicode, so you won't have any trouble about char set and such when using native Delphi UnicodeString under XE. You can use WideString in your code and the conversion to string will be done silently.

It will be all managed by Windows, so even non Delphi libraries or applications (like .Net or C++) would be able to handle it directly.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
3

You are over-complicating. The Delphi language/libraries will handle conversion between strings and pointers to null-terminated char arrays.

unit DllUnit; 

interface

uses 
  windows, sysutils;

Procedure GuPrcA(var p:PAnsiChar); StdCall;
Procedure GuPrcW(var p:PWideChar); StdCall;

Exports 
  GuPrcA,GuPrcW;

implementation

procedure GuMes(s:string);
begin
  MessageBox(0,pchar(s),'From dll',mb_iconinformation);
end;

Procedure GuPrcW(var p:PWideChar); // wide
var
  s: string;
begin
  s := p;
  gumes(s);
end;

Procedure GuPrcA(var p:Pansichar); // ansi
var
  s: string;
begin
  s := p;
  gumes(s);
end;

Initialization
  ReportMemoryLeaksOnShutdown:=true;

end.

And similarly for the calling routines

Procedure GuPrcA(var p:PansiChar); StdCall; external 'mydll.dll' name 'GuPrcA';
Procedure GuPrcW(var p:PwideChar); StdCall; external 'mydll.dll' name 'GuPrcW';

procedure TForm1.Button6Click(Sender: TObject);
var
  s: UnicodeString;
begin
  s := memo1.Text;
  GuPrcW(PWideChar(s));
end;

procedure TForm1.Button7Click(Sender: TObject);
var
  s: AnsiString;
begin
  s := memo1.Text;
  GuPrcA(PAnsiChar(s));
end;

I have omitted all the diagnostics code that you included. If you want to make modifications to the text before displaying it, or before passing it to the DLL then that's easy. Make the modifications using standard string operations in the local string variables (always named s above).

For example:

Procedure GuPrcA(var p:Pansichar); // ansi
var
  s: string;
begin
  s := p;
  s := s + '-' + Length(s);
  gumes(s);
end;

or

procedure TForm1.Button7Click(Sender: TObject);
var
  s: AnsiString;
begin
  s := memo1.Text;
  s := s + '-' + Length(s);
  GuPrcA(PAnsiChar(s));
end;

The bottom line is that there is absolutely no need for you to write code that converts between strings and pointers to null-terminated char arrays since Delphi will do it for you.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • No. Display of a string here excites me a little. Problem: to transfer a string in DLL, to show it there (only to look, whether correctly it is transferred), __to process (convert/modify/ect) and return back_ in the program. Especially widestring where can be other coding or 2-byte symbols #0 in the middle of a array. – Gu. Jan 05 '12 at 08:07
  • What do you mean? No what? In all cases I can think of it is easier to use strings as your buffer in preference to manual memory allocation. – David Heffernan Jan 05 '12 at 08:10
  • Are you sure that you want to support #0 in the middle of a string? If so why? A list of strings? Normally done with double null terminated. – David Heffernan Jan 05 '12 at 08:24
1

With the code

SetLength(s, trunc(l/sizeof(widechar)));
Move(p^, Pointer(s)^, l);

you will finally get program heap corrupted; I guess you meant

SetLength(s, l);
Move(p^, Pointer(s)^, l * sizeof(widechar));

Since your Dll does not use managed string types in interface section, it need not a shared memory manager and can be used with other languages (like VB or C++/C#).

kludg
  • 27,213
  • 5
  • 67
  • 118