Marshaler personnalisé pour PInvoke avec std :: ssortingng

Clause de non-responsabilité: question Noob C ++ / CLI

J’essaye d’utiliser un PInvoke sur une DLL C ++ qui a un std :: ssortingng dans la signature. Pour l’instant, je viens de tester: mon objective est de transmettre une chaîne à la DLL native et de la renvoyer.

L’exportation native ressemble à ceci:

#define NATIVE_CPP_API __declspec(dllexport) NATIVE_CPP_API void hello_std(std::ssortingng inp, char* buffer) { const char* data = inp.data(); strcpy(buffer, data); } 

J’essaie de l’invoquer normalement, avec un marshaler personnalisé:

 [DllImport("native_cpp.dll", EntryPoint = "?hello_std@@YAPADV?$basic_ssortingng@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z", CallingConvention = CallingConvention.Cdecl)] private static extern void hello_std( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(clr_wrapper.ssortingng_marshaler))] Ssortingng inp, SsortingngBuilder buffer); static void Main(ssortingng[] args) { var buffer = new SsortingngBuilder(100); hello_std("abcdefg", buffer); Console.WriteLine(buffer); Console.ReadLine(); } 

Le clr_wrapper.ssortingng_marshaler personnalisé spécifié ici, clr_wrapper.ssortingng_marshaler , est un ICustomMarshaler dans un projet C ++ / CLI et est conçu pour ICustomMarshaler entrée System::Ssortingng et la convertir en std::ssortingng natif. Mon implémentation MarshalManagedToNative est un coup de poignard dans le noir. J’ai essayé plusieurs choses, mais c’est ma meilleure hypothèse:

 IntPtr ssortingng_marshaler::MarshalManagedToNative( Object^ ManagedObj ) { Ssortingng^ val = (Ssortingng^) ManagedObj; size_t size = (size_t)val->Length; char* ptr = (char*) Marshal::SsortingngToHGlobalAnsi(val->ToSsortingng()).ToPointer(); std::ssortingng * str = new std::ssortingng(ptr, size); IntPtr retval = (IntPtr) str; return retval; } 

Malheureusement, lorsque j’essaie de l’exécuter, un appel PInvoke déclenche une AccessViolationException .

Qu’est-ce que je fais de mal ou est-ce toute cette entreprise mal conçue?


Première édition, liste complète

1. Application console C #

 class Program { static void Main(ssortingng[] args) { var buffer = new SsortingngBuilder(100); hello_std("abcdefg", buffer); Console.WriteLine(buffer); Console.ReadLine(); } [DllImport("native_cpp.dll", EntryPoint = "?hello_std@@YAXV?$basic_ssortingng@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PAD@Z", CallingConvention = CallingConvention.Cdecl)] private static extern void hello_std( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(clr_wrapper.ssortingng_marshaler))] [In] Ssortingng inp, SsortingngBuilder buffer ); } 

2. Projet de DLL C ++ natif “native_cpp”

native_cpp.h

 #ifdef NATIVE_CPP_EXPORTS #define NATIVE_CPP_API __declspec(dllexport) #else #define NATIVE_CPP_API __declspec(dllimport) #endif #include  NATIVE_CPP_API void hello_std(std::ssortingng inp, char* buffer); 

native_cpp.cpp

 #include "native_cpp.h" void hello_std(std::ssortingng inp, char* buffer) { const char* data = inp.data(); strcpy(buffer, data); } 

3. Projet C ++ / CLI “clr_wrapper”

clr_wrapper.h

 #pragma once using namespace System; using namespace System::Runtime::InteropServices; namespace clr_wrapper { public ref class ssortingng_marshaler : public ICustomMarshaler { public: ssortingng_marshaler(void); virtual Object^ MarshalNativeToManaged( IntPtr pNativeData ); virtual IntPtr MarshalManagedToNative( Object^ ManagedObj ); virtual void CleanUpNativeData( IntPtr pNativeData ); virtual void CleanUpManagedData( Object^ ManagedObj ); virtual int GetNativeDataSize(); static ICustomMarshaler ^ GetInstance(Ssortingng ^ pstrCookie) { return gcnew ssortingng_marshaler(); } private: void* m_ptr; int m_size; }; } 

clr_wrapper.cpp

 #include "clr_wrapper.h" #include  using namespace clr_wrapper; using namespace System::Text; ssortingng_marshaler::ssortingng_marshaler(void) { } Object^ ssortingng_marshaler::MarshalNativeToManaged( IntPtr pNativeData ) { return Marshal::PtrToSsortingngAnsi(pNativeData); } IntPtr ssortingng_marshaler::MarshalManagedToNative( Object^ ManagedObj ) { Ssortingng^ val = (Ssortingng^) ManagedObj; size_t size = (size_t) val->Length; char* ptr = (char*) Marshal::SsortingngToHGlobalAnsi(val->ToSsortingng()).ToPointer(); std::ssortingng * str = new std::ssortingng(ptr, size); m_size = sizeof(str*); m_ptr = (void*) str; IntPtr retval = (IntPtr) str; return retval; } void ssortingng_marshaler::CleanUpNativeData( IntPtr pNativeData ) { //Marshal::FreeHGlobal(pNativeData); delete (std::ssortingng*) m_ptr; } void ssortingng_marshaler::CleanUpManagedData( Object^ ManagedObj ) { } int ssortingng_marshaler::GetNativeDataSize() { return m_size; } 

Fin première édition

Si vous pouvez créer la dll C ++ / CLI avec exactement la même version du compilateur, le même emballage, l’alignement des membres de la classe, la convention d’appel, la liaison CRT, des options de bibliothèque telles que _ITERATOR_DEBUG_LEVEL, la configuration de débogage / édition, etc. avec la DLL native, vous pouvez transmettre une classe STL. sur la limite de la DLL . et une fonction wrapper comme celle-ci peut fonctionner:

 public ref class Wrapper { void hello_std_managed(Ssortingng^ inp, array^ buffer) { IntPtr inpCopy = Marshal::SsortingngToHGlobalAnsi(inp); std::ssortingng inpNative(static_cast(inpCopy.ToPointer())); pin_ptr nativeBuffer = &buffer[0]; hello_std(inpNative,nativeBuffer); Marshal::FreeHGlobal(inpCopy); } } 

Cependant, puisqu’il s’agit d’un gros IF, vous pouvez demander à l’auteur de la DLL de modifier la signature de la méthode en types primitifs C / COM tels que char * ou BSTR. C’est mieux de cette façon, la DLL est maintenant consommable, quelle que soit la langue ou la configuration de construction.