【问题标题】:How to natively call this function from a DLL?如何从 DLL 本地调用此函数?
【发布时间】:2012-06-22 08:56:58
【问题描述】:

我使用 DLL 导出查看器尝试查找此 DLL 中的函数,我找到了一个函数列表,它是:

public: int __thiscall CSTVdsDisk::GetPartitionCount(void);

问题在 C# 中我无法使用以下任何一种方法调用该函数:

[DllImport("Some.dll", 
           ExactSpelling = true,
           EntryPoint = "GetPartitionCount",
           CallingConvention = CallingConvention.StdCall,
           SetLastError = true)]

或:

[DllImport("Some.dll", 
           ExactSpelling = true,
           EntryPoint = "CSTVdsDisk::GetPartitionCount",
           CallingConvention = CallingConvention.StdCall,
           SetLastError = true)]
private static extern int GetPartitionSize();

他们都失败了。有什么我做错了吗?任何人都可以帮忙吗?谢谢!

【问题讨论】:

  • 你可以试试这个 [DllImport("Some.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int GetPartitionSize();
  • 我现在收到一个无法找到的错误。

标签: c# visual-studio-2010 dllimport


【解决方案1】:

您不能使用 P/Invoke 调用该函数。 __thiscall 调用引用表示该函数是类成员函数。它是CSTVdsDisk 类的成员函数。

为了能够调用该函数,您必须创建CSTVdsDisk 类的实例并从该实例调用GetPartitionCount

您必须在 C++ 或 C++/CLR 中执行此操作,因为您无法在 C# 中创建 C++ 类。另见Create unmanaged c++ object in c#

【讨论】:

  • Windows 允许您将 C++ 构造函数公开为 PE 函数导出,在 C++ 之外使用简直一团糟。
【解决方案2】:

根据名称,这似乎是一个 C++ 类方法。这将使直接从 P/Invoke 调用该方法变得非常困难,原因有两个:

  1. 你需要找到“真实”的名字;导出查看器显然显示了未修改的名称,但实际的 C++ 函数名称看起来更难看,如 @0GetPartitionCount@CSTVdsDisk@@QPBAEXA 或类似名称。您可能需要使用较低级别的工具(例如 dumpbin)来查找该名称。
  2. 你需要伪造“thiscall”风格的调用;这意味着您需要传递一个 C++ 类 的实例作为第一个参数。只有当 C++ 类构造函数也从 DLL 中公开时,这才会起作用;在这种情况下,您可以调用类构造函数,将结果存储在 IntPtr 中,并将其传递给每个后续调用。 (如果构造函数以 DLL 导出的形式公开,则其损坏的名称将以 ?? 开头,例如 `??0CSTVdsDisk@@QAE@ABV0@@Z

This CodeProject article 向您展示了如何完成大部分操作,但它非常脆弱,所以请期待问题。我强烈建议您寻找具有类似功能的非 C++ 库,或者至少寻找可在 C 代码中使用的库。

【讨论】:

    【解决方案3】:

    在您的本机代码中,确保您正在导出函数。默认情况下,您的函数不会列在 Exports 表中,因此您需要对其进行标记,以便编译器知道导出它。您还需要将该功能标记为 外部“C” 这样编译器就不会破坏名称。

    通常我定义以下宏:

    #define DLLEXPORT extern "C" __declspec(dllexport)
    

    处理所有这些,然后简单地声明导出的函数,例如:

     DLLEXPORT __cdecl int Example(int x, int y)
    

    如果您发现名称仍有问题,请尝试在 dll 上使用免费的 PE 资源管理器程序并检查导出的函数表以获取正确的名称。

    【讨论】:

    • 我没有 DLL 的源代码,我正在尝试使用另一个程序中的函数,以便可以在 c# 下格式化磁盘
    • 在这种情况下,请跳到有关使用 PE 资源管理器获取正确导出名称的部分。 “PE Explorer”试用版heaventools.com/overview.htm可以使用30天,派上用场。
    猜你喜欢
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    相关资源
    最近更新 更多