繁体   English   中英

如何通过禁用名称管理来启用实例方法

[英]How to PInvoke an Instance Method by disabling 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包装函数并调用它们。
  2. 创建一个C ++ / CLI混合模式层,用于发布包装本机类的托管类。

在我看来,选项2更可取。

您可以使用comment / linker #pragma将/EXPORT开关传递给链接器,该链接器允许您重命名导出的符号:

#pragma comment(linker, "/EXPORT:GetAnswer=?GetAnswer@a@@UAEHXZ")

不幸的是,这并不能解决您使用依赖或其他工具查找损坏名称的需要。

您不必禁用实际包含有关如何声明函数本身的大量信息的受损名称,它基本上表示函数名称被去除后的函数的整个签名。 我知道你已经发现了一个单词,而另一个答案已被标记为正确的答案。 我在下面写的是我们如何使它按照您的期望工作。

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

如果将“#OrdinalNumber”替换为GetAnsweer的实数序号,例如“#1”,它将按您的需要工作。

您可以只考虑EntryPoint属性与我们传递给GetProcAddress的函数名称相同,您可以在其中传递函数名称或函数的序号。

您调用C ++类的非静态函数成员的方法确实是正确的,并且正确使用了此调用,这正是调用约定在C#P / Invoke中发挥作用。 这种方法的问题是你必须查看DLL的PE信息,导出函数信息并找出你想要调用的每个函数的序号,如果你有大量的C ++函数可以调用,你可以想要自动化这样一个过程。

来自问题作者:我实际上采用的解决方案

我结束了与C风格的功能封装了实例方法和采用的一个实例作为一个参数去。 这样,如果类继承自继承,则会调用正确的虚方法。

我故意选择不使用C ++ / CLI,因为它只是另一个要管理的项目。 如果我需要在类上使用所有方法,我会考虑它,但我真的只需要这个序列化类数据的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM