Pinvoke错误堆栈不平衡 - lzo解压缩C函数

时间:2013-06-19 12:06:13

标签: c# .net pinvoke dllimport lzo

我知道这个问题已被问过几次,如下: (Unbalanced Stack!

但是我使用的是用ANSI C编写的开源DLL LZO 2.0.3。有关DLL的信息在这里: LZO download the source

我的C#程序是一个下载程序,它与服务器建立TCP套接字,该服务器通过TCP连接发送LZO压缩数据包。

.NET中有几个LZO端口,例如:

http://lzohelper.codeplex.com/

http://wallaceturner.com/lzo-for-c

http://lzo-net.sourceforge.net/ [过时]

http://www.codeproject.com/Articles/16239/Pure-C-MiniLZO-port

http://powerawarebt2.googlecode.com/svn/trunk/PowerAwareBT/CompactFramework/ADOHelper/SRC_Helper/MiniLZO.cs

与.NET中的多个LZO和miniLZO端口不同,它们有自己的解压缩功能,根据数据包的最后4位确定目标缓冲区的长度,我的数据包包含一个未压缩的8字节头,如下所示:

Header:
  4 bytes - number of packets [bytes] in the incoming packet
  4 bytes - length of decompressed data packet

Data:
  X bytes - what needs to be decompressed 

这是我的代码片段:

Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
client.Connect(remoteEP);
while (true)
//infinite loop since the client keeps receiving data 
{
    m = client.Receive(inStream);
    //instream is previously defined as a byte of 100000
    //this is followed by code copying the m bytes received from inStream
    //to a new byte original
    short iNoOfPackets = 0;
    short myPacketLength = 0;
    //this is followed by code to extract the two variables above
    //from the first 8 bytes of original (or inStream)
    if (m > 8)
    {
        compressedData = new byte[m - 8];
        Array.Copy(original, 8, compressedData, 0, compressedData.Length);
    }
    byte[] destination = new byte[myPacketLength];
    try
    {
        int destlen = (int)myPacketLength;
        r = lzo1x_decompress_safe(compressedData, (int)compressedData.Length, destination, ref destlen, null);
    }
    catch (Exception ex)
    ....

使用PInvoke的函数调用如下:

[DllImport(LzoDLL64bit)]
private static extern int lzo1x_decompress_safe(byte[] src, int src_len, byte[] dst, ref int dst_len, byte[] wrkmem);

我在64位Windows Server 2008计算机上使用Visual Studio 2012 Express。

正如本文标题所示,我收到的错误是:

    Additional Information: A call to PInvoke function 'My.Program::lzo1x_decompress_safe' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

调试控制台产生以下输出:

    4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    'MyProgra.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
    The program '[6852] Myprogram.vshost.exe: Managed (v4.0.30319)' has exited with code -1073741510 (0xc000013a).

如果你看一下LZO 2.0.3库的源代码 - 特别是文件lzo1x.h,它说:

/* safe decompression with overrun testing */
LZO_EXTERN(int)
lzo1x_decompress_safe   ( const lzo_bytep src, lzo_uint  src_len,
                            lzo_bytep dst, lzo_uintp dst_len,
                            lzo_voidp wrkmem /* NOT USED */ );

我的问题很简单 - 如何解决错误?作为一名对C语言知之甚少的新手C#程序员,我对PInvoke不熟悉,并且非常感谢您可能拥有的任何具体建议。为可能重复的问题/场景提前道歉。

1 个答案:

答案 0 :(得分:1)

默认的CallingConvention是StdCall,但似乎LZO使用Cdecl,因此您需要将其添加到DllImport声明中。以前版本的.NET运行时可能已经无声地修复了该问题,但在.NET 4.0及更高版本中,当指定了错误的调用约定时会发生这种情况。

http://msdn.microsoft.com/en-us/library/ee941656%28v=VS.100%29.aspx#core

  

为了提高与非托管代码的互操作性能,平台调用中的错误调用约定现在导致应用程序失败。在以前的版本中,编组层将这些错误解决了堆栈。

此外,最后一个参数是void *但由于它未被使用,您可以将类型指定为IntPtr并传递IntPtr.Zero,它是C / C ++等效于NULL。

[DllImport(LzoDLL64bit, CallingConvention = CallingConvention.Cdecl)] 
private static extern int lzo1x_decompress_safe(byte[] src, uint src_len, byte[] dst, ref uint dst_len, IntPtr wrkmem);

另外,似乎你编组了uint - > INT。这可能是为了避免以后进行投射,但这可能会导致可能的负值。