c# - 使用第三方 DLL 对 PInvokeStackImbalance 进行故障排除

标签 c# c++ .net dll pinvoke

我在对尝试 PInvoke 第三方 DLL 时发生的 PInvokeStackImbalance 异常进行故障排除时遇到困难。根据我下面的描述,有人可以建议后续的故障排除步骤吗?

我花了一些时间研究这里与 PInvokeStackImbalance 异常相关的线程,并在 MSDN 上进行了一些粗略的阅读。编码和使用非托管代码对我来说仍然相对较新,因此我可能遗漏了一些明显的东西。也有可能答案就在第三方 DLL 中。目标之一是确定我是否应该关注我的代码或 DLL,以找出问题发生的位置。

我试图通过调用需要无符号字符指针的 DLL 来填充托管字节数组。由于我无法访问第三方源,因此我无法提供独立的示例。我将尝试提供尽可能多的代码来显示错误发生的位置。

第三方 header (C++):

    API.h
    #define PUCHAR      unsigned char *
    #define INT32       long
    #define UINT32      unsigned long
    _declspec( dllexport ) INT32 _stdcall CAPTURE_ReadData(INT32 devID, UINT32 address, UINT32  Num_Bytes,PUCHAR pucBuffer); 
    _declspec( dllexport ) INT32 _stdcall CAPTURE_ReadStart(INT32 devID, UINT32 start_adr, UINT32 byte_len);
    _declspec( dllexport ) INT32 _stdcall CAPTURE_ReadEnd(INT32 devID );

这是我尝试调用这些函数的代码

C#:

namespace CameraTest
{
  class CameraInterface : IDisposable
  {
    // Interface
    [DllImport("API.dll")]
    public static extern int CAPTURE_ReadStart(int devId, uint startAdr, uint byteLen);

    [DllImport("API.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int CAPTURE_ReadData(int devId, uint numBytes, 
        IntPtr pucBuffer);

    [DllImport("API.dll")]
    public static extern int CAPTURE_ReadEnd(int devId);   

    //Code 
    const int BUFFSIZE = 2592*1944;
    private byte[] _buffer = new byte[BUFFSIZE]; // Array to contain image / byte data
    const int devId = 0; // Device Id 
    uint bytesToRead = 2592 * 1944;  // Shortcut assignement. Verified other code
                                   // assigns value correctly
    const uint startAdr = 0; // Starting address


    // Create a pointer that we will later copy its data to the _buffer once 
    // it has been assigned values.

    IntPtr pBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(_buffer[0]*_buffer.Length));

    // This function returns successfully with _status = 0
    // It initializes the data capture device and specifies how many bytes will be 
    // read

    _status = CAPTURE_ReadStart(devId, startAdr, bytesToRead);
    if (_status < 0 ) { // Error handling }

    // The ReadData function reads the number of bytes specified from the device
    // and assigns the byte array and is supposed to set pBuffer to point to it. 
    // This ReadData function throws the PInvokeStackImbalance exception.
    // If I continue in debug mode, _status gives an error value which indicates
    // the primary dll has an issue with communicating with a secondary dll. 
    // My thought is that the error code has to do with me not specifying the
    //  correct interface for CAPTURE_ReadData. 

    _status = CAPTURE_ReadData(devId, bytesToRead, pBuffer);
    if (_status < 0 ) { // Error handling }

    // Code never reaches this point due to thrown exception

    _status = CAPTURE_ReadEnd(devId);
     if (_status < 0 ) { // Error handling }

    // Marshal pBuffer to _buffer

    // IDisposable stuff and freeing allocated items that need it

  }
}

我尝试将 ReadData 的调用约定更改为 StdCall,尝试将签名从 IntPtr 更改为 [in,out] byte[] 以及尝试使用 Marshal.UnsafeAddrOfPinnedArrayElement 传递 _buffer 第一个元素的位置。然而,我并不完全确定我是否正确地尝试了这些更改,因此我希望向社区学习。

我仍在研究我做错了什么导致了异常。我知道我发送的函数调用内容与调用期望的内容之间存在基本的不匹配,但我不完全理解这意味着什么或如何调试或解决该问题。任何人都可以提供的指导将不胜感激。如果我遗漏了任何重要信息,请告诉我。

最佳答案

您的 CAPTURE_ReadStart 声明有两个错误:

  1. 调用约定是 stdcall 而不是 cdecl
  2. 您错过了一个参数。该函数有 4 个参数。您只定义了 3 个。

应该是:

[DllImport("API.dll")]
public static extern int CAPTURE_ReadData(int devId, uint address,
    uint numBytes, IntPtr pucBuffer);

事实上,字节数组可能更容易编码为byte[]:

[DllImport("API.dll")]
public static extern int CAPTURE_ReadData(int devId, uint address,
    uint numBytes, byte[] pucBuffer);

关于c# - 使用第三方 DLL 对 PInvokeStackImbalance 进行故障排除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19939610/

相关文章:

c# - MySql "Select Where"和 C#

c# - Entity Framework CTP4 和复合键

c++ - 通过网页执行程序(如 Steam)

C++ 我可以根据给单个构造函数的参数创建派生类而不是 bass 类吗?

c# - 使用 ValidateCredentials 重复失败的登录尝试是否会导致用户被锁定?

c# - 如何使用 IronRuby 的 ErrorListener

c# - 使用http post方法在c#中将数据发布到php网站

c++ - 为什么在使用命名空间 foo 时不能在 sub::bar 中使用 foo::bar 函数?

.Net 消费 Web 服务 : Identical types in two different services

c# - 在没有回发的情况下重置 ASP.NET 中的页面