我必须创建一个VB6应用程序使用的DLL。这个DLL必须提供几个函数,其中一些函数必须返回字符串。
这是VB6声明:
Declare Function MyProc Lib "mylib.dll" (ByVal Param As String) As String
这是mylib.dll
中的Delphi实现存根:
function MyProc(AParam: PChar): PChar; stdcall;
var
ReturnValue: string;
begin
ReturnValue := GetReturnValue(AParam);
Result := ???;
end;
我有什么要回到这里?谁将释放回归PChar字符串的记忆?
编辑:我问的是Delphi 2005(PChar
= PAnsiChar
)
答案 0 :(得分:6)
你需要制作一个BSTR。 VB6字符串实际上是BSTR。在Delphi端调用SysAllocString()并将BSTR返回到VB6端。 VB6方必须调用SysFreeString()来释放字符串 - 它会自动执行。
如果PChar对应于ANSI字符串(您的情况),则必须手动将其转换为Unicode - 请使用MultiByteToWideChar()。有关如何更好地一起使用SysAllocStringLen()和MultiByteToWideChar()的信息,请参阅this answer。
答案 1 :(得分:5)
如果您不想冒着崩溃或内存泄漏的风险,请使用Windows API作为模型来制作API。在那里,API函数通常不分配自己的内存。相反,调用者传递缓冲区并告诉API缓冲区有多大。 API将缓冲区填充到该限制。例如,请参阅GetWindowText
功能。函数不会返回指针,除非它们指向调用者已经提供的内容。相反,调用者自己提供一切,而函数只使用它给出的任何东西。您几乎从未看到输出缓冲区参数没有伴随另一个参数告知缓冲区的大小。
您可以对该技术进行的进一步增强是允许该函数告诉调用者需要多大的缓冲区。当输入指针是空指针时,该函数可以返回调用者需要提供的字节数。调用者将调用该函数两次。
您无需从头开始派生API。使用已经在工作的API作为如何公开自己的API。
答案 2 :(得分:2)
结合Sharptooth和Lars D的答案;是不是已经通过Windows和BSTR分配了宽带?
答案 3 :(得分:2)
我不熟悉Dephi,但是当使用带有非COM DLL和VB6的字符串时,这里有两个主要选项。
选项1.使用“ANSI”字符串。
'DLL routine expecting to be passed pointers to ANSI strings '
'VB6 will allocate and deallocate the strings '
'Its vital that VB6 allocates sufficient space for the return string '
Declare Sub MyProc Lib "mylib.dll" (ByVal Param As String, _
ByVal OutVal As String)
Function DoMyProc(ByVal Param As String) As String
Dim sResult As String
sResult = Space$(255) ' create 255 bytes of space for the return string '
Call MyProc(Param, sResult)
DoMyProc = sResult
End Function
选项二。使用BSTR。
'DLL routine expecting to be passed two BSTRs. It will modify the second one. '
'VB6 "owns" both BSTRs and will deallocate them when it has finished with them. '
Declare Sub MyProc(ByVal lpParam As Long, ByVal lpOutVal As Long)
Function DoMyProc(ByVal Param As String) As String
Dim sResult As String
Call MyProc(StrPtr(Param), StrPtr(sResult))
DoMyProc = sResult
End Function
我还建议在编写要从VB调用的C DLL时查看Microsoft advice。最初与VB5一起发布但仍与VB6相关。
答案 4 :(得分:1)
使用Windows API分配PChar指针指向的内存。然后,VB应用程序也可以在使用后使用Windows API解除分配内存。
答案 5 :(得分:1)
我想说,在这种情况下,分配内存的人也必须释放它。您将遇到其他方案的问题。所以最安全和最干净的方式是:
设置如下:
unit DLL;
interface
uses
SysUtils;
function Execute(const Params: PChar): PChar; stdcall;
procedure FreePointer(const P: PChar); stdcall;
exports Execute;
exports FreePointer;
implementation
function Execute(const Params: PChar): PChar; stdcall;
var
Size: Cardinal;
begin
Size := Calculate the size;
GetMem(Result, Size);
...do something to fill the buffer
end;
procedure FreePointer(const P: PChar); stdcall;
begin
FreeMem(P);
end;
end.
答案 6 :(得分:1)
您不能将PChar作为函数结果返回,但您可以传递一个额外的PChar参数并复制您想要返回此PChar的字符串。注意,VB必须将该字符串分配给所需的大小,然后再将其传递给dll。同样在VB中,参数必须声明为byval param作为字符串AND,它必须与byval一起传递:
param = "aaaaaaaaaaaaaaaaaaaa" ' reserve 20 characters
call myproc(byval param)
调用中的附加byval将使编译器魔术将VB字符串转换为PChar并返回。
(我希望我记得这是正确的,因为我被迫使用VB已经有一段时间了。)