Question

Je vais avoir du mal à obtenir une chaîne de retour de code C je l'ai écrit.

D'abord quelques informations d'arrière-plan général unrealated: Je souhaite recevoir l'utilisateur chaîne lisible pour un TSP TAPI de l'API TAPI. J'ai mis en place une solution TAPI semi-réaliste reposant sur l'adéquation entre les noms des pilotes à des chaînes stockées, mais je voudrais changer cela fonctionne sur ID de la place la ligne permanant, comme l'un de nos clients a un PBX (Alcatel) qui refuse de travailler d'une autre manière .

En C, je définit la fonction dans mon fichier d'en-tête comme:

__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName);

La fonction est écrite ainsi:

__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));
}

Comme indiqué plus haut, ce qui finira par faire quelque chose d'utile, mais pour l'instant je serai heureux si abc est placé dans mon wchar_t * / StringBuilder et je peux voir que dans C #.

En C # Je définit la fonction comme:

    [DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)]
    static extern void GetDeviceName(long DeviceId, StringBuilder DeviceName);

Je définis DeviceName comme StringBuilder parce qu'une chaîne est immuable pour et je veux DeviceName à régler en C ( Ceci est recommandé par MS ). Je mets également le type de retour à void sur le mince espoir que cela affecte aussi quelque chose (voir cette article mono semi-utiles pour une explication scientifique pseudo partielle).

Et l'appeler ainsi:

StringBuilder name = new StringBuilder();
name.EnsureCapacity(100);
long n = 0;
GetDeviceName(n, name);

Je joins mon débogueur au processus en cours d'exécution, définissez un point d'arrêt, et l'avis dans le code C qui est en quelque sorte le StringBuilder perverti et est fourni au code non managé comme un pointeur NULL.

Un AccessViolationException est ensuite jeté en C #.

Qu'est-ce qui a mal tourné?

suppression du paramètre à long aide. Je suis en mesure d'ajouter « abc » à mon paramètre DeviceName en C. Je veux cette variable longtemps cependant! Qu'est-ce que je fais mal ou dérangeant pour forcer un accident en ayant là ce paramètre longtemps?

Était-ce utile?

La solution

Sur les plates-formes 32 bits long est de 8 octets (64 bits) de large dans .NET et 4 octets (32 bits) de large dans le code natif. Vous devez changer votre méthode P / Invoke comme ceci:

[DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)]
static extern void GetDeviceName(int DeviceId, StringBuilder DeviceName);

De cette façon, C # int et C long ont la même largeur sur les plates-formes 32 bits.

Autres conseils

  

Je veux cette variable longtemps cependant

Ensuite, vous devez définir le paramètre en C comme long long. Comme souligné Lucero, une longue en C ++ est de 32 bits, alors qu'une longue en C # est de 64 bits. Donc, si vous passez une valeur de 64 bits où la fonction C attend une valeur 32 bits, la fonction lit les 32 bits supplémentaires comme second paramètre, ce qui entraîne évidemment une mauvaise adresse pour le tampon ...

c ++ long est de 32 bits, le C # long est de 64 bits, non? Par conséquent, vous aurez besoin d'utiliser un int pour le premier paramètre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top