DLL输出丢失字符问题,实在搞不定了 ( 积分: 100 )

  • 主题发起人 主题发起人 rsjd
  • 开始时间 开始时间
R

rsjd

Unregistered / Unconfirmed
GUEST, unregistred user!
函数库:
library strstr;
uses
Windows,SysUtils;
function strToJS(const str: PChar): PChar
stdcall;
var
Len: Cardinal;
strn: String;
begin
Len := StrLen(str);
if Len &gt
0 then
begin
try
SetLength(strn, 256);
strn := strPas(str);
strn := StringReplace(strn, '''', '/''', [rfReplaceAll]);
strn := StringReplace(strn, '"', '/"', [rfReplaceAll]);
strn := StringReplace(strn, '/', '//', [rfReplaceAll]);
Result := PChar(strn);
except
Result := PChar('');
end;
end
else
Result := PChar('');
end;
exports
strToJS;
begin
end.

看起来一切正常,但就是在使用时,无缘无故有时会丢失字符,比如字符串'金属垫片(齿形)'输出正常,但字符串'金属垫片(不锈钢)'就会在把主程序中后面两个字符串丢失,为什么呢?
 
函数库:
library strstr;
uses
Windows,SysUtils;
function strToJS(const str: PChar): PChar
stdcall;
var
Len: Cardinal;
strn: String;
begin
Len := StrLen(str);
if Len &gt
0 then
begin
try
SetLength(strn, 256);
strn := strPas(str);
strn := StringReplace(strn, '''', '/''', [rfReplaceAll]);
strn := StringReplace(strn, '"', '/"', [rfReplaceAll]);
strn := StringReplace(strn, '/', '//', [rfReplaceAll]);
Result := PChar(strn);
except
Result := PChar('');
end;
end
else
Result := PChar('');
end;
exports
strToJS;
begin
end.

看起来一切正常,但就是在使用时,无缘无故有时会丢失字符,比如字符串'金属垫片(齿形)'输出正常,但字符串'金属垫片(不锈钢)'就会在把主程序中后面两个字符串丢失,为什么呢?
 
一般dll中要返回pchar的都是用var参数传入比较好。

procedure strToJS(const str: PChar;var outstr:PChar)
stdcall;
 
但我就有点想不明白,我的函数为什么会把主程序的字符串改掉?我的主程序是这样的(VB):

dim str1, str2 as string
str1 = "金属垫片(不锈钢)"
str2 = "s='&quot
&amp
strToJS(str1) &amp
"';"
这个语句运行后居然变成为str2="s='金属垫片(不锈钢)",就是说把"';"这两个字符去掉了,但如果str1="金属垫片(齿形)"的话,又是正常值,真是怪事情
 
dirk说得是正解!
不过还有简单的一招,把strn: String;定义为全局变量。
 
function strToJS(const str: PChar;sResult:PChar): PChar
stdcall;//加上一个传回的参数
var
Len: Cardinal;
strn: String;
begin
Len := StrLen(str);
if Len &gt
0 then
begin
try
// SetLength(strn, 256)
//在动态库中分配内存
strn := strPas(str);
strn := StringReplace(strn, '''', '/''', [rfReplaceAll]);
strn := StringReplace(strn, '"', '/"', [rfReplaceAll]);
strn := StringReplace(strn, '/', '//', [rfReplaceAll]);
Result := PChar(strn)
//传到主程序中会出错的
except
Result := PChar('');
end;
end
else
Result := PChar('');

end;
 
还是搞不定啊,修改后的程序如下,毛病一样的,是不是delphi不能做DLL啊???
function strToJS(const str: PChar
var outStr: PChar): integer
stdcall;
var
strn: string;
begin
Result := 0;
if StrLen(str) &gt
0 then
begin
try
strn := strPas(str);
strn := StringReplace(strn, '/', '//',[rfReplaceAll]);
strn := StringReplace(strn, '''', '/''',[rfReplaceAll]);
strn := StringReplace(strn, '"', '/"',[rfReplaceAll]);
outStr := PChar(strn);
Result := 1;
except
end;
end
else
begin
outStr := str;
Result := 1;
end;
end;

VB中调用它的函数:
Private Declare Function strToJS Lib "unit1.dll&quot
(ByVal str As String, outStr As String) As Long

