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

时间:2013-11-12 20:50:57

标签: c# c++ .net dll pinvoke

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

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

我试图通过调用期望无符号字符指针的DLL来填充托管字节数组。因为我无法访问第三方来源,所以我无法提供自包含的示例。我将尝试提供尽可能多的代码来显示错误发生的位置。

第三方标题(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的第一个元素的位置。我并不完全确定我是否正确地尝试了这些更改,所以我希望向社区学习。

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

1 个答案:

答案 0 :(得分:3)

您对CAPTURE_ReadStart的声明有两个错误:

  1. 调用约定为stdcall而不是cdecl
  2. 您错过了一个参数。该功能有4个参数。您只定义了3。
  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);