1

我是使用经典 C++ 的 PInvoke 的新手,昨天我问了这个问题:在 .NET 中使用 Windows API 函数

我现在创建了一个非常简单的 C++ 程序,如下所示:

#include <iostream>
#include <stdio.h>
#include <string>
extern "C" __declspec(dllexport) int hello()
{
  //printf ("Hello World!\n");
  return 1;
} 

然后我使用以下命令编译 DLL:g++ -c mydll.cpp 然后使用以下命令创建共享库:g++ -shared -o mydll.dll mydll.o,然后将 mydll.dll 复制到 C:\Windows\syswow64 .

然后我创建了一个新的 VB.NET 项目并创建了以下代码:

    Imports System.Runtime.InteropServices
Public Class TestPlatformInvoke
    <DllImport("mydll.dll", CallingConvention:=CallingConvention.Cdecl)> _
    Public Shared Function hello() As Integer
    End Function
    Public Sub New()
        Try
            Dim test As Integer = hello() 'Line 6 ex As Exception
            'I don't swallow exceptions
            MsgBox("test")
        Catch ex As Exception

        End Try
    End Sub
End Class

应用程序在调用 hello() 后退出。它不会抛出异常。

我正在尝试了解它是如何工作的。我没有任何 C++ 商业经验;只有大学的学术经验。

这是 mydll.dll 的 Dependancy Walker 的图像。

在此处输入图像描述

4

2 回答 2

2

如果您使用 Visual Studio 调试程序并将 DLL 包含在您的项目中(Visual Studio 2012 Express Edition 允许在解决方案中包含不同类型的项目),您可以设置“允许本机代码调试”选项以自动将调试器从VB.NET 到 C++,当您从 DLL 中 P/Invoke 函数时。

这是一个有效的概念证明。只需解压缩,在 Visual Studio 中打开,构建并运行。您可以将此程序与您的项目进行比较并发现差异,从而使您的代码失败。

我猜,您实际上并没有从 DLL 中导出函数。仅仅将它包含在 DLL 的代码中可能是不够的:检查,使用Dependency Walker其他链接)程序从 DLL 中导出了哪些函数。例如,我必须添加以下声明:

__declspec(dllexport) int __stdcall Test() { ... }

并另外为导出的函数的名称创建 .def 文件而不进行修饰。

尝试修改您的 DLL 源代码并将函数声明更改为:

extern "C" __declspec(dllexport) int hello()
{
  return 1;
}  
于 2013-03-01T11:02:55.430 回答
2

Declare是 VB6 遗留的。您应该使用 p/invoke 和 DllImport 属性。

<DllImport("mydll.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Shared Function hello() As Integer
End Function

有很多方法可能会失败。可能由于 32/64 位不匹配,DLL 没有加载。此外,您的调用约定不匹配。您的 DLL 将使用 cdecl,但您的 VB 代码使用 stdcall。上面的 pinvoke 解决了这个问题。

最严重的是,您的函数似乎没有从 DLL 中导出。那肯定会失败。使用 Dependency Walker 确定您的函数是否已导出。我对 g++ 不太熟悉,所以你必须弄清楚如何使用 GNU 工具链导出你的函数。但要注意名称装饰和名称修饰。您可能需要注意如何导出函数,以便以所需的名称导出它。

于 2013-03-01T11:11:42.873 回答