2013-06-19 60 views
0

我知道這個問題已經被問了好幾次,如下: (Unbalanced Stack!的PInvoke錯誤堆棧不平衡 - LZO壓縮C函數

但我使用一個開源的DLL,LZO 2.0.3,用ANSI C.在DLL信息是在這裏: LZO download the source

我的C#程序是建立一個TCP套接字與通過TCP連接發送LZO壓縮包的服務器下載。

有LZO的多個端口在.NET,如:

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,並且非常感謝您可能有的任何具體建議。提前爲可能重複的問題/場景道歉。

+0

這個簽名在下面是不同的 - src_len是uint不是int,dst_len是ref uint不是int,這個不重要,但是最後一個參數wrkmem有註釋/ * NOT USED * /這是void指針這個可以是object或void *在不安全的C#指針,或IntPtr – ahmedsafan86

回答

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類型。這可能是爲了避免以後繼續施放,但這可能會導致可能的負面價值。

+0

謝謝,這是完美的!不僅解決了錯誤,而且還爲我節省了發佈有關負面值(src_len/dest_len)的另一個問題的問題,這些問題一直導致程序崩潰。一旦服務器在幾個小時內恢復在線狀態,我將重新測試。 – John