c# - 如何通过禁用 Name Mangling 来调用实例方法

标签 c# c++ pinvoke name-mangling

给定 foo.dll 中的以下 c++ 类

class a{
  private:
    int _answer;

  public:
    a(int answer) { _answer = answer; }
    __declspec(dllexport) int GetAnswer() { return _answer; }
}

我想要来自 C# 的 pInvoke GetAnswer。为此,我使用以下方法:

[DllImport("foo.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint= "something")]
public static extern int GetAnswer(IntPtr thisA);

然后我传入一个指向 a 的 IntPtr(我从其他地方得到的,这并不重要)。 CallingConvention = CallingConvention.ThisCall 确保它得到正确处理

这个问题的妙处在于,我知道到目前为止我是对的,因为它已经运行良好!使用 Depends.exe,我可以看到“GetAnswer”导出为 ?GetAnswer@a @@UAEHXZ(或者类似的东西——关键是它的名字被破坏了)。当我将损坏的名称插入 EntryPoint 的“某物”时,一切都很好!我花了大约一天的时间才意识到使用 Depends.exe,所以我将把它留在这里以帮助有类似问题的任何人。

我真正的问题是:有没有什么方法可以在 GetAnswer 上禁用 C++ 名称修改,这样我就不需要将修改后的名称作为我的入口点。将经过修饰的名称放在其中似乎可能会中断,因为我对名称修饰的理解是,如果编译器发生变化,它可能会发生变化。对我想要 pInvoke 的每个实例方法使用 Depends.exe 也是一件很痛苦的事情。

编辑:忘记添加我尝试过的内容: 我似乎无法将 extern "C"放在函数声明中,尽管我可以将其粘贴在定义中。这似乎没有帮助(当你想到它时很明显)

我能想到的唯一其他解决方案是一个 c 风格的函数,它包装了实例方法并将 a 的实例作为参数。然后,禁用该包装器上的名称重整并 pInvoke 那个。不过,我宁愿坚持我已经拥有的解决方案。我已经告诉我的同事 pInvoke 很棒。如果我必须在我们的 c++ 库中放置特殊函数来使 pInvoke 工作,我会看起来像个白痴。

最佳答案

您不能禁用 C++ 类方法的重整,但您可以使用 /EXPORT 或 .def 文件以您选择的名称导出该函数。

但是,您的整个方法很脆弱,因为您依赖于实现细节,即 this 作为隐式参数传递。更重要的是,导出类的各个方法是一种痛苦的方法。

将 C++ 类暴露给 .net 语言的最明智策略是:

  1. 创建平面 C 包装函数并 p/调用它们。
  2. 创建一个 C++/CLI 混合模式层,用于发布包装 native 类的托管类。

我认为选项 2 更可取。

关于c# - 如何通过禁用 Name Mangling 来调用实例方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17579003/

相关文章:

c# - 从外部线程关闭模式对话框 - C#

返回 char* 的 C 函数的 C# pinvoke

.net - 为什么 SendMessageTimeout 不更新环境变量?

c# - DbTransaction 类和关于 C# 中的接口(interface)

c# - Nancy:从 "/"提供静态内容(例如 index.html)?

c++ - 使用 Midi 库解析事件并存储在 Vector C++ 中

c++ - x86/C++ - 指向指针 : Const being violated by compiler? 的指针

wpf - 如何从 WPF 应用程序打开 MFC 对话框?

c# - 如何覆盖 C# 中两个字符串的一般比较

c++ - boost::mpi 在具有相同标签的多个 isend/irecv 传输中抛出 MPI_ERR_TRUNCATE