2013-03-07 7 views
8

la funzione nella DLL C si presenta così:PInvoke char * nella DLL C gestita come stringa in C#. Problema con caratteri nulli

int my_Funct(char* input, char* output); 

devo chiamare questo da C# app. Lo faccio nel modo seguente:

...DllImport stuff... 
public static extern int my_Funct(string input, string output); 

La stringa di input è perfettamente trasmessa al DLL (ho la prova visibile di quello). L'output che la funzione compila sebbene sia sbagliato. Ho dati hexa in esso, come:

3F-D9-00-01 

Ma purtroppo tutto ciò che è dopo i due zeri è tagliato, e solo i primi due byte vengono in C# app. Succede, perché (immagino) tratta come carattere null e lo prende come la fine della stringa.

Qualche idea su come potrei liberarmene? Ho provato a specificarlo come IntPtr invece di una stringa, ma non so cosa farmene dopo. Ho cercato di fare dopo:

byte[] b1 = new byte[2]; 
Marshal.Copy(output,b1,0,2); 

2 dovrebbe essere normalmente la lunghezza della matrice di byte. Ma ottengo tutti i tipi di errori: come "L'intervallo richiesto si estende oltre la fine dell'array". o "Tentativo di leggere o scrivere memoria protetta ..."

Apprezzo qualsiasi aiuto.

+0

(1) Le stringhe C# sono più larghe di un carattere; sono 2 caratteri piuttosto che 1. (2) Un carattere * restituito da questa funzione non avrà la struttura aggiuntiva necessaria per essere una stringa C# valida (anche se era della larghezza corretta). –

+0

È necessario leggere su COM Interop e P/Invoke per imparare come eseguire questa azione. Fallo e richiamalo con qualsiasi domanda tu abbia con quel materiale. –

+0

Il marshaller pinvoke supporta solo stringhe C. Chiaramente non è una stringa C quando ha byte che contano dopo lo 0. È quindi un byte []. Ma con l'hangup significativo, nessuno può capire come * molti * byte siano rilevanti. Questa funzione è molto difficile da usare anche dal codice C, che non migliora quando la si fa ruotare. Faresti meglio a sistemarlo. Usa MarshalAs.SizeConst se la lunghezza è prevedibile. –

risposta

12

Il marshalling della stringa di output non è corretto. L'utilizzo di string nella dichiarazione p/invoke è appropriato quando si passano dati da gestiti a nativi. Ma non puoi usarlo quando i dati fluiscono nell'altra direzione. Invece è necessario utilizzare StringBuilder. Come questo:

[DllImport(...)] 
public static extern int my_Funct(string input, StringBuilder output); 

Poi allocare la memoria per l'uscita:

StringBuilder output = new StringBuilder(256); 
//256 is the capacity in characters - only you know how large a buffer is needed 

e poi si può chiamare la funzione.

int retval = my_Funct(inputStr, output); 
string outputStr = output.ToString(); 

D'altra parte, se questi parametri hanno caratteri nulli in loro, allora non si può schierare come stringa. Questo perché il marshaller non eseguirà il marshalling di nulla oltre il null. Invece è necessario effettuare il marshalling come array di byte.

public static extern int my_Funct(
    [In] byte[] input, 
    [Out] byte[] output 
); 

che soddisfa le vostre dichiarazione C.

Poi assumendo l'ANSI codifica di convertire la stringa di input a un array di byte come questo:

byte[] input = Encoding.Default.GetBytes(inputString); 

Se si desidera utilizzare una codifica diversa, è ovvio come farlo.

E per l'output è necessario allocare l'array. Supponendo che è la stessa lunghezza l'ingresso che si dovrebbe fare questo:

byte[] output = new byte[input.Length]; 

E in qualche modo la funzione C ha avuto modo di conoscere la lunghezza degli array. Lascerò quel pezzetto a te!

Poi si può chiamare la funzione

int retval = my_Funct(input, output); 

E poi di convertire l'array di uscita in una stringa C# si utilizza ancora una volta la classe Encoding.

string outputString = Encoding.Default.GetString(output); 
+0

Grazie mille! La versione [Out] byte [] ... funziona !!! – user2124150