2010-01-08 4 views
1

Je rencontre des problèmes pour récupérer une chaîne à partir d'un code c que j'ai écrit. D'abord quelques informations d'arrière-plan généralement non réalisées: Je souhaite recevoir la chaîne lisible par l'utilisateur pour un TSPI TAPI à partir de l'API TAPI. J'ai implémenté une solution TAPI semi-exploitable en utilisant des noms de pilotes correspondants aux chaînes stockées, mais je voudrais changer cela pour travailler sur les identifiants de ligne permanents, car un de nos clients a un PBX (Alcatel) qui refuse de fonctionner autrement .recevoir des chaînes via interop

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 écrit 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, cela 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 le voir en 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 (This is recommended by MS). J'ai également mis le type de retour à void sur le mince espoir que cela affecte également quelque chose (voir this article mono semi utile pour une explication pseudo scientifique 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 que le StringBuilder est en quelque sorte perverti et est fourni au code non managé comme pointeur nul. Une exception AccessViolationException est ensuite lancée en C#.

Qu'est-ce qui ne va pas?

en supprimant le paramètre long aide. Je suis capable d'ajouter "abc" à mon paramètre DeviceName en C. Je veux cependant cette longue variable! Qu'est-ce que je fais de mal ou de dérangeant de manière à forcer un crash en ayant ce long paramètre là?

Répondre

1

Sur les plates-formes 32 bits long est 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# et C intlong ont la même largeur sur 32 plates-formes bits.

1

Le C++ long est de 32 bits, le C# long est de 64 bits, n'est-ce pas? Par conséquent, vous devez utiliser un int pour le premier paramètre.

+0

pas besoin de. StringBuilder est automatiquement défini comme [In, Out] –

+0

Et maintenant vous êtes allé et a dérouté tout le monde en éditant votre réponse à quelque chose de complètement différent, ce qui rend mes commentaires absurdes :) –

+0

Désolé à ce sujet. Mais tout le monde voit qu'il a été édité tout le monde peut vérifier l'histoire ...;) – Lucero

2

Je veux cette variable longue mais

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

Questions connexes