Delphi写的DLL在VB中调用出错!(100分)

  • 主题发起人 主题发起人 xiao_ping
  • 开始时间 开始时间
X

xiao_ping

Unregistered / Unconfirmed
GUEST, unregistred user!
DLL中有一个函数如下:
function SmallToBig (szCurrency,StrRet:pchar):word
stdcall;
在Delphi中调用如下:
procedure TForm1.Button1Click(Sender: TObject);
var
//mystr:pchar;
myStr:string;
myRet:word;
begin
// getmem(myStr,255);
setlength(mystr,255);
myRet:=SmallToBig(pchar(edit1.Text),pchar(myStr));
setLength(mystr,strlen(pchar(mystr)));
label1.Caption:=Mystr;
// freemem(mystr);
end;

能正确返回。
但在VB中调用却出错,想了一个上午还是没有头绪!!!
在VB中的声明如下:
Declare Function SmallToBig Lib "rmb" (ByVal lpBuffer As String, ByVal LpRet As String) As Long
调用如下:
Private Sub Command1_Click()
Dim Str As String
Dim sStr As String
Dim ret As Long

Str = String(MAX_PATH, 0)
Str = Str + Chr(0)
sStr = trim(Text1.Text) + Chr(0)
ret = SmallToBig(sStr, Str)
Str = Left(Str, InStr(Str, Chr(0) - 1))
MsgBox Str
End Sub

我运行这段程序,VB(6.0中文版)就死掉,说是调用Rmb.dll导致.........
 
返回类型不对呀
WORD是16位。
别告诉我说VB中的LONG也是16位哦。
 
我把DLL中的定义改为Integer了,还是同样错误!
 
我知道,把vb声明的String的改成定长字符串你再试试
 
to jzx:
是这样吗?
Declare Function SmallToBig Lib "rmb" (ByVal lpBuffer As String * 255, ByVal LpRet As String * 255) As Long
编译通不过!
 
VB中定义的函数参数类型错误。

传给SmallToBig的字符串可以是 ByVal XXXX as string
从SmallToBig中返回的字符串可以用 ByRef XXXX as byte(能不能用 ByRef XXXX as string我没试过),
在VB调用该函数之前,要给返回字符串的参数分配内存。
请注意ByVal、ByRef的区别。
 
pchar与string不等同,你可以试试其它的字符或字符串类型,我手头没有书,
所以无法说出用哪个类型,如果可以等的话,我会查查资料,你也可以查一下,
返回值word也不完全等同long或integer,试试其他的,另外,分清楚delphi
中的word与vb中的word的区别。
我临时看到此题,无法完全回答。建议你看一下谭浩强写的C程序教程,里面
对类型写的比较详细些,对比一下,可能会有答案的。
VB中对类型的说明与其它的说明不太一样(至少我这样感觉)。各个语言的类型
或有些小差别,请注意一下。
还有,VB中调用DLL的声明似乎不太对,请再看一下实例。(记忆当中似乎不是LIB,而
与DELPHI相仿,用CALL类,请核实一下。)
 
可能是Pchar的问题,你将
function SmallToBig (szCurrency,StrRet:pchar):word
stdcall;
改为
function SmallToBig (szCurrency,StrRet:Pointer):word
stdcall;
试试,我有一个BC++程序,样例:
char Buf[20];
GetInfo(Buf);

delphi:
function GetInfo(pBuf:Pointer):DWORD
stdcall;
此函数返回为:StrCopy (PChar (pBuf),'aabbcc');

VB我不懂,你试试我的方法先!

 
我想我可能近来见“鬼”比较多的原因,今天早上回来
改了一下。
Str = String(MAX_PATH, vbNullChar)
居然成功调用,并成功返回。
再用原先的方法。
Str = String(MAX_PATH, 0)
也成功了!****!!!!!!!!!!!!!ms
等我查查原因。如果有答案贴出来讨论一下!
 
msdn:
修改字符串参数的过程
DLL 过程能够修改作为参数输入的字符串变量的数据。不过,如果修改后的数据超过了原来的长度,过程的修改将越界(越过字符串的结尾),这可能会毁坏其它的数据。

要避免这个问题,一种办法是使字符串参数足够长,从而使 DLL 过程无法超出字符串的尾部。例如,GetWindowsDirectory 过程在第一个参数中返回了 Windows 目录的路径:

Declare Function GetWindowsDirectory Lib "kernel32" _
Alias "GetWindowsDirectoryA" (ByVal lpBuffer As _
String, ByVal nSize As Long) As Long

在调用该过程时,为了安全起见,先使用 String 函数在字符串中填充 255 个空字符(二进制的 0),只要返回的路径少于 255 个字符,就不会出问题:

Path = String(255, vbNullChar)
ReturnLength = GetWindowsDirectory(Path, Len(Path))
Path = Left(Path, ReturnLength)

另一个办法是将字符串定义为定长的:

Dim Path As String * 255
ReturnLength = GetWindowsDirectory(Path, Len(Path))

上述方法的目的只有一个:创建一个固定长度的字符串,使之能够包含过程可能产生的最长的字符串。

注意 Windows API 的 DLL 过程通常不需要超过 255 个字符的字符串缓冲区。尽管这对于其它的许多库也是成立的,为了保险起见,最好参考相应过程的文档。

当 DLL 过程需要内存缓冲区时,既可以使用适合的数据类型,也可以使用字节数据类型的数组。

但好象我就是这样做的,真是莫明其妙!
 
To xiao_ping:
如果要从函数的参数中返回数据,在调用函数之前,必须为该参数分配内存,不管是显式还是隐式,
这是写程序的基本要求,即“在VB调用该函数之前,要给返回字符串的参数分配内存。”
另外,“Windows API 的 DLL 过程通常不需要超过 255 个字符的字符串缓冲区”这一点可能成立,
但对自定义的函数却未必。
“当 DLL 过程需要内存缓冲区时,既可以使用适合的数据类型,也可以使用字节数据类型的数组。”
这一点无疑是正确的,因为内存的使用是线形的。
再次提醒“请注意ByVal、ByRef的区别。”
 
怎么会不行?
把代码贴给你
//Visual Basic
Public Declare Function GetMsg Lib "../dlltest.dll" (ByRef Str As String) As Boolean

Private Sub Command1_Click()
[red]Dim Str As String * 100[/red]

On Error Resume Next
If GetMsg(Str) Then
Text1.Text = Str
Else
MsgBox "error"
End If
End Sub



//Delphi
function GetMsg(var Str: PChar): BOOL
stdcall;
begin
try
StrPCopy(Str,'this is a string from dll');
Result := True;
except
on Exception do Result := False;
end;//except
end;
 
To: jiangyiquan

VB 中的ByRef 同 Delphi 中的 Var 都是相同概念,传址(引用)调用。是吧!

在Delphi中,PChar 指向null 结束的Char字符串的指针,类似于C 的char *
或 vb lpstr 类型。
msdn: LPSTR A 32-bit pointer to a character string.
通常,如果 DLL 过程需要 LPSTR 参数,那么使用 ByVal 关键字。
如果 DLL 需要得到指向 LPSTR 的指针,则使用引用方式传递 Visual Basic 字符串
那 var pchar 是同 ByRef string 是一样吗?
如果是 那pchar 同 ByVal string 呢?
因为我的调用方式成功,jzx 的方式也成功了。
??????

 
多人接受答案了。
 
后退
顶部