2012-08-24 4 views
0

Je développe actuellement un complément Excel en C#, et j'utilise interop avec une bibliothèque C++. Les deux sont développés par moi. La bibliothèque C++ n'est pas un composant COM, mais seulement une DLL exportant certaines fonctions.C# Paramètres dllimport shift

J'ai une fonction C#, que je veux passer un nombre et deux chaînes à la fonction C++, et la fonction C++ renvoie une chaîne. Tout d'abord j'ai essayé de retourner une chaîne directement, de sorte que les prototypes ressembler à quelque chose comme

//C# 
[return: MarshalAs(UnmanagedType.LPStr)] 
private static extern string Function([MarshalAs(UnmanagedType.I4)] int number, 
             [MarshalAs(UnmanagedType.LPStr)]string str1, 
             [MarshalAs(UnmanagedType.LPStr)] string str2); 
//C++ 
extern "C" __declspec(dllexport) string Function(int, char*, char*); 

(BTW, je mets déjà la convention d'appel en C# pour cette fonction CDECL)

Puis quand je l'appelle la version C# , et est entré dans le C++ (lors du débogage), j'ai trouvé que les paramètres sont décalés, donc l'entier est la valeur du pointeur vers la première chaîne, et la première chaîne est la deuxième chaîne, et la deuxième chaîne pointe vers un autre . J'ai également vérifié la mémoire, et ai trouvé que les paramètres n'étaient pas passés selon la convention de _cdecl, l'entier était le dernier poussé dans la pile (qui est ok), mais les positions des deux chaînes ont été commutées. Il y a beaucoup d'autres informations que le compilateur a ajoutées, donc je ne veux pas aller plus loin dans ceci.

Cependant, plus tard, je changé la chaîne de retour en tant que paramètre, et les prototypes ressemblent

//C# 
private static extern void Function([MarshalAs(UnmanagedType.I4)]int number, 
            [MarshalAs(UnmanagedType.LPStr)] string str1, 
            [MarshalAs(UnmanagedType.LPStr)] string str2, 
            [MarshalAs(UnmanagedType.LPStr), Out] StringBuilder returnStr); 
//C++ 
extern "C" __declspec(dllexport) void Function(int, char*, char*, string&); 

Et maintenant, les paramètres sont transmis correctement.

Donc, ma première question est: comment cela se passe-t-il? Ma deuxième question est, même en utilisant la deuxième méthode, je n'ai pas pu exécuter le programme correctement, le programme s'est écrasé en retournant de la fonction C++ (en fait dans la fonction C++, la seule chose à faire est d'appeler une autre fonction membre d'une classe, donc la fonction est juste comme un wrapper de la fonction membre, et le programme s'est écrasé exactement lors du retour dans la fonction membre car la fonction warpper appelle simplement la fonction membre, donc je ne peux pas dire où est le problème).

Est-ce que quelqu'un a une idée de comment faire cela? Donc, le point principal de la fonction est de prendre un nombre et deux chaînes et retourner une autre chaîne.

Merci à l'avance.

Répondre

0

look at this article about the usage of stringbuilder in unmanaged code

essayer quelque chose comme ceci:

//C# 
public string Function(int number, string str1, string str2) 
{ 
    StringBuilder sbStr1 = new StringBuilder(str1); 
    StringBuilder sbStr2 = new StringBuilder(str2); 
    StringBuilder sbReturnStr = new StringBuilder(1024); 
    Function(number, sbStr1 , sbStr2 , sbReturnStr , sbReturnStr.Capacity); 
    return sbReturnStr.ToString(); 
} 

//C# p/invoke 
private static extern void Function(int number, StringBuilder str1, StringBuilder str2, StringBuilder returnStrBuffer, int size); 

//C++ 
extern "C" __declspec (dllexport) void __stdcall Function(int number, const char* str1, const char* str2, char* returnStrBuffer, int size) 
{ 
    //fill the returnStrBuffer 
    strncpy(returnStrBuffer, "blablalb", size); //example!! 
} 
+0

Merci, très coincidently j'ai parlé le même blog hier pour une autre question, et je l'ai trouvé cela très utile! J'ai vérifié aussi celui que vous avez fourni, et j'ai découvert que c'est un peu complexe. Je vais essayer la méthode qu'un autre article du même blog mentionné, en utilisant CoTaskMemAlloc. Si cela ne fonctionne pas, je peux essayer cette dernière option. Merci. –

+0

Merci encore pour votre mise à jour! Je viens de lire le blog, et j'ai réalisé que le problème principal du retour de chaîne est le problème du tas. Je vais essayer votre version et celle utilisant AllocHGlobal. –

+0

Salut, codeteq, j'ai essayé votre version, mais j'ai eu une erreur d'assertion, que le tampon est trop petit. J'ai alloué 1024 octets pour le constructeur de chaîne, comment cela pourrait-il arriver? –