How to map C ++ char * to a C # string using P / INVOKE

I am new to C ++. I am calling a C ++ function from C # using PINVOKE and want to return the string as an out parameter. However, I just return an empty string. The int out parameter is working fine.

Import

[DllImport ( @"UnamanagedAssembly.dll", CharSet = CharSet.Ansi)] public static extern int Activate(ref int numActivated, StringBuilder eventsActivated); extern "C" __declspec(dllexport) int Activate(int *p_NumActivated, char *p_EventsActivated) {return Activation::GetInstance()->Activate(p_NumActivated, p_EventsActivated);} 

Calling my C ++ function from C #:

 int numActivated = 0; StringBuilder eventsActivated = new StringBuilder(); int status = Activate(ref numActivated, eventsActivated); 

C ++ function:

 int Activation::Activate(int *p_NumActivated, char *&p_EventsActivated) { char *pTemp = "Hello"; p_EventsActivated = pTemp; *p_NumActivated = 1; return 0; } 
+4
source share
4 answers
 [DllImport ( @"UnamanagedAssembly.dll", CharSet = CharSet.Ansi)] public static extern int Activate( ref int numActivated, [MarshalAs(UnmanagedType.LPStr)]StringBuilder eventsActivated); 
+2
source
 StringBuilder eventsActivated = new StringBuilder(5); 

instead

 StringBuilder eventsActivated = new StringBuilder(); 
+3
source

P / Invoke is only supported for C. YMMV interfaces if you are trying to get it to talk to C ++ constructs. In this case, you will need to find out what exactly the C ++ compiler translated the link to, since C ++ compilers can implement this in any way.

If you want to be able to P / Invoke this, but don’t want to use pointer semantics on the call site, you can do something like:

 int Activation::Activate(int *p_NumActivated, char **p_EventsActivated) { return Activate(p_NumActivated, *p_EventsActivated); } int Activation::Activate(int *p_NumActivated, char *&p_EventsActivated) { char *pTemp = "Hello"; p_EventsActivated = pTemp; *p_NumActivated = 1; return 0; } 

which provides a simple pointer, you should be able to more simply P / Invoke.

Please note, however, that any line you marshal it will probably not be modified by the corresponding function. This is because .NET strings are UTF-16 strings, and the C ++ function uses ASCII strings that are not fully compatible with each other. You may have to convert the .NET string to ASCII, marshal it, marshal it back, and then convert it back to UTF-16.

Oh, the last: as it is written, you will need to pass a reference to the Activation object for this function to work. The position of this argument will depend on the C ++ compiler.

+1
source

Forgive my answer if it is wrong, but:

I don't think StringBuilder is compatible with char * &

Are you confusing StringBuilder with char **? * You might want to create a new string or string constructor based on the return from Activate, and not try to pass Activate data location. (How do you seem to be trying to do?)

(Activate - allocate a place for "Hello", and then return the pointer to its location).

As a rule, when sorting between C ++ or C objects when sending strings, it is best to also send the length of the string to ensure that lines of the correct length are passed between the callers.

0
source

Source: https://habr.com/ru/post/1316114/


All Articles