我用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行。异常(exception)是:
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参数“返回”字符串,但这似乎在客户端进行了大量工作,我希望使它尽可能简单对客户来说可能的,即看看我是否可以使这种方法起作用。

    最佳答案

    为了在托管代码和非托管代码之间传递数据,必须正确地将其混搭。由于运行时无法知道testfunc()返回的内容,因此您必须通过提供它的声明来告诉它,您可以通过以下方式进行声明:

    <DllImport("testfunc.dll")>
    Private Function testfunc() As String
    

    但是,由于存在许多表示字符串的方式,因此返回类型为String的信息尚不明确。使用MarshalAs -Attribute告诉运行时如何处理返回的值:

    <DllImport("testfunc.dll")>
    Private Function testfunc() As <MarshalAs(UnmanagedType.BStr)> String
    

    阅读有关Interop MarshalingPassing strings between managed and unmanaged code的更多信息。

    关于c - 从VB.net调用DLL会导致堆异常,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52489909/

    10-11 21:16