我用gcc制作了一个仅包含以下功能的DLL:
#include <windows.h>
BSTR __declspec(dllexport) testfunc(void)
{
return SysAllocString(L"Hello");
}
,它基于this answer末尾的代码。构建命令为gcc -shared -o testfunc.dll main.c -Os -s -loleaut32
。
在使用VS 2017社区的Visual Basic中,我的代码是:
Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic
Imports System
Imports System.Text
Module Module1
<DllImport("testfunc.dll", CallingConvention:=CallingConvention.Cdecl
)>
Private Function testfunc() As String
End Function
Sub Main()
Dim Ret = testfunc()
Console.WriteLine(Ret)
End Sub
End Module
但是,执行程序会导致从testfunc
返回时发生异常。执行永远不会到达Console.WriteLine
行。例外是:
The program '[15188] ConsoleApp1.exe' has exited with code -1073740940 (0xc0000374).
表示堆损坏。我在做什么错了?
我尝试过的事情没有帮助:
__stdcall
并使用Declare Auto Function testfunc Lib "testfunc.dll" Alias "testfunc@0" () As String
而不是<DllImport...>
声明函数可以正常工作的事物:
注意:我知道我可以尝试按照我链接的线程上的建议通过ByRef StringBuilder
参数“返回”字符串,但这似乎在客户端上进行了大量工作,我会希望对客户来说尽可能地简化它,即看看我是否可以使这种方法起作用。
答案 0 :(得分:2)
为了在托管代码和非托管代码之间传递数据,必须正确混搭。由于运行时不知道您的testfunc()
返回什么,因此您必须通过提供它的声明来告诉它,
<DllImport("testfunc.dll")>
Private Function testfunc() As String
但是,由于存在多种表示字符串的方式,因此返回类型为String
的信息尚不明确。使用MarshalAs属性可以告诉运行时如何处理返回的值:
<DllImport("testfunc.dll")>
Private Function testfunc() As <MarshalAs(UnmanagedType.BStr)> String
详细了解Interop Marshaling和Passing strings between managed and unmanaged code。