我正在尝试在Delphi 2007中执行导入的函数:
function getOfficialCardNumber(): WideString ; cdecl; external 'idcapp.dll';
但几秒后(在调试配置中)它停在这里:
77BD37D6 C6055562C17700 mov byte ptr [$77c16255],$00
并说:
Debug Output: Heap block at 027D4FF8 modified at 027D5009 past requested size of 9 Process PreglediZaDom.exe (23672)
提到的函数是用C ++(Visual Studio)编写的
我尝试将WideString更改为PWideString等,但没有成功。有谁知道什么是问题?
在类似的应用程序中,但用VB6编写,他们给了我这个函数来转换字符串:
Public Function pisBstrToString(bstr) As String
Dim bArray() As Integer
Dim longArray() As Long
Dim str As String
Dim i As Integer
bArray = pisStringToBArray(bstr)
longArray = pisBArrayToLongArray(bArray)
str = ""
For i = 1 To UBound(longArray)
If longArray(i) > 0 And longArray(i) < 256 Then
str = str & Chr(longArray(i))
Else
str = str & pisLongToUnichar(longArray(i))
End If
Next i
pisBstrToString = str
End Function
我现在知道用C ++编写的函数是这样导出的:
BSTR _stdcall getOfficialCardNumber()
答案 0 :(得分:1)
VB6不支持cdecl
,仅支持stdcall
。就在那里,你在Delphi代码中使用了错误的调用约定,导致调用堆栈管理不善。
Delphi的WideString
类型是COM BSTR
字符串的包装,VB6确实用于它自己的字符串 - 但不是外部DLL函数的String
返回值!即使VB6期望/接受BSTR
作为输出,DLL函数也将返回BSTR
cpu寄存器中的EAX
指针,就像大多数其他返回类型一样。但是,在将EAX
作为返回类型处理时,Delphi不使用WideString
。它作为隐藏的var
参数传递。看到
Why can a WideString not be used as a function return value for interop?了解更多详情。
如果DLL函数返回char*
指针,则必须将函数返回值声明为PAnsiChar
:
function getOfficialCardNumber(): PAnsiChar; stdcall; external 'idcapp.dll';
否则,如果它返回wchar_t*
指针 1 ,则必须将函数返回值声明为PWideChar
:
function getOfficialCardNumber(): PWideChar; stdcall; external 'idcapp.dll';
无论哪种方式,您还有另一个问题需要处理 - 谁拥有指向的内存,以及如何释放它? Delphi不能直接释放DLL返回的内存,那么内存是如何分配的呢?
如果在DLL中静态,则根本不需要释放它。
如果动态,哪个内存管理器分配了它?
如果它是DLL内部的内存管理器,那么DLL在完成使用后必须导出一个单独的函数来接收指针,以便可以使用相同的内存管理器释放它。
如果是OS提供的内存API(LocalAlloc()
/ GlobalAlloc()
,IMalloc.Alloc()imalloc
/ CoTaskMemAlloc()
等),那么Delphi代码可以直接调用相应的记忆释放功能(LocalFree()
/ GlobalFree()
,IMalloc.Free()
/ CoTaskMemFree()
等)。
1 :如果发生实际上是BSTR
指针,则需要将返回的指针传递给SysFreeString()
使用它完成。