2011-04-19 46 views
2

我收到了一些C/C++代碼,用於另一個項目。我把它放到一個DLL中,然後從C++測試工具中調用DLL。它工作得很好,並且與代碼只是一個函數調用時的結果相匹配。從C++調用的C++ DLL應用程序工作,從C#控制檯調用應用程序有堆棧溢出

但是,我然後試圖讓DLL從C#應用程序工作。我轉換了測試工具,並進行了DLL調用,但我收到了一個堆棧溢出異常。

在C++中我說:

#include "proxy_rec_02.h" 
#pragma comment(lib,"proxy_rec_02.lib") 

而且這樣調用該函數:

proxy_rec_main(simtime,mx$gl,mz$gl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,outputs); 

其中報頭包含:

void DLL_EXPORT proxy_rec_main(double simtime, double mx$gl, double mz$gl, double ry, int start_dig, 
           int blytarg_on, double blytarg, int spread_on, int last_call, double *outputs); 

在C#中我使用:

using System.Runtime.InteropServices; 

[DllImport("proxy_rec_02.dll")] 
unsafe static extern void proxy_rec_main(double simtime, double mxSgl, double mzSgl, double ry, int start_dig,   
            int blytarg_on, double blytarg, int spread_on, int last_call, ref double[] outputs); 

用一個函數調用是這樣的:

proxy_rec_main(simtime,mxSgl,mzSgl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,ref outputs); 

的DLL功能在多次調用for循環。 C++代碼運行得很好。 C#代碼會引發堆棧溢出錯誤。我向proxy_rec_main函數添加了一些調試狀態,並且它在函數返回之前似乎擊中了每條語句。但它似乎拋出了從函數返回的錯誤。任何見解都會受到歡迎。

謝謝。

回答

1

ref雙數組似乎有問題, 向它添加[MarshalAs]並傳遞IntPtr,而不是雙數組。

.net數組不是指針,因爲它們在C++中。

將c#方法標記爲私有, 用使用Marshal.Copy將公共方法傳回的指針轉換爲.net數組。

實施例用於在.NET分配時轉移陣列:

[DllImport(EntryPoint="ExternalMethod"] 
private static void ExternalMethodInvoke(
    [MarshalAs(UnmanagedType.SysInt), In] IntPtr); 

public void ManagedWrapper(ref double[] array) 
{ 
    IntPtr unmanagedMem = Marshal.AllocHGlobal(1000); 
    Marshal.Copy(array, unmanagedMem, 0, 1000); 
    ExternalMethodInvoke(unmanagedMem); // use try finally for freeing 
    Marshal.Copy(unmanagedMem, array, 1, 1000); 
    Marshal.FreeHGlobal(unmanagedMem); 
} 

實施例在本機中分配時轉移陣列:

[DllImport(EntryPoint="ExternalMethod"] 
private static void ExternalMethodInvoke(
    [MarshalAs(UnmanagedType.SysInt), Out] out IntPtr); 

[DllImport(EntryPoint="ExternalDeleteArray"] 
private static void ExternalDeleteArrayInvoke(
    [MarshalAs(UnmanagedType.SysInt), Out] out IntPtr); 

public void ManagedWrapper(ref double[] array) 
{ 
    IntPtr unmanagedMem; 
    ExternalMethodInvoke(out unmanagedMem); // use try finally for freeing 
    Marshal.Copy(unmanagedMem, array, 1, 1000); 
    ExternalDeleteArrayInvoke(unmanagedMem); 
} 

如果C#側分配陣列,不要忘記分配和釋放在C#中。 (使用元帥的(de)分配h全局方法。)

在C++分配中,調用C++方法來解除分配。

+0

你的意思是'IntPtr'? – 2011-04-19 23:11:51

+0

該死的自動更正:-) – 2011-04-19 23:19:46

+0

所以我不太清楚如何進行這些更改。我已經將數組編組到一個非託管數組並且有一個IntPtr。但我不知道如何改變界面來接受它。 – 2011-04-19 23:26:32

2

[DllImport]聲明中缺少CallingConvention屬性。在C聲明中沒有使用__stdcall的跡象,因此可能需要CallingConvention.Cdecl。這確實可能導致SO,堆棧不會被清理。

Debug + Windows +在通話前後註冊並注意ESP寄存器的值,它應該是相同的。如果您禁用了PInvokeStackImbalance管理調試器警告,那麼一定要重新打開它。忽略此警告不是一個好主意。

並調試本機代碼,驗證傳遞的參數值。有太多的論點,其中一個不好的聲明足以讓人發現腳。

+0

這通常是類成員方法的一個問題。 – 2011-04-20 01:46:22

0

假設膠水代碼是正確的,它可能就是DLL函數佔用了很多堆棧。我自己遇到了類似的情況,事實證明,在C++堆棧上分配了一些非常大的對象。當從本機代碼調用時,在調用之前僅使用了一點點堆棧,因此堆棧上有足夠的剩餘空間。當從託管代碼調用時,很多堆棧已經被佔用,因此沒有足夠的空間。如果你看看導致溢出的C++函數,你可能會發現它試圖把一個大對象放在堆棧上。

相關問題