Public Function showJS(ByVal str As String) As String
strToJS str, showJS
End Function
 
用在VB里问题可多了,可能是d对unicode支持的问题,VB里调用问题n多,我还有个问题没解决挂着呢。


参数不用pchar改用widestring试试。
 
赫赫,我以前也问过这个问题
http://delphibbs.com/delphibbs/dispq.asp?lid=2646321
 
终于搞定了,代码如下:
threadVar strn: string
//先定义全局变量
function strToJs(const str: PChar): PChar
stdcall;
begin
try
if StrLen(str) &gt
0 then
begin
strn := str;
strn := StringReplace(strn, '/', '//',[rfReplaceAll]);
strn := StringReplace(strn, '''', '/''',[rfReplaceAll]););
strn := StringReplace(strn, '"', '/"',[rfReplaceAll]););
Result := PChar(strn);
strn := '';
end
else
Result := '';
except
Result := '';
end;
end;
来个小总结和一个疑问:
1。必须用stdcall;
2。参数和返回值如果是字符串,必须用PChar;
3。返回值如果是字符串,最方便的办法是在DLL中声明一个全局变量(高手除外),Another_eYes大佬用的Inc(PInteger(Integer(result)-8)^);这句我没看懂,不太明白是什么意思,好象是说将返回值的地址减去8?为什么?
 
function strToJs(str: PChar): PChar
stdcall;
var
s : string;
begin
try
if StrLen(str) &gt
0 then
begin
s := strPas(str);
s:= StringReplace(s, '/', '//',[rfReplaceAll]);
s:= StringReplace(s, '''', '/''',[rfReplaceAll]);
s:= StringReplace(s, '"', '/"',[rfReplaceAll]);
Result := StrAlloc(Length(s));
StrPCopy(Result, s);
end
else
begin
Result := StrAlloc(1);
StrPCopy(Result, #0);
end;
except
Result := nil;
end;
end;
 
来自:lichengbin, 时间:2005-2-25 10:27:38, ID:2997116 | 编辑
dirk说得是正解!
不过还有简单的一招,把strn: String;定义为全局变量。

早就跟你讲过,简单的方法是直接把strn定义为全局变量,嘿嘿

Another_eYes大佬用的Inc(PInteger(Integer(result)-8)^);这句我没看懂,不太明白是什么意思,好象是说将返回值的地址减去8?为什么?
字符串在内存中的结构:
StrRec = packed record
refCnt: Longint;
length: Longint;
end;
字符串内容 <- 字符串指针
结束符#0

这是把Result字符串的引用计数增加1,这是为了避免主程序端返回结果字符串使用完之后,引用计数减1成为0而释放字符串内存,由于在DLL中分配的字符串,因此在主程序中释放会出问题(DLL、EXE内存管理器不同)。而在DLL中主动将此值增1就避免了主程序会自动释放这个内容。不过缺点是每次调用都会导致分配一块字符串内存,使用完之后不被释放,这实际上也可以算是内存泄漏。当然程序结束时占用的资源总是会释放的。
 
学习!高手们都常来坐坐!
 
>Another_eYes大佬用的Inc(PInteger(Integer(result)-8)^);这句我没看懂,不太明白是什么意思,好象是说将返回值的地址减去8?为什么?

Another_eYes的方法是手动把string的引用记数加1,以骗过系统,不释放字符串占用的内存,楼主的这类问题都是一个原因:字符串内存被释放,运气好的话,这些内存仅仅是被弃用,而没有被别的数据占用,还可以读出数据,运气不好的话,读出的内容就错误了。

我觉得用全局变量不好,用var参数才是比较好的方法,程序中总不能所有的函数处处都用全局变量吧?

你用用var参数的代码的问题是,你传入的var参数并没有申请自己的内存,指向的仍然是局部string变量,string类型的结构其实和pchar是一样的,只是多了引用记数和字符串长度,在强制转换的时候直接把pchar指向了string的字符数组部分,这样,在string释放后pchar指向的内存的内容就不定了,这就是你用var参数仍然错误的原因,和使用pchar返回值的问题是一样的。
 
这100分真是太值了,尝到好多别的地方学不到的东西,可惜我总共只有1百多分,不然就多送上一些
 
后退
顶部