我有一个返回大字符串的Delphi 7 DLL函数,它工作正常,但在Delphi XE5中,我在特定大小后得到访问冲突。
我已经编写了一个示例演示,它反映了我的实际代码,在Delphi XE5中也生成了一个AV,它也返回一个大字符串,但是在特定大小之后,我又遇到了访问冲突?
13000行20个字符,它工作正常,但有14000行崩溃。 我用Delphi 7做了一些测试,它也可以正常工作。
我做错了什么?任何人都可以帮助我吗?
感谢。
这是我的DLL的代码:
function RetLargeStr(Buffer : pAnsiChar; var BufferSize: Integer) : boolean ; stdcall;
var l_ansiStr : string;
loop : integer;
begin
Result := False;
//13000 ok 14000+ fail ???
for loop := 1 to 15000 do
begin
l_AnsiStr := l_AnsiStr + 'String of 20 chars' + Char($0D) + Char($0A) ;
end;
if Assigned(Buffer) and (BufferSize >= Length(l_ansiStr) + 1) then
begin
//Buffer := pAnsiChar(AnsiString(l_AnsiStr));
move(l_AnsiStr, Buffer^, length(l_AnsiStr) + 1);
Result := True;
end;
//Return actual size of output string.
BufferSize := Length(l_AnsiStr) + 1;
end ;
这是来自我的EXE的电话:
procedure TForm1.Button7Click(Sender: TObject);
var l_StrOut : pAnsiChar;
l_Str : ansistring;
p_Size : integer;
begin
p_Size := 600000;
SetLength(l_Str, p_Size);
l_strout := pAnsiChar(l_str);
Memo2.Lines.Clear;
if RetLargeStr(l_StrOut, p_Size)
then Memo2.Lines.Add( l_StrOut );
end;
答案 0 :(得分:1)
你在这里拥有它的方式可能只是运气,它可以运作。
在DLL中,执行此操作时:
Buffer := pAnsiChar(AnsiString(l_AnsiStr));
您实际上是将DLL中分配的字符串缓冲区返回给调用EXE,即使您在调用之前已经明确分配了接收缓冲区。该接收缓冲区指针被覆盖。
崩溃最有可能发生,因为EXE中的堆管理器没有准备释放内存块,该内存块是在其他地方(在DLL中)分配的。
您可以尝试将字符串的内容复制到缓冲区,而不是分配给缓冲区,如下所示:
if Assigned(Buffer) and (BufferSize >= Length(l_ansiStr) + 1) then
begin
move(AnsiStr[1], Buffer^, length(AnsiStr) + 1));
Result := True;
end;
测试代码(DLL):
library Project2;
uses
SysUtils,
Classes;
function RetLargeStr(Buffer : pAnsiChar; var BufferSize: Integer) : boolean ; stdcall;
var l_ansiStr : string;
loop : integer;
begin
Result := False;
//13000 ok 14000+ fail ???
for loop := 1 to 15000 do
begin
l_AnsiStr := l_AnsiStr + 'String of 20 chars' + Char($0D) + Char($0A) ;
end;
if Assigned(Buffer) and (BufferSize >= Length(l_ansiStr) + 1) then
begin
//Buffer := pAnsiChar(AnsiString(l_AnsiStr));
move(l_AnsiStr[1], Buffer^, length(l_AnsiStr) + 1);
Result := True;
end;
//Return actual size of output string.
BufferSize := Length(l_AnsiStr) + 1;
end ;
exports
RetLargeStr;
begin
end.
测试代码(EXE):
unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm3 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
function RetLargeStr(Buffer : pAnsiChar; var BufferSize: Integer) : boolean ; stdcall; external 'project2.dll';
procedure TForm3.Button1Click(Sender: TObject);
var l_StrOut : pAnsiChar;
l_Str : ansistring;
p_Size : integer;
begin
p_Size := 600000;
SetLength(l_Str, p_Size);
l_strout := pAnsiChar(l_str);
Memo1.Lines.Clear;
if RetLargeStr(l_StrOut, p_Size)
then Memo1.Lines.Add( l_StrOut );
end;
end.