2010-08-24 3 views
5

Per favore, sopportare me come sono nuovo per lo smistamento. Ho una struttura C e funzione dichiarata come segue:Marshalling di struttura C in C#

typedef struct 
{ 
    char* name; 
    BT_ADDR address; 
} DeviceList; 

extern "C" _declspec(dllexport)DeviceList* PerformQuery(); 

La struttura BT_ADDR è la stessa struttura definita in wsbth2.h in Windows CE SDK. PerformQuery restituisce un puntatore a un array di DeviceList.

Nel mio programma C#, eseguo la seguente dichiarazione PInvoke come seguito

[StructLayout(LayoutKind.Sequential)] 
struct DeviceList 
{ 
    public string name; 
    public ulong address; 
} 

[DllImport("BT_Conn.dll")] 
public extern static DeviceList[] PerformQuery(); 

Dopo aver eseguito il programma di C#, un NotSupportedException viene restituito. Potete gentilmente consigliarmi cosa c'è di sbagliato nel mio marshalling?

risposta

2

Un problema è che il marshaller non è in grado di sapere quanti elementi sono presenti nell'array restituito, il che significa che non può eseguirne il marshalling.

L'API PerformQuery() ha un altro modo per determinare la lunghezza dell'array?

Se è sempre e solo restituisce 1 elemento, si può decidere di farla tornare un IntPtr e quindi utilizzare Marshal.PtrToStructure(), come descritto qui:

p/invoke C function that returns pointer to a struct

Aggiornamento:

Si potrebbe prova un'interfaccia C come questa, cioè una funzione che restituisce il numero di elementi e uno che riempie un array pre-assegnato con gli elementi.

extern "C" _declspec(dllexport) int GetQueryNumItems(); 
extern "C" _declspec(dllexport) void GetQueryItems(DeviceList* items); 

Poi la definizione C# sarebbe simile a questa:

[DllImport("BT_Conn.dll")] 
public extern static int GetQueryNumItems(); 
[DllImport("BT_Conn.dll")] 
public extern static void GetQueryItems([In, Out] DeviceList[] items); 

E si chiamerebbe che in C# come questo:

int numItems = GetQueryNumItems(); 
DeviceList[] items = new DeviceList[numItems]; 
GetQueryItems(items); 

Quando interfaccia C# e C++ di solito trovano più facile creare una libreria di classi C++/CLI, che fornisce un'interfaccia gestita che racchiude il codice C, in una DLL mista. Tuttavia, questa opzione potrebbe non essere disponibile se stai utilizzando CE.

+0

Hi Saxon, L'API PerformQuery() restituirebbe effettivamente più di un elemento. Per determinare la lunghezza dell'array, userei sizeof (* devList)/sizeof (DeviceList) in C++, ma come dovrei dichiarare la mia API per informare il marshaller sul numero di elementi nell'array restituito? –

+0

@CK: In C++ 'sizeof (* devList)' restituirà 'sizeof (DeviceList)', ovvero la dimensione di un singolo oggetto. Se hai un puntatore 'DeviceList *', allora il compilatore non può sapere quanti oggetti ci sono. È solo se si dispone di un array 'DeviceList []' (con un numero fisso di elementi) che sizeof può restituire l'intera dimensione dell'array. –

+0

@CK: A proposito, è PerformQuery() una funzione che stai scrivendo, o è una funzione in una DLL esistente con cui devi interfacciarti? –