2011-12-12 76 views
5

我正在使用C#的非託管資源。該資源公開了一個可以爲硬件中可能發生的特定事件設置的回調。要訪問非託管功能我做到以下幾點:非託管回調導致堆棧溢出

[DllImportAttribute("testDLL.dll", EntryPoint = "InstallCallback")] 
public static extern short InstallCallback(uint handle, byte x, byte y, IntFuncPtr ptr); 

[UnmanagedFunctionPointer(CallingConvention.StdCall)] 
public delegate void IntFuncPtr(uint handle, byte x, byte y, LogEntry info); 

我第一次到下面的IntFuncPtr委託的方法的參考安裝回調。然後我讓硬件去做它的事情。在大約4700次回調調用之後,應用程序崩潰。如果我在c/C++中編寫代碼,回調工作正常,但是我可以通過從回調函數中刪除__stdcall來複制它。從C#我無法捕捉到錯誤,指示應用程序在非託管資源中死亡。使用c/C++應用程序,我可以看到堆棧沒有__stdcall溢出。

我認爲代表可能無法與調用約定STDCALL工作,所以我嘗試了以下內容:

[DllImportAttribute("testDLL.dll", EntryPoint = "InstallCallback")] 
public static extern short InstallCallback(uint handle, byte x, byte y, IntPtr ptr); 

public delegate void IntFuncPtr(uint handle, byte x, byte y, LogEntry info); 

var callBackDelegate = new IntFuncPtr(Callback); 
var callBackPtr = Marshal.GetFunctionPointerForDelegate(callBackDelegate); 
InstallCallback(handle, 1, 1, callBackPtr); 

這也沒有工作。總之,我有一個非託管回調,它需要一個函數指針指向一個定義爲__stdcall的函數。如果函數指針指向非__stdcall函數,那麼堆棧會增長並溢出。我試圖在C#中使用DllImport和一個帶有stdcall調用約定的UnmanagedFunctionPointer委託來使用回調。當我這樣做時,C#應用程序就像一個使用非__stdcall函數的c/C++應用程序。

我怎樣才能完全在C#中工作?

編輯1:

這裏是包括C#結構信息的本地方法定義&結構的信息。

extern "C" __declspec(dllexport) short __stdcall InstallCallback(unsigned int handle, unsigned char x, unsigned char y, LOG_ENTRY info); 

typedef union 
{ 
    unsigned int ul_All; 
    struct 
    { 
    unsigned int ul_Info:24; 
    unsigned int uc_IntType:8; 
    }t; 

    struct 
    { 
    unsigned int ul_Info:24; 

    unsigned int uc_Biu1:1; 
    unsigned int uc_Biu2:1; 
    unsigned int uc_Dma:1; 
    unsigned int uc_Target:1; 
    unsigned int uc_Cmd:1; 
    unsigned int uc_Biu3:1; 
    unsigned int uc_Biu4:1; 
    unsigned int res:1; 
    }b; 
} LOG_ENTRY_C; 

typedef union 
{ 
    unsigned int All; 
    struct 
    { 
    AiUInt32 Index:16; 
    AiUInt32 Res:8; 
    AiUInt32 IntSrc:8; 
    }t; 
} LOG_ENTRY_D; 

typedef struct log_entry 
{ 
    unsigned int a; 
    unsigned int b; 
    LOG_ENTRY_C c; 
    LOG_ENTRY_D d; 
} LOG_ENTRY; 

[StructLayoutAttribute(LayoutKind.Sequential)] 
public struct LogEntry { 
    public uint Lla; 
    public uint Llb; 
    public LogEntryC Llc; 
    public LogEntryD Lld; 
} 

[StructLayoutAttribute(LayoutKind.Explicit)] 
public struct LogEntryC { 
    [FieldOffsetAttribute(0)] 
    public uint All; 
    [FieldOffsetAttribute(0)] 
    public LogEntryCT t; 
    [FieldOffsetAttribute(0)] 
    public LogEntryCB b; 
} 

[StructLayoutAttribute(LayoutKind.Explicit)] 
public struct LogEntryD { 
    [FieldOffsetAttribute(0)] 
    public uint All; 
    [FieldOffsetAttribute(0)] 
    public LogEntryDT t; 
} 

