继续讨论DLL输出字符的问题 ( 积分: 100 )

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

rsjd

Unregistered / Unconfirmed
GUEST, unregistred user!
上个帖子我已经结了,但是却发生了新的问题,新开一贴,不好意思,本人分不多,只给100分,我做了个试验,函数库DLL代码如下:
procedure test(const str: PChar
var outStr: PChar)
stdcall;
var strn: string;
begin
strn := str;
if Length(strn) &gt
0 then
begin
strn := StringReplace(strn, '/', '//', [rfReplaceAll]);
strn := StringReplace(strn, '''', '/''', [rfReplaceAll]);
strn := StringReplace(strn, '"', '/"', [rfReplaceAll]);
end;
outStr := PChar(strn);
end;
exports test;
VB中调用的代码如下:
Private Declare Sub test Lib "unit1.dll&quot
(ByVal str As String, outStr As String)
Public Function vbsToJs(ByVal str As String) As String
Dim strOut As String
test str, strOut
vbsToJs = strOut
End Function
结果仍然不正确,还是会丢失字符,也就是说结果不可预料,但是且慢,只要我把DLL中的StringReplace改为Peter Morris的FastStrings单元中的FastAnsiReplace,结果戏剧性地发现,不管我怎么搞,结果都完全正确,这下我就更加搞不明白了,这是DELPHI的BUG呢,还是我哪里又出漏子了?
原来的帖子请看:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2997058
 
上个帖子我已经结了,但是却发生了新的问题,新开一贴,不好意思,本人分不多,只给100分,我做了个试验,函数库DLL代码如下:
procedure test(const str: PChar
var outStr: PChar)
stdcall;
var strn: string;
begin
strn := str;
if Length(strn) &gt
0 then
begin
strn := StringReplace(strn, '/', '//', [rfReplaceAll]);
strn := StringReplace(strn, '''', '/''', [rfReplaceAll]);
strn := StringReplace(strn, '"', '/"', [rfReplaceAll]);
end;
outStr := PChar(strn);
end;
exports test;
VB中调用的代码如下:
Private Declare Sub test Lib "unit1.dll&quot
(ByVal str As String, outStr As String)
Public Function vbsToJs(ByVal str As String) As String
Dim strOut As String
test str, strOut
vbsToJs = strOut
End Function
结果仍然不正确,还是会丢失字符,也就是说结果不可预料,但是且慢,只要我把DLL中的StringReplace改为Peter Morris的FastStrings单元中的FastAnsiReplace,结果戏剧性地发现,不管我怎么搞,结果都完全正确,这下我就更加搞不明白了,这是DELPHI的BUG呢,还是我哪里又出漏子了?
原来的帖子请看:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2997058
 
StringReplace
???????

String <&gt
PChar 不是吗?
 
var strn: string;
str:PChar;
strn := str //这里最好转换一下.一个是字符串指针,另一个是字符串
 
楼上两位,在D5版本以后,PChar是可以直接赋值给string变量的,这个没有问题,而且我测试过加不加strPas是一样的,Help中说了,This function is provided for backwards compatibility only,也就是说是不必要的
 
procedure test(const str: PChar
outStr: PChar)
stdcall
//不要var
VB中怎么调用不太清楚。对于传出参数,调用函数前必须分配足够的内存,否则会丢失字符
 
strn是局部变量,这样操作outStr := PChar(strn);结果难预料。
把strn设为全局变量试试
 
全局变量我已经知道是可行的,但我还是想试试用局部变量的方法,我也不想让DLL到处是全局变量,况且这个DLL以后可能会在服务器上多个线程调用它运行,全局变量在多线程中会出什么问题我也很难保证,我想保持这个DLL的稳定性和可预见性是最重要的,上一个帖子的内容请看:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2997058
 
真是搞笑,慢慢上个帖子明明已经说了局部变量象你这样用是不行的,还是非要这么用。
其实是非常简单的一个问题。
procedure test(const Src: PChar
Dest: PChar
MaxLen: Cardinal = 0)
stdcall;
var
S: string;
begin
S := Src;
if Length(S) &gt
0 then
begin
S := StringReplace(S, '/', '//', [rfReplaceAll]);
S := StringReplace(S, '''', '/''', [rfReplaceAll]);
S := StringReplace(S, '"', '/"', [rfReplaceAll]);
end;
if MaxLen = 0 then
StrCopy(Dest, S)
else
StrLCopy(Dest, S, MaxLen);
end;
主程序调用之前,要先分配好Dest指针内存。
 
但是,在VB中是没有什么指针和内存概念的,VB中定义一个字符串变量时,只是给该变量分配一个零长度的字符串空间,而且在本例中,VB也无法知道DLL会返回多大长度的字符串,那么是不是说,VB不能使用这种方法吗?
但是VB调用API或C++的DLL,却并没有要自己先分配好返回字符串内存大小的要求啊, 而且在VB中,一个string的字符串变量其实也是一个指针,那么如何解释这种情况呢?
 
