我正在使用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))); }
}
}
是否檢查您的代理一直沒有垃圾回收,從而導致非託管代碼調用不再存在的功能? – tinman
我現在正在驗證這一點。該回調適用於約4700個電話,並且始終在該數字附近。我相信如果這是一個GC問題,它不會如此一致。一旦我運行了更多的測試,我會給出更新。 – Lux782