[StructLayoutAttribute(LayoutKind.Sequential)] 
public struct LogEntryCT { 
    public uint bitvector1; 
    public uint IntType { 
     get { return ((uint)((this.bitvector1 & 255u))); } 
     set { this.bitvector1 = ((uint)((value | this.bitvector1))); } 
    } 
    public uint Info { 
     get { return ((uint)(((this.bitvector1 & 4294967040u)/256))); } 
     set { this.bitvector1 = ((uint)(((value * 256) | this.bitvector1))); } 
    } 
} 
[StructLayoutAttribute(LayoutKind.Sequential)] 
public struct LogEntryCB { 
    public uint bitvector1; 
    public uint res { 
     get { return ((uint)((this.bitvector1 & 1u))); } 
     set { this.bitvector1 = ((uint)((value | this.bitvector1))); } 
    } 
    public uint Biu4 { 
     get { return ((uint)(((this.bitvector1 & 2u)/2))); } 
     set { this.bitvector1 = ((uint)(((value * 2) | this.bitvector1))); } 
    } 
    public uint Biu3 { 
     get { return ((uint)(((this.bitvector1 & 4u)/4))); } 
     set { this.bitvector1 = ((uint)(((value * 4) | this.bitvector1))); } 
    } 
    public uint Cmd { 
     get { return ((uint)(((this.bitvector1 & 8u)/8))); } 
     set { this.bitvector1 = ((uint)(((value * 8) | this.bitvector1))); } 
    } 
    public uint Target { 
     get { return ((uint)(((this.bitvector1 & 16u)/16))); } 
     set { this.bitvector1 = ((uint)(((value * 16) | this.bitvector1))); } 
    } 
    public uint Dma { 
     get { return ((uint)(((this.bitvector1 & 32u)/32))); } 
     set { this.bitvector1 = ((uint)(((value * 32) | this.bitvector1))); } 
    } 
    public uint Biu2 { 
     get { return ((uint)(((this.bitvector1 & 64u)/64))); } 
     set { this.bitvector1 = ((uint)(((value * 64) | this.bitvector1))); } 
    } 
    public uint Biu1 { 
     get { return ((uint)(((this.bitvector1 & 128u)/128))); } 
     set { this.bitvector1 = ((uint)(((value * 128) | this.bitvector1))); } 
    } 
    public uint Info { 
     get { return ((uint)(((this.bitvector1 & 4294967040u)/256))); } 
     set { this.bitvector1 = ((uint)(((value * 256) | this.bitvector1))); } 
    } 
} 

[StructLayoutAttribute(LayoutKind.Sequential)] 
public struct LogEntryDT { 
    public uint bitvector1; 
    public uint IntSrc { 
     get { return ((uint)((this.bitvector1 & 255u))); } 
     set { this.bitvector1 = ((uint)((value | this.bitvector1))); } 
    } 
    public uint Res { 
     get { return ((uint)(((this.bitvector1 & 65280u)/256))); } 
     set { this.bitvector1 = ((uint)(((value * 256) | this.bitvector1))); } 
    } 
    public uint Index { 
     get { return ((uint)(((this.bitvector1 & 4294901760u)/65536))); } 
     set { this.bitvector1 = ((uint)(((value * 65536) | this.bitvector1))); } 
    } 
} 
+0

是否檢查您的代理一直沒有垃圾回收,從而導致非託管代碼調用不再存在的功能? – tinman

+0

我現在正在驗證這一點。該回調適用於約4700個電話,並且始終在該數字附近。我相信如果這是一個GC問題,它不會如此一致。一旦我運行了更多的測試,我會給出更新。 – Lux782

回答

1

似乎是內存泄漏問題。你知道是否需要釋放與接收到的對象相關的任何內存(如LogEntry)?

我有一個類似的場景,我需要釋放傳遞給我的回調方法的每個對象的內存。

查看您的C#代碼,並嘗試識別您在做什麼與c/C++不同。

+0

我作爲答覆發佈,因爲我還無法評論。如果我在這個答案中得到5票,我將能夠發表評論:-) –

+0

LogEntry結構不需要清理。 – Lux782

0

你嘗試明確指定調用約定

[DllImportAttribute("testDLL.dll", EntryPoint = "InstallCallback", CallingConvention=CallingConvention.StdCall) ] 
+0

我也試過這個。 – Lux782