你事先分配StrLen(str)长度就可以了
 
局部变量的办法我已经在上篇贴出来了, 你有没有看过阿
 
借花一用:
同题,不过是用在VF中的
function i1(ii:integer
var ss:pchar):integer;stdcall;
begin
if ii=1 then
ss:='ccc'
else
ss:='ddd'
end;
vf的声明是:declare short i1 in test.dll integer ii, string @aa
调用:
aa=space(255)
=i1(1,@aa)
?aa
aa的值是:?Y口
会变的
在PB里也是这样
我没在VB里试

是什么原因???带不带VAR都一样
 
to tseug:你的方法我用过了,输出的字符串一样是错误的,要丢字符,事实上,用局部变量的方法我试过很多次,唯一不出错的情况就是我在顶楼中说用fastansireplace的方法,其它的结果全是错误的,比如下面这个方法,结果也是错误的:
procedure strToJs(const str: PChar
var outStr: PChar)
stdcall;
var strn: string;
begin
strn := str;
if Length(strn) &gt
0 then
begin
strn := StringReplace(strn, '/', '//', [rfReplaceAll]);
strn := StringReplace(strn, '''', '/''', [rfReplaceAll]);
strn := StringReplace(strn, '"', '/"', [rfReplaceAll]);
end;
GetMem(outStr, Length(strn)+1);
strPCopy(outStr, strn);
end;
 
丢不丢字符,你要在Delphi中进行测试,这样可以确定是不是DLL的问题。
“但是VB调用API或C++的DLL,却并没有要自己先分配好返回字符串内存大小的要求啊, 而且在VB中,一个string的字符串变量其实也是一个指针,那么如何解释这种情况呢?”
你调用一下GetClassName函数试试:
Private Declare Sub GetClassName Lib "user32.dll&quot
Alias "GetClassNameA&quot
(ByVal hwnd As Long, ByVal str As String, ByVal ilen As Long)

Dim ilen As Long
Dim str As String
Dim hwnd As Long

ilen = 255
hwnd = 1901532
'str = "dsfdfsjldsfadsfla;dsfajl&quot
//
GetClassName hwnd, str, ilen
MsgBox str
 
lichengbin你好,我知道你是Delphi高手,VB也很厉害,但针对你的代码(有点小错误,我改了如下):
procedure strToJs(const Src: PChar
var Dest: PChar
MaxLen: Cardinal=0)
stdcall;
var S: string;
begin
S := Src;
if Length(S)>0 then
begin
S := StringReplace(S, '/', '//', [rfReplaceAll]);
S := StringReplace(S, '''', '/''', [rfReplaceAll]);
S := StringReplace(S, '"', '/"', [rfReplaceAll]);
end;
StrPLCopy(Dest, S, MaxLen);
end;
然后在VB中我们来简单做一个测试代码:
Private Declare Sub strToJs Lib "Unit1.dll&quot
(ByVal inStr As String, outStr As String, ByVal strLen As Long)
Private Sub Command1_Click()
Dim str As String, strOut As String
str = "我的电脑"
strOut = Space(20)
strToJs str, strOut, 20
MsgBox Trim(strOut) &amp
"太老了"
End Sub
然后你运行一下,看看是什么结果!
 
在DELPHI中测试是正常,一点问题都没有
 
那么请你测试一下下面的代码是否正确!
library StrJS;

uses SysUtils;

procedure strToJs(Src, Dest: PChar
MaxLen: Cardinal = 0)
stdcall;
var
S: string;
begin
S := Src;
if Length(S) &gt
0 then
begin
S := StringReplace(S, '/', '//', [rfReplaceAll]);
S := StringReplace(S, '''', '/''', [rfReplaceAll]);
S := StringReplace(S, '"', '/"', [rfReplaceAll]);
end;
StrPLCopy(Dest, S, MaxLen);
end;

exports
strToJs;

begin
end.

Private Declare Sub strToJs Lib "StrJS.dll&quot
(ByVal Src As String, ByVal Dest As String, ByVal MaxLen As Long)

Private Sub Command1_Click()
Dim str As String, strOut As String
Dim pos As Long

str = "我的电脑"
strOut = Space(20)
strToJs str, strOut, 20
pos = InStr(1, strOut, Chr(0))
strOut = Left(strOut, pos - 1)
strOut = strOut &amp
"太老了"
MsgBox strOut
End Sub
问题原因在哪里呢?呵呵
Delphi、C/C++中PChar字符串的结束符0,很不幸,在VB中string类型与PChar并不完全等同的,...........
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
775
import
I
I
回复
0
查看
626
import
I
后退
顶部