delphi:没有内存管理器的dll用于传输字符串

时间:2012-01-05 07:33:26

标签: delphi dll delphi-xe

Delphi Xe。

给出:

1.dll,以单位

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.程序,窗口备忘录和2个按钮

...
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.

要下载源代码,可以在此处执行:http://www.multiupload.com/WSZKF8IGP1

按下按钮,在dll行(ansi或宽字符串)中有一个传输,它在msgbox dll中显示,在那里处理(空闲时间大写)并返回程序。没有使用内存管理器(快速 - 简单 - sharemem)。在程序和dll中都包含了ReportMemoryLeaksOnShutdown(显示有关内存丢失的事件),这些内容都是静默的,即所有内容都可以工作,而且各行的长度也一样重合。

这是必要的

  1. 要查看是否存在错误(检查错误)

  2. 是否可以优化或提供更好或更轻松的方式

  3. 是否可以使用VB或C ++ / C#中的此类过程寻址此DLL?

  4. 由于

3 个答案:

答案 0 :(得分:4)

如果您不想使用堆管理器传输数据,只需使用WideString种字符串。

它会(稍微)慢,但它会允许你改变每一边的字符串长度。

它将是真正的Unicode,因此在使用XE下的本机Delphi UnicodeString时,您不会遇到任何关于char set的问题。您可以在代码中使用WideString,转换为string将以静默方式完成。

它将全部由Windows管理,因此即使非Delphi库或应用程序(如.Net或C ++)也能够直接处理它。

答案 1 :(得分:3)

你太复杂了。 Delphi语言/库将处理字符串和指向以null结尾的char数组的指针之间的转换。

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.

类似于调用例程

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;

我省略了您包含的所有诊断代码。如果要在显示文本之前对文本进行修改,或者在将文本传递给DLL之前进行修改,那么这很容易。使用本地字符串变量中的标准字符串操作进行修改(上面始终命名为s)。

例如:

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

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

最重要的是,你完全不需要编写在字符串和指针之间转换为以null结尾的char数组的代码,因为Delphi会为你做这件事。

答案 2 :(得分:1)

使用代码

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

你最终会破坏程序堆;我想你的意思是

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

由于您的Dll在接口部分不使用托管字符串类型,因此它不需要共享内存管理器,可以与其他语言一起使用(如VB或C ++ / C#)。