关于Dll编写中传递string的问题(100分)

  • 主题发起人 dead_lee
  • 开始时间
D

dead_lee

Unregistered / Unconfirmed
GUEST, unregistred user!
我想写一个dll供其他程序调用,其中需要传递字符串出来,由于pascal对于string的处理
方式,我想传递出一个pchar出来,程序如下
dll中的函数
function StringTest(out Pstr: Pchar): integer;
var
Str: string;
Chars: array[0..255] of char;
i: integer;
begin
for i:=1 to 255 do
begin
Chars := #0;
end;

Str := 'leetest'+#0;
for i:=0 to Length(Str) do
begin
Chars := Str;
end;

Pstr := @Chars;
end;
宿主程序部分:
procedure TForm1.Button1Click(Sender: TObject);
var
Msg: string;
PStr: Pchar;
begin
PStr := nil;
StringTest(PStr);
Msg := PStr;
ShowMessage(Msg);
end;
程序出现非法访问错误,经察看帮助得知是因为不能将函数中的局部变量的地址返回所至
帮助信息如下
A common error when working with PChars is to store in a data structure, or
return as a value, a local variable. When your routine ends, the PChar will
disappear because it is simply a pointer to memory, and is not a reference
counted copy of the string. For example:

function title(n: Integer): PChar;
var
s: string;
begin
s := Format('title - %d', [n]);
Result := PChar(s)
// DON'T DO THIS
end;

This example returns a pointer to string data that is freed when the
title function returns.
现在想知道到底如何是正确的做法.
 
Chars: array[0..255] of char;
改成Chars: ^char;

然后getmem(Chars,256);

不过要记得调用后free(PStr)
 
应该在外部分配好一定长度的字符(比如255长的字符数组),然后传入地址给Dll
让Dll把结果填入。微软就这么干
 
最好不要在Dll中分配内存,或者使用Dll中的临时变量的内存
在主程序中分配好,以pchar的方式传给Dll
out类型也不要用把?
 
redcony说得对。最好把Chars去掉,直接用Pstr,调用先分配内存。
 
function StringTest(out Pstr: Pchar): integer;
var
Str: string;
i: integer;
begin

Str := 'leetest';

StrPCopy(Pstr,Str);
end;
 
var
Str: string;
Chars: array[0..255] of char
//这是栈上分配的, 过程结束后就不存在了,所以访问时出现错误
i: integer;

你应该这样处理
function StringTest(Buffer: Pchar
Len: Integer): integer;
然后根据输入的Buffer地质来复制
参考完颜康,的例子
 
奇怪,我修改程序成这个样子...
dll的函数
function StringTest(out Pstr: Pchar): integer;
var
Str: string;
i: integer;
begin
Str := 'leetest';
StrPCopy(Pstr, Str);
end;
宿主程序部分
procedure TForm1.Button1Click(Sender: TObject);
var
Msg: string;
PStr: Pchar;
begin
getmem(PStr, 256);
StringTest(PStr);
Msg := PStr;
ShowMessage(Msg);
// FreeMem(Pstr, 256);
end;
现在的依然会有内存错误,不过变成了第1,3,5次点击会出错,第2,4,6次能显示数据,但是
只显示了'est',请继续指教,谢谢...
另外,如果加上FreeMem的那一句,会出'不正确的指针操作'这样的错误.
 
不用这么麻烦
只要将你的uses语句改成这样就行了
uses
ShareMem,......
borland公司说得好
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
 
关键就在于我为了兼容性和发布时的方便,不打算用string而用Pchar,你注意用ShareMem 是在需要
用String作为传入传出参数的时候才需要。
 
function StringTest(Pstr: Pchar): integer;
var
Str: string;
i: integer;
begin
Str := 'leetest'+#0;
for i:=0 to Length(Str)-1 do ////////////
pstr := Str[i+1]
///////////
pstr[Length(Str)]:=#0;
end;

宿主程序部分:
procedure TForm1.Button1Click(Sender: TObject);
var
PStr: char[0..255];
begin
StringTest(PStr);
ShowMessage(pstr);
end;
 
StringTest(PStr);
不用附直?
 
to jsxjd,
你的程序你测试过没有,也不能用哦,当然其中
PStr: char[0..255];
我改成了
PStr: array[0..255] of char;
否则无法通过编译;

to dragonlee007,
我已经用getmem(PStr, 256);给PChar指针分配了内存啊,不用再赋值的了.

 
以下我调试过了,也就是上面的声明问题:

library testdll;

uses
SysUtils,
Classes;

{$R *.RES}

function StringTest(Pstr: Pchar): integer;
var
Str: string;
i: integer;
begin
Str := 'leetest'+#0;
for i:=0 to Length(Str)-1 do ////////////
pstr := Str[i+1]
///////////
pstr[Length(Str)]:=#0;
end;
exports
StringTest;
end.






//////////////
function StringTest(Pstr: Pchar): integer;external 'testdll';
procedure TForm1.Button1Click(Sender: TObject);
var
PStr: array[0..255] of char;
begin
StringTest(PStr);
ShowMessage(pstr);
end;
 
这就奇怪了,我这里几乎照抄下来,一运行就出内存访问错误,有什么编译开关是需要注意
的吗
 
终于找到问题的原因了,dll里面把Pchar变量声明成out,那么主程序里面也一定要声明
成out,否则会出错。
结贴了,上面诸位也帮我解决了程序中的其他错误,唉,才几行程序,错误良多啊。。。
 
多人接受答案了。
 
顶部