Sto lavorando con una risorsa non gestita con C#. La risorsa espone un callback che può essere configurato per determinati eventi che potrebbero verificarsi all'interno dell'hardware. Per accedere alle funzioni non gestite faccio la seguente:Chiamata non gestita causando overflow dello stack
[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);
ho prima installare il callback con un riferimento a un metodo che segue il delegato IntFuncPtr. Allora lascio andare l'hardware a fare le sue cose. Dopo circa 4700 chiamate del callback, l'applicazione si arresta in modo anomalo. Il callback funziona bene se scrivo il codice in c/C++ ma posso replicarlo rimuovendo __stdcall dalla mia funzione di callback. Da C# non riesco a rilevare l'errore che indica che l'applicazione sta morendo nella risorsa non gestita. Con l'applicazione c/C++ posso vedere che lo stack trabocca senza __stdcall.
ho pensato che il delegato potrebbe non funzionare con la convenzione di chiamata stdcall così ho provato quanto segue:
[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);
Questa, inoltre, non ha funzionato.
Per riepilogare, ho un callback non gestito che richiede un puntatore a funzione di una funzione definita come __stdcall. Se il puntatore della funzione è su una funzione non __stdcall, lo stack aumenta e trabocca. Sto tentando di utilizzare la richiamata in C# usando DllImport e un delegato UnmanagedFunctionPointer con la convenzione di chiamata stdcall. Quando faccio questo l'applicazione C# si comporta come un'applicazione c/C++ che usa una funzione non __stdcall.
Come posso far funzionare tutto in C#?
Edit 1:
Ecco il metodo definizione & informazioni struttura nativa comprese le informazioni C# struttura.
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))); }
}
}
Avete controllato che il delegato non è stato garbage collection, causando il codice non gestito per chiamare una funzione che non esiste più? – tinman
Lo sto verificando ora. Il callback funziona per circa 4700 chiamate ed è costantemente attorno a quel numero. Credo che se fosse un problema di GC non sarebbe così coerente. Darò un aggiornamento una volta che avrò eseguito qualche altro test. – Lux782