Hi,
a strange problem ....
I wrote a managed c++ class that has the followig function:
void EndPointsMappingWrapper::GetLastError(char* strErrorMessage) { strErrorMessage = (char*) Marshal::StringToHGlobalAnsi(_managedObject->GetLastError()).ToPointer(); }
As you can see, this is simple methode to copy the managed string of the last error to the unmanaged world (char*)
from my unmanaged class I call this method like that:
char err[1000]; ofer->GetLastError(err);
The Problem:
putting a breakpoint at the managed c++ methode shows that the string is successfully translated into the char*
however, onece I return to the unmanaged class, the content of err[1000] is lost and its empty again...
Any suggesting will be wellcomed...
Ofer
-
We use the following C++ Class to do the conversions for us and it works fine. You should be able to modify your method to use it.
H File
public ref class ManagedStringConverter { public: ManagedStringConverter( System::String^ pString ); ~ManagedStringConverter(); property char* PrimitiveString { char* get() { return m_pString; } } /// <summary> /// Converts a System::String to a char * string. You must release this with FreeString. /// </summary> static const char* StringToChar( System::String^ str ); /// <summary> /// Converts a System::String to a __wchar_t * string. You must release this with FreeString. /// </summary> static const __wchar_t * StringToWChar( System::String^ str ); /// <summary> /// Frees memory allocated in StringToChar() /// </summary> static void FreeString( const char * pszStr ); private: char* m_pString; };
CPP File
ManagedStringConverter::ManagedStringConverter( System::String^ pString ) { m_pString = const_cast<char*>( ManagedStringConverter::StringToChar( pString ) ); } ManagedStringConverter::~ManagedStringConverter() { ManagedStringConverter::FreeString( m_pString ); } // static const char * ManagedStringConverter::StringToChar( System::String^ str ) { IntPtr^ ip = Marshal::StringToHGlobalAnsi( str ); if ( ip != IntPtr::Zero ) { return reinterpret_cast<const char *>( ip->ToPointer() ); } else { return nullptr; } } // static const __wchar_t * ManagedStringConverter::StringToWChar( System::String^ str ) { IntPtr^ ip = Marshal::StringToHGlobalUni( str ); if ( ip != IntPtr::Zero ) { return reinterpret_cast<const __wchar_t *>( ip->ToPointer() ); } else { return nullptr; } } // static void ManagedStringConverter::FreeString( const char * pszStr ) { IntPtr ip = IntPtr( (void *)pszStr ); Marshal::FreeHGlobal( ip ); }
-
The problem is that StringToHGlobalAnsi creates a new unmanged memory and does not copy into the memory you intended to use which you assigned into strErrorMessage.
To resolve this you should do some thing like:void EndPointsMappingWrapper::GetLastError(char** strErrorMessage) { *strErrorMessage = (char*) Marshal::StringToHGlobalAnsi(_managedObject->GetLastError()).ToPointer(); }
And the usage should look like:
char* err; GetLastError(&err); //and here you need to free the error string memory
for more information check out this msdn article
-
You are assigning the value of the passed parameter (strErrorMessage) instead of copying to that address the content of the buffer returned by Marshal::StringToHGlobalAnsi.
A correct implementation should be:
void EndPointsMappingWrapper::GetLastError(char* strErrorMessage, int len) { char *str = (char*) Marshal::StringToHGlobalAnsi(_managedObject->GetLastError()).ToPointer(); strncpy(strErrorMessage,str,len); strErrorMessage[len-1] = '\0'; }
The length is the size of the buffer passed.
strncpy()
will copy at the most len bytes. If there is no null byte among the first n bytes of the str, the destination string won't be null terminated. For that reason we force the '\0' in the last byte of the buffer.
0 comments:
Post a Comment