2012-01-05 29 views
-2

Delphi Xe。德尔福:DLL没有内存管理器的字符串传输

它给出:

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,它的处理(空闲时间大写)并返回到程序。内存管理器不使用(快速 - 简单 - 共享)。在程序和dll中都包含了ReportMemoryLeaksOnShutdown(显示关于内存丢失的事件),它们都是无声的,就像所有的线程都可以工作一样,线路的长度也在任何地方都一致。

是必要

  1. 看,是否有不存在错误(检查上面的错误)

  2. 是否有可能优化或提供了一个更好的方式或更容易

  3. 是否有可能使用VB或C++/C#中的此类过程来解决此DLL问题?

感谢

+0

如何管理这种编码风格? : -/ – OnTheFly 2012-01-05 09:40:21

+0

这是正常的我可以:) – 2012-01-05 10:47:26

+1

@Gu否你不能。你有一个很大的问题,因为你不缩进你的代码。 – 2012-01-05 10:52:17

回答

4

如果您不想使用堆管理器来传输数据,只需使用WideString类型的字符串即可。

它会慢一点,但它可以让你改变每一边的字符串长度。

而且它将是真正的Unicode,因此在XE下使用原生Delphi UnicodeString时,不会有任何关于字符集的问题。您可以在您的代码中使用WideString,转换为string将以无提示方式进行。它将全部由Windows管理,因此即使非Delphi库或应用程序(如.Net或C++)也能够直接处理它。

+0

+1是的,'WideString',也被称为'BSTR',是interop的绝佳选择。 – 2012-01-05 09:20:31

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#)中使用。

+0

setlength ... =在DLL和程序中? – 2012-01-05 07:54:27

+0

@serg奇怪q中的代码传递字节大小而不是字符串长度 – 2012-01-05 08:27:01

+0

@david在任何情况下,OP代码对于奇数'l'值都不正确 – kludg 2012-01-05 08:31:38

3

你太过复杂了。 Delphi语言/库将处理字符串之间的转换以及指向空终止字符数组的指针。

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; 

底线是,有完全没有必要为你写的字符串和指针之间进行转换,因为以空字符结尾的字符数组码德尔福将为你做到这一点。

+0

不,显示字符串在这里让我感到有点兴奋。问题:在DLL中传输一个字符串,在那里显示它(仅查看,是否正确传输),__to处理(转换/修改/ ect)并返回程序中的back_。尤其是宽字符串,其中可以是其他编码或数组中间的2字节符号#0。 – 2012-01-05 08:07:34

+0

你是什么意思?没有什么?在所有情况下,我都能想到使用字符串作为缓冲区比使用手动内存分配更容易。 – 2012-01-05 08:10:10

+0

您确定要在字符串中间支持#0吗?如果是这样,为什一串字符串?通常用双null终止。 – 2012-01-05 08:24:01