简体   繁体   中英

Troubleshooting PInvokeStackImbalance with a third party DLL

I am having difficulty troubleshooting a PInvokeStackImbalance exception that occurs when I attempt to PInvoke a third party DLL. Based on what I describe below, can someone please suggest next steps for troubleshooting?

I have spent some time researching threads on here relating to the PInvokeStackImbalance exception and have done some cursory reading on MSDN. Marshaling and working with unmanaged code is still relatively new to me, so it is possible I am missing something obvious. It is also possible that the answer lies in the third party DLL. One goal is to determine whether I should be focusing on my code or the DLL to find out where the problem is occurring.

I am attempting to fill a managed byte array through a call to a DLL that expects an unsigned char pointer. Because I do not have access to the third party source, I cannot provide a self contained example. I will try to provide as much code as possible to show where the error is occurring.

Third party 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 );

Here is my code that attempts to call these functions

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

  }
}

I have tried changing the calling convention for ReadData to StdCall, tried changing the signature from IntPtr to [in,out] byte[] as well as trying to pass the location of the first element of _buffer using Marshal.UnsafeAddrOfPinnedArrayElement. I am not entirely sure that I tried those changes correctly, however, so I am hoping to learn from the community.

I am still researching what I am doing wrong to cause the exception. I understand that there is a basic mismatch between what I am sending the function call and what the call expects, but I do not fully understand what that means or how to debug or solve that problem. Any guidance anyone can provide is appreciated. If I am leaving out any crucial information, please let me know.

Your declaration of CAPTURE_ReadStart is wrong on two counts:

  1. The calling convention is stdcall rather than cdecl .
  2. You have missed a parameter. The function has 4 parameters. You have defined only 3.

It should be:

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

In fact the byte array would probably be more easily marshalled as byte[] :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM