问题
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