2008-11-06 10 views
3

J'ai écrit une classe managée C++ qui a la fonction suivante:chaîne à char * marshaling

void EndPointsMappingWrapper::GetLastError(char* strErrorMessage) 
{ 
    strErrorMessage = (char*) Marshal::StringToHGlobalAnsi(_managedObject->GetLastError()).ToPointer(); 
} 

Comme vous pouvez le voir, c'est une méthode simple pour copier la chaîne managée de la dernière erreur au monde non géré (char*).

de ma classe non géré j'appelle la méthode comme ceci:

char err[1000]; 
ofer->GetLastError(err); 

Mettre un point d'arrêt à la méthode géré C++ montre que la chaîne est traduit avec succès dans le char*. Cependant, une fois que je reviens à la classe non gérée, le contenu de err[1000] est perdu et il est à nouveau vide.

Répondre

2

Vous assignez la valeur de le paramètre passé (strErrorMessage) au lieu de copier à cette adresse le contenu du tampon retourné par Marshal :: StringToHGlobalAnsi.

Une mise en œuvre correcte doit être:

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 longueur est la taille de la mémoire tampon passée.

strncpy() va copier au maximum len octets. S'il n'y a pas d'octet nul parmi les n premiers octets du str, la chaîne de destination ne sera pas terminée par un caractère nul. Pour cette raison, nous forçons le '\ 0' dans le dernier octet du tampon.

0

Nous utilisons la classe C++ suivante pour effectuer les conversions et cela fonctionne correctement. Vous devriez être capable de modifier votre méthode pour l'utiliser.

H Fichier

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; 
}; 

RPC Fichier

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); 
} 
0

Le problème est que StringToHGlobalAnsi crée une nouvelle mémoire unmanged et ne copie pas dans la mémoire vous aviez l'intention d'utiliser que vous avez attribué dans strErrorMessage.
Pour résoudre cela, vous devez faire quelque chose comme:

void EndPointsMappingWrapper::GetLastError(char** strErrorMessage) 
{ 
    *strErrorMessage = (char*) Marshal::StringToHGlobalAnsi(_managedObject->GetLastError()).ToPointer(); 
} 

Et l'utilisation devrait ressembler à:

char* err; 
GetLastError(&err); 

//and here you need to free the error string memory 

pour plus d'informations consultez ce msdn article

Questions connexes