stringa a char * marshaling
-
06-07-2019 - |
Domanda
Ho scritto una classe C ++ gestita che ha la seguente funzione:
void EndPointsMappingWrapper::GetLastError(char* strErrorMessage)
{
strErrorMessage = (char*) Marshal::StringToHGlobalAnsi(_managedObject->GetLastError()).ToPointer();
}
Come puoi vedere, questo è un metodo semplice per copiare la stringa gestita dell'ultimo errore nel mondo non gestito ( char *
).
Dalla mia classe non gestita chiamo il metodo in questo modo:
char err[1000];
ofer->GetLastError(err);
Inserire un breakpoint nel metodo C ++ gestito mostra che la stringa è stata tradotta correttamente nel char *
. Tuttavia, una volta tornato alla classe non gestita, il contenuto di err [1000]
viene perso ed è di nuovo vuoto.
Soluzione
Stai assegnando il valore del parametro passato (strErrorMessage) invece di copiare a quell'indirizzo il contenuto del buffer restituito dal Maresciallo :: StringToHGlobalAnsi.
Un'implementazione corretta dovrebbe essere:
void EndPointsMappingWrapper::GetLastError(char* strErrorMessage, int len)
{ char *str = (char*) Marshal::StringToHGlobalAnsi(_managedObject->GetLastError()).ToPointer();
strncpy(strErrorMessage,str,len);
strErrorMessage[len-1] = '\0';
Marshal::FreeHGlobal(IntPtr(str));
}
La lunghezza è la dimensione del buffer passato.
strncpy ()
copierà al massimo len byte. Se non vi è alcun byte null tra i primi n byte di str , la stringa di destinazione non verrà terminata con null. Per questo motivo forziamo lo '\ 0' nell'ultimo byte del buffer.
Altri suggerimenti
Usiamo la seguente classe C ++ per fare le conversioni per noi e funziona benissimo. Dovresti essere in grado di modificare il tuo metodo per usarlo.
File H
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;
};
File CPP
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 );
}
Il problema è che StringToHGlobalAnsi crea una nuova memoria non aggiustata e non copia nella memoria che intendevi usare che hai assegnato in strErrorMessage.
Per risolvere questo problema dovresti fare qualcosa del tipo:
void EndPointsMappingWrapper::GetLastError(char** strErrorMessage)
{
*strErrorMessage = (char*) Marshal::StringToHGlobalAnsi(_managedObject->GetLastError()).ToPointer();
}
E l'uso dovrebbe apparire come:
char* err;
GetLastError(&err);
//and here you need to free the error string memory
per ulteriori informazioni consulta questo msdn articolo