【问题标题】:Exporting functions from C++ dll to C# P/Invoke将函数从 C++ dll 导出到 C# P/Invoke
【发布时间】:2010-10-08 23:29:43
【问题描述】:

我已经构建了一个我想从 C# 代码调用的 C++ dll。我可以调用一个函数,但是当 C# 代码尝试加载 dll 时,另一个会引发异常。

标题如下所示:

extern "C" __declspec(dllexport) BOOL Install();
extern "C" __declspec(dllexport) BOOL PPPConnect();

这会生成一个 dll,导出表有点混乱(名称字段中的 foo = foo 是什么意思?):

File Type: DLL

Section contains the following exports for PPPManager.dll

00000000 characteristics
499F44F0 time date stamp Fri Feb 20 16:04:00 2009
    0.00 version
       1 ordinal base
       2 number of functions
       2 number of names

ordinal hint RVA      name

      1    0 000078E4 Install = Install
      2    1 000079DC PPPConnect = PPPConnect

我的 P/Invoke 声明如下所示:

[DllImport("PPPManager.dll")]
private static extern bool Install();

[DllImport("PPPManager.dll")]
private static extern bool PPPConnect();

对 Install 的调用毫无例外地返回,但是当我调用 PPPConnect 时,我收到 MissingMethodException -“在 PInvoke DLL 'PPPManager.dll' 中找不到入口点 'PPPConnect'。”

我已经尝试从 Install 函数声明中删除 extern 和 declspec 指令,这样 PPPConnect 是唯一导出的函数,这仍然不允许我调用 PPPConnect。

我也尝试过按序号进行 DllImport;这与按名称调用的结果相同 - 安装返回,但 PPPConnect 抛出异常“找不到入口点 '#2'...”。

互操作日志给出:

[pinvokeimpl][preservesig]
bool  invivodata.Common.System.IPAQUtils::Install();
BOOLEAN (I1_WINBOOL_VAL) Install();

JIT ERROR FOR PINVOKE METHOD (Managed -> Native): 
[pinvokeimpl][preservesig]
bool  invivodata.Common.System.IPAQUtils::PPPConnect();
BOOLEAN (I1_WINBOOL_VAL) PPPConnect();

这远远超出了我的专业领域,因此欢迎提出任何建议或想法。

谢谢, 保罗

编辑: 事实证明,这段代码确实有效;问题在于最新的 dll 未传播到设备。哦!

【问题讨论】:

标签: c# c++ dll pinvoke dllimport


【解决方案1】:

很好的信息,但正如您所提到的,这里一切都井井有条。尝试安装适用于 Windows 的调试工具并运行:

kd -z \path\to\PPPManager.dll -y \path\to\PPPManager.pdb -c "x pppmodule!*"

为了更好地转储符号表;这也是盲目的,但你也可以试试:

extern "C" 
{
    __declspec(dllexport) BOOL Install();
    __declspec(dllexport) BOOL PPPConnect();
};

以防 __declspec 做一些奇怪的事情。

【讨论】:

    【解决方案2】:

    这可能很简单,例如 PPPConnect 以一种被操作系统误解的方式失败。尝试将InstallPPPConnect 都实现为无操作(只需让它们返回TRUE 而不做任何其他事情)并查看错误是否仍然存在。如果是这样,请尝试交换它们的导出顺序(仍然是无操作),看看问题是否与排序有关(不太可能)或其他原因。

    您也可以使用图形工具depends 来确认 DLL 的导出表是什么样的,但我怀疑问题出在那些方面。

    【讨论】:

    • 这些是隔离真正问题的好主意。您还可以尝试添加第三个函数,看看那个函数会发生什么。
    【解决方案3】:

    根据您的描述,Install 和 PPPConnect 仅在名称上有所不同。我猜你只是在你的 C# 应用程序中使用旧的 .dll 版本。一个没有定义 PPPConnect。

    声明看起来是正确的(据我在没有来源的情况下判断)。

    【讨论】:

      【解决方案4】:

      您是否在 dll 项目中使用 .def 文件来导出这些函数?如果是这样,请将其删除并重试。这只是一个猜测,因为当您执行 extern "C" declspec(dllexports) 时,您的导出看起来不是应该的。

      我用一个简单的 C++ dll 尝试了这个

      extern "C" __declspec(dllexport) BOOL Install();
      extern "C" __declspec(dllexport) BOOL PPPConnect();
      

      和一个使用您的 PInvoke 声明的简单 C# 应用程序它运行良好。

      当我对我看到的 dll 进行转储/导出时:

      文件 PPPManager.dll 的转储

      文件类型:DLL

      部分包含 PPPManager.dll 的以下导出

      00000000 characteristics
      499F6C2D time date stamp Fri Feb 20 20:51:25 2009
          0.00 version
             1 ordinal base
             2 number of functions
             2 number of names
      
      ordinal hint RVA      name
      
            1    0 000110CD Install = @ILT+200(_Install)
            2    1 00011069 PPPConnect = @ILT+100(_PPPConnect)
      

      请注意,在我的情况下,导出的名称是不同的。

      【讨论】:

      • 最后事实证明我没有复制最新的 dll,因为我误解了 VS 中的“将文件添加到项目”命令的作用。您尝试精简 dll 的想法是我需要去解决这个问题的种子。谢谢!
      【解决方案5】:

      使用依赖遍历器并打开您的 DLL 以验证可用的方法

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-17
        • 1970-01-01
        • 2013-05-31
        • 1970-01-01
        • 1970-01-01
        • 2010-11-07
        • 1970-01-01
        • 2012-09-06
        相关资源
        最近更新 更多