2

我在尝试 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 的第一个元素的位置。但是,我不完全确定我是否正确尝试了这些更改,因此我希望向社区学习。

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

4

1 回答 1

3

您的声明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);
于 2013-11-12T20:54:04.707 回答