0

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

但我使用的是开源 DLL,LZO 2.0.3用 ANSI C 编写。关于 DLL 的信息在这里: LZO 下载源代码

我的 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,并且非常感谢您可能提出的任何具体建议。对于可能重复的问题/场景,请提前道歉。

4

1 回答 1

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,它是 NULL 的 C/C++ 等效项。

[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。这可能是为了避免稍后进行强制转换,但这可能会导致可能的负值。

于 2013-06-19T12:31:57.253 回答