【问题标题】:FatalExecutionEngineError during DllImportDllImport 期间的 FatalExecutionEngineError
【发布时间】:2014-05-22 21:52:42
【问题描述】:

这是我得到执行错误的那一行:

NimbieImportedFunctions.BS_Robots_Connect(
    out robotCount, out robotIDs, out robotTypes, out robotReadys);

还有 DllImport 本身:

[DllImport("BSRobots20.DLL", CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 BS_Robots_Connect(
    out int nRobotCount,
    out int[] pnRobotIDS,
    out int[] pnRobotTypes,
    out bool[] pbRobotReadys);

从头文件中:

extern "C" __declspec(dllexport) DWORD BS_Robots_Connect(
        int *nRobotCount,
        int *pnRobotID,
        int *pnRobotType,
        bool *pnRobotReady
    );
//
//  Description:
//      Function to connect all online robots.
//
//  Parameters:
//      nRobotCount  [out]  Pointer to an integer that receives the number of robots.
//      pnRobotID    [out]  Pointer to an array of integer that receives the robot IDs.
//      pnRobotType  [out]  Pointer to an array of integer that receives the robot types.
//
//  Return:
//      BS_ROBOTS_OK     If the function succeeds with no error.
//      BS_ROBOTS_ERROR  If the function fails with any error occurred.
//
///////////////////////////////////////////////////////////////////////////////

我得到的错误:

The runtime has encountered a fatal error. The address of the error was 
at 0x72c4898e, on thread 0xdf0. The error code is 0xc0000005. 
This error may be a bug in the CLR or in the unsafe or non-verifiable portions
of user code. Common sources of this bug include user marshaling errors for
COM-interop or PInvoke, which may corrupt the stack.

有时,我也会收到 AccessViolationException。我非常不确定发生了什么。请帮帮我!

【问题讨论】:

  • 这可能是错误的约定或没有正确检索入口点。 DLL 也可能存在错误或以某种方式不兼容。
  • 还有哪些信息可以帮助解决这个问题?这是一个导入的API函数,所以我有头文件等!
  • 这些信息的含义相当开放。 AccessViolation 是一个跟踪,可能意味着 DLL 未加载或加载不正确,因此您尝试访问应用程序可见/分配区域之外的无效地址。我建议搜索The error code is 0xc0000005。这可能意味着什么。事实是问题不在 CLR 托管代码中(要么没有正确链接,要么 DLL 的某些其他要求不正常)。您可以使用反汇编来跟踪问题,但您将跳转到真实的、非托管的汇编代码中。
  • 尝试使用 StdCall 并明确指向 EntryPoint。我对 __declspec 有这样的问题,它被 CLR 扭曲了,或者 C 和 C++ 不同(不记得确切)。
  • @Rolice outref 关键字对于方法的参数是否重要?

标签: c# c++ pinvoke dllimport


【解决方案1】:

您的 p/invoke 不正确。也许应该这样写:

[DllImport("BSRobots20.DLL", CallingConvention = CallingConvention.Cdecl)]
public static extern uint BS_Robots_Connect(
    out int nRobotCount,
    [Out] int[] pnRobotIDS,
    [Out] int[] pnRobotTypes,
    [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1)]
    [Out] bool[] pbRobotReadys
);

nRobotCount 应该是 ref 而不是 out 是合理的。根据您是否需要将信息传递给函数来确定。你确定pbRobotReadys 是一个数组吗?如果没有,请使用out boolref bool

所以也许你需要的是:

[DllImport("BSRobots20.DLL", CallingConvention = CallingConvention.Cdecl)]
public static extern uint BS_Robots_Connect(
    ref int nRobotCount,
    [Out] int[] pnRobotIDS,
    [Out] int[] pnRobotTypes,
    [MarshalAs(UnmanagedType.U1)]
    out bool pbRobotReadys
);

要深入了解这一点,您需要进一步研究文档,并可能参考您可以找到的任何 C++ 示例代码。

您需要在调用函数之前分配数组。我不能从这里告诉你究竟需要如何分配数组。大概您知道它们需要多大。


为什么你的版本错了?好吧,考虑这个问题的方法是 C# 数组已经是一个引用。通过使用out 传递数组,您正在传递一个指向指针的指针。换句话说,一级间接太远了。

另一种思考方式是,您要求非托管代码创建托管数组。这显然是它无法做到的。

【讨论】:

  • pnRobotReady 必须是 byte[] 或使用 [MarshalAs],默认编组是 32 位(如 BOOL),但本机代码通常使用单个字节。不太清楚它是一个数组顺便说一句。 ref 在 nRobotCount 上的几率非常高。
  • 哇...我非常不确定为什么其中任何一个有效,我肯定需要进一步阅读 p/invoke 等。谢谢您的帮助!
  • @HansPassant 谢谢。我现在试图掩盖其中的一些不确定性。
猜你喜欢
  • 2011-07-23
  • 1970-01-01
  • 1970-01-01
  • 2017-05-07
  • 1970-01-01
  • 1970-01-01
  • 2014-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多