How to marshall c++ char* to C# string using P/INVOKE

假装没事ソ 提交于 2019-12-23 14:54:18

问题


I'm new to C++. I'm calling a C++ function from C# using a PINVOKE and wanting to get a string back as an out parameter. However I just get an empty string back. The int out parameter works fine.

Importing:

[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);  

The C++ function:

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

    *p_NumActivated = 1;

    return 0;
}

回答1:


[DllImport ( @"UnamanagedAssembly.dll", CharSet = CharSet.Ansi)]
public static extern int Activate(
    ref int numActivated, 
    [MarshalAs(UnmanagedType.LPStr)]StringBuilder eventsActivated);



回答2:


StringBuilder eventsActivated = new StringBuilder(5);

instead of

StringBuilder eventsActivated = new StringBuilder();



回答3:


P/Invoke is only supported for C interfaces. YMMV if you're trying to get it to talk to C++ constructs. In this case, you'd have to find out specifically what the C++ compiler was translating the reference into, as C++ compilers are free to implement that in any means they wish.

If you want to be able to P/Invoke this, but don't want to have to use pointer semantics at the call site, you could 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 exposes a plain pointer you should be able to more simply P/Invoke.

Note, however, that whatever string you marshal it too is probably not going to be modifiable by the function in question. This is because .NET strings are UTF-16 strings, while the C++ function is using ASCII strings, which are not completely compatible with each other. You'll probably have to convert the .NET string into ASCII, marshal it across, marshal it back, and then reconvert back into UTF-16.

Oh, one last thing: As written, you're going to need to pass a reference to an Activation object in order for that function to work. The position of that argument is going to be C++ compiler dependent though.




回答4:


Pardon my answer if it is wrong, but:

I dont think a StringBuilder is compatible with a char *&

Are you're confusing a StringBuilder with a char** ? * You might want to create a new string , or stringbuilder based upon the return from Activate, rather than try to pass Activate a place to put the data. (As you seem to be trying to do?)

(Activate is allocating space for "Hello", then returning the pointer to its location).

Generally, when marshalling between C++ or C objects, when sending strings, it is best to also send the length of the string, to ensure that proper length strings are passed between callers.



来源:https://stackoverflow.com/questions/3278314/how-to-marshall-c-char-to-c-sharp-string-using-p-invoke

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!