Marshal StringBuilder to char* in C++/CLI (for IN/OUT)
I'm loading a C++/CLI wrapping dll into my C# software and need some char* parameters for the underlying native C++ dll!
I found out that I need passing a StringBuilder for save the answer without getting some Access violations?!
C#
StringBuilder sB = new StringBuilder();
WrapperClass wC = new WrapperClass();
wC.Function(sB);
C++/CLI
void 开发者_开发知识库WrapperClass::Function(StringBuilder ^sB)
{
nativeObject->Function(charString); // need the marshaled sB
}
C++
void NativeObject::Function(char *charString)
{
// do something and save answer to charString
}
How it is possible to use the StringBuilder and marshal it to char* and back to save the answer of native function?
The problems I see are two: first, that you are mapping a UNICODE object to an MBCS or ASCII object, and second that StringBuilder does not pin automatically either. I would recommend you do this:
void WrapperClass::Function(StringBuilder^ sB)
{
// Pin a copy of the string
String^ strVal = sB->ToString();
pin_ptr<const wchar_t> psVal = PtrToStringChars(strVal);
// Translate the UNICODE string to MBCS
int wchLen = wcslen(psVal);
int pchLen = wchLen * 2 + 1;
char* pchVal = new char[pchLen];
int nclen = WideCharToMultiByte(
CP_ACP, // Source codepage (default)
WC_COMPOSITECHECK, // ch@rs with accents
strVal, // UNICODE string
wchLen, // Number of UNICODE ch@rs
pchVal, // ASCII string
pchLen, // Max number of ASCII ch@rs
0, // No default ch@rs
0 // No default flag
);
pchVal[nclen] = '\0';
// Pass the MBCS string to MBCS function
nativeObject->Function(pchVal); // need the marshaled sB
// Cleanup
delete[] pchVal;
}
You can directly pass in c# strings with help from the following tools: (EASY!)
You need to take advantage of some interop abiliteis to copy the strings into unmanaged heap memory and back for c++ native to use. These two helpers should do the trick when used in your c++/cli layer. Pass the string in as std::string& to the native c++ layer. When native c++ is done copy back to managed memory.
//////////////////////////////////////////////////
// Marshalling Strings Functions
inline
String ^ ToManagedString(const char * pString) {
return Marshal::PtrToStringAnsi(IntPtr((char *)pString)); // Marshal pString into Managed Memory. return as a C# string reference (^).
}
inline
const std::string ToStdString(String ^ strString) {
IntPtr ptrString = IntPtr::Zero;
std::string strStdString;
try {
ptrString = Marshal::StringToHGlobalAnsi(strString); // Marshal a C# String reference into unmanaged HEAP memory space.
strStdString = (char *)ptrString.ToPointer(); // Convert C# IntPtr to char* implicitly, call assignment operator of std::string to copy.
}
finally {
if (ptrString != IntPtr::Zero) {
Marshal::FreeHGlobal(ptrString);
}
}
return strStdString; // return std::string copied out of interop unmanaged heap space
}
//////////////////////////////////////////////////////
Throw the above code in a header file in your c++/cli layer. very handy interfacing tools. Good luck. (I've used these snippets tons.)
精彩评论