8

希望这是一个简单粗暴的问题,但这表明我缺乏 C++ 专业知识。我是一名 C# 程序员,过去我曾使用 P/Invoke 和其他人的 C++/C dll 进行过大量工作。但是,这一次我决定自己编写一个包装器 C++ dll(非托管),然后从 C# 调用我的包装器 dll。

我立即遇到的问题是我无法定义 p/invoke 可以找到的 C++ 函数。我不知道它的语法是什么,但这是我目前正在尝试的:

extern bool __cdecl TestFunc()
{
  return true;
}

最初我只是有这个,但它也不起作用:

bool TestFunc()
{
  return true;
}

然后在 C# 方面,我有:

    public const string InterfaceLibrary = @"Plugins\TestDLL.dll";

    [DllImport( InterfaceLibrary, CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "TestFunc" ), SuppressUnmanagedCodeSecurity]
    internal static extern bool TestFunc();

一切都可以编译,但是当我执行这个 C# p/invoke 调用时,我得到一个 System.EntryPointNotFoundException: Unable to find an entry point named 'TestFunc' in DLL 'Plugins\TestDLL.dll'。

当然,这在 C++ 端一定是非常简单的东西,我只是不知道它的语法。

4

6 回答 6

13

您将要使用extern "C"以及__declspec(export),如下所示:

extern "C" _declspec(dllexport)  bool TestFunc()
{
    return true;
}

有关完整的详细信息,请参阅MSDN on Marshalling Types

于 2009-10-07T20:21:52.917 回答
7

扩展里德的正确答案。

通过 PInvoke 公开 C++ 函数时可能遇到的另一个问题是使用无效类型。PInvoke 实际上只能支持原始类型和普通旧数据结构/类类型的编组。

例如,假设 TestFunc 具有以下签名

void TestFunc(std::string input);

即使添加 extern "C"__declspec(dllexport)也不足以暴露 C++ 函数。相反,您需要创建一个仅公开 PInvoke 兼容类型的辅助函数,然后调用到主函数中。例如

void TestFunc(const std::string& input) { ... }

extern "C" _declspec(dllexport)  void TestFuncWrapper(char* pInput) {
  std::string input(pInput);
  TestFunc(input);
}
于 2009-10-07T20:35:08.587 回答
1

您必须公开此函数,extern "C"否则名称会被破坏。

于 2009-10-07T20:21:29.143 回答
1

C++ 编译器会修改函数的名称以包含有关参数和返回类型的信息。这称为名称修改。另一方面,C 编译器不会破坏您的函数名称。

您可以使用以下命令告诉 C++ 编译器作为 C 编译器工作extern "C"

extern "C" __declspec(dllexport) bool TestFunc { return true; }

要使用 P/Invoke 从 C# 调用函数,您的名称不能被破坏。因此,您实际上可以将 C 函数导出到 C#。如果您希望在 C++ 中实现该功能,您可以编写一个 C 函数,该函数只调用实现该功能的 C++ 函数。

于 2009-10-07T20:24:22.790 回答
1

做这样的事情:

#define EXPORT extern "C" __declspec(dllexport)

然后使用 EXPORT 关键字声明任何函数,例如 c++ 函数

BOOL getString(TCHAR* string, DWORD size);

会成为

EXPORT BOOL getString(TCHAR* string, DWORD size);

然后是有趣的部分:转到您的 VS 控制台并输入:

dumpbin /EXPORTS <PATH_TO_GENERATED_DLL>

你会看到所有容易导出的函数的名称和序号,然后只需 pInvoking 它们

于 2011-01-26T14:51:24.837 回答
0

使用 Win32 平台和适当的位(例如 x86 或 x64)构建选项构建所有项目。

于 2016-02-24T09:30:21.150 回答