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

时间:2009-02-21 00:44:11

标签: c# c++ dll pinvoke dllimport

我已经构建了一个C ++ dll,我想用C#代码调用它。我可以调用一个函数,但是当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没有传播到设备。 D'哦!

5 个答案:

答案 0 :(得分:8)

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

我使用

使用简单的C ++ dll尝试了这一点
extern "C" __declspec(dllexport) BOOL Install();
extern "C" __declspec(dllexport) BOOL PPPConnect();

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

当我在dll上执行dumpbin / exports时,我看到了:

转储文件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)

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

答案 1 :(得分:1)

它可能像PPPConnect那样简单,但却被操作系统误解为错误。尝试将InstallPPPConnect同时作为no-ops实现(只需让它们返回TRUE而不做任何其他操作)并查看错误是否仍然存在。如果是这样,请尝试交换它们的导出顺序(仍然是无操作)并查看问题是否与排序(不太可能)或其他相关联。

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

答案 2 :(得分:1)

根据您的描述,安装和PPPConnect仅在名称上有所不同。我想你只需在你的C#应用​​程序中使用旧的.dll版本。没有定义PPPConnect的那个。

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

答案 3 :(得分:0)

很棒的信息,但正如你所说,一切都在这里。尝试安装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正在做一些奇怪的事情。

答案 4 :(得分:0)

使用依赖性walker并打开DLL来验证可用的方法