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ì?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top