将函数从 C++ dll 导出到 C# P/Invoke

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/571799/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 08:43:10  来源:igfitidea点击:

Exporting functions from C++ dll to C# P/Invoke

c#c++dllpinvokedllimport

提问by Symmetric

I have built a C++ dll that I would like to call from C# code. I'm able to call one function, but the other throws an exception when the C# code tries to load the dll.

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

The header looks like this:

标题如下所示:

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

This produces a dll with slightly confusing exports table (what does foo = foo mean in the name field?):

这会生成一个带有稍微令人困惑的导出表的 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

My P/Invoke declarations look like this:

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

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

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

The call to Install returns with no exception, but when I call PPPConnect, I get a MissingMethodException - "Can't find an Entry Point 'PPPConnect' in a PInvoke DLL 'PPPManager.dll'."

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

I've tried removing the extern and declspec directives from the Install function declaration, so that PPPConnect is the only function exported, and this still doesn't let me call PPPConnect.

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

I have also tried doing the DllImport by ordinal; this gives the same result as calling by name - Install returns, but PPPConnect throws the exception "Can't find an Entry Point '#2'...".

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

The interop log gives:

互操作日志给出:

[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();

This is well outside my area of expertise, so any suggestions or thoughts would be welcome.

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

Thanks, Paul

谢谢,保罗

edit: It turns out that this code does work; the problem was with the latest dll not being propagated to the device. D'oh!

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

采纳答案by m-sharp

Are you using a .def file in your dll project to export those functions? If so, remove it and try again. This is just a guess because it looks like your exports are not what they should be when you do an extern "C" declspec(dllexports).

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

I tried this out with a simple C++ dll using

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

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

and a simple C# app using your PInvoke declarations and it worked fine.

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

When I did a dumpbin/exports on the dll I saw:

当我对 dll 执行转储/导出时,我看到:

Dump of file PPPManager.dll

文件 PPPManager.dll 的转储

File Type: DLL

文件类型:DLL

Section contains the following exports for PPPManager.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)

Notice that the exported names are different in my case.

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

回答by Ana Betts

Great information, but as you mention, everything is in order here. Try installing Debugging Tools for Windows and running:

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

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

to get a better dump of the symbols table; it's a blind shot as well, but you could also try:

获得更好的符号表转储;这也是一个盲目的镜头,但你也可以尝试:

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

in case the __declspec is doing something weird.

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

回答by vladr

It could be something as simple as PPPConnectfailing in a way that gets misinterpreted by the OS. Try implementing both Installand PPPConnectas no-ops (just have them return TRUEwithout doing anything else) and see if the error persists. If so, try swapping the order in which they are exported (still as no-ops) and see if the problem is tied to ordering (unlikely) or to something else.

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

You can also use the graphical tool dependsto confirm what the DLL's exports table looks like, but I doubt the problem is coming from those quarters.

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

回答by alex2k8

According to your description Install and PPPConnect differs only in names. I guess you simply use old .dll version with your C# application. A one without PPPConnect defined.

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

The declarations looks right (as far as I can judge without sources).

声明看起来是正确的(据我所知,没有消息来源)。

回答by patrick

use dependency walker and open your DLL to verify what methods are available

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