che ricevono le stringhe attraverso Interop
-
19-09-2019 - |
Domanda
Sto avendo difficoltà ad ottenere una stringa di ritorno da un po 'di codice C che ho scritto.
Per prima cosa un po 'in generale unrealated sfondo Informazioni: Vorrei ricevere la stringa leggibile all'utente un TAPI TSP dal API TAPI. Ho implementato una soluzione TAPI praticabile semi basandosi sulla corrispondenza nomi dei driver per stringhe memorizzate, ma vorrei cambiare questo a lavorare sulla linea permanant id, invece, come uno dei nostri clienti ha un PBX (Alcatel), che si rifiuta di lavorare in altro modo .
In C, ho definire la funzione nel mio file di intestazione come:
__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName);
La funzione è scritto nel seguente modo:
__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName)
{
//tapi code here...
//copy the string to DeviceName
wcscpy(DeviceName, (wchar_t*)((char *)devCaps + devCaps->dwLineNameOffset));
}
Come già detto, questo finirà per fare qualcosa di utile, ma per ora sarò felice se abc è collocato nel mio wchar_t * / StringBuilder e posso vedere che in C #.
In C # io definisco la funzione come:
[DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)]
static extern void GetDeviceName(long DeviceId, StringBuilder DeviceName);
definisco DeviceName come StringBuilder perché una stringa è immuatable e voglio il DeviceName da impostare in C ( Questo è consigliato da MS ). Ho anche impostare il tipo di ritorno alla void
sulla speranza sottile che che colpisce anche qualcosa (vedi questo semi articolo mono utile per una pseudo parziale spiegazione scientifica).
E lo chiamano così:
StringBuilder name = new StringBuilder();
name.EnsureCapacity(100);
long n = 0;
GetDeviceName(n, name);
Allego il mio debugger al processo in esecuzione, impostare un punto di interruzione, e notare nel codice C che in qualche modo lo StringBuilder è perverso ed è previsto per il codice non gestito come un puntatore nullo.
Un AccessViolationException viene successivamente gettato in C #.
Che cosa è andato storto?
rimuovere il parametro tempo aiuta. Sono in grado di aggiungere "abc" per il mio parametro DeviceName in C. Io voglio quella variabile lungo però! Che cosa sto facendo di sbagliato o sconvolgente in modo da forzare un crash avendo così a lungo parametro lì?
Soluzione
32 bit piattaforme long
è 8 byte (64 bit) di larghezza in NET e 4 byte (32 bit) di larghezza nel codice nativo. È necessario modificare il vostro P / Invoke metodo come questo:
[DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)]
static extern void GetDeviceName(int DeviceId, StringBuilder DeviceName);
In questo modo, C # int
e C long
hanno la stessa larghezza di 32 bit piattaforme.
Altri suggerimenti
Voglio che molto tempo variabile ma
Poi si dovrebbe definire il parametro in C come long long
. Come Lucero sottolineato, lungo in C ++ è di 32 bit, mentre un lungo in C # è di 64 bit. Quindi, se si passa un valore a 64 bit in cui la funzione C si aspetta un valore a 32 bit, la funzione legge l'extra 32 bit come il secondo parametro, che si traduce, ovviamente, in un indirizzo sbagliato per il buffer ...
Il long
C ++ è di 32 bit, il C # long
è di 64 bit, non è vero? avresti dunque necessario utilizzare un int
per il primo parametro.