2011-12-12 4 views
5

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))); } 
    } 
} 
+0

Avete controllato che il delegato non è stato garbage collection, causando il codice non gestito per chiamare una funzione che non esiste più? – tinman

+0

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

risposta

1

Sembra un problema di perdita di memoria. Sai se è necessario liberare memoria relativa agli oggetti ricevuti (come LogEntry)?

Ho uno scenario simile in cui ho bisogno di liberare la memoria di ogni oggetto passato al mio metodo di callback.

Rivedere il codice C# e provare a identificare ciò che si sta facendo in modo diverso da c/C++.

+0

Ho postato una risposta perché non posso ancora commentare. Se ottengo 5 voti in questa risposta, sarò in grado di commentare :-) –

+0

Non è richiesta alcuna pulizia per la struttura LogEntry. – Lux782

0

Hai provato a specificare esplicitamente convenzione di chiamata

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

Ho provato anche questo. – Lux782