3

次の関数を持つマネージ C++ クラスを作成しました。

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

ご覧のとおり、これは最後のエラーのマネージド文字列をアンマネージド ワールド ( char*) にコピーする簡単な方法です。

アンマネージ クラスから、次のようにメソッドを呼び出します。

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

マネージ C++ メソッドにブレークポイントを置くと、文字列がchar*. ただし、アンマネージ クラスに戻ると、の内容err[1000]が失われ、再び空になります。

4

3 に答える 3

2

Marshal::StringToHGlobalAnsi によって返されたバッファーの内容をそのアドレスにコピーする代わりに、渡されたパラメーター (strErrorMessage) の値を割り当てています。

正しい実装は次のようになります。

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

長さは、渡されたバッファーのサイズです。

strncpy()最大でlenバイトをコピーします。strの最初の n バイトに null バイトがない場合、宛先文字列は null で終了しません。そのため、バッファの最後のバイトに '\0' を強制します。

于 2008-11-06T19:36:02.267 に答える
0

次の C++ クラスを使用して変換を行い、正常に動作します。メソッドを変更して使用できるようにする必要があります。

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

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 );
}
于 2008-11-06T19:28:05.637 に答える
0

問題は、StringToHGlobalAnsi が新しい管理されていないメモリを作成し、strErrorMessage に割り当てた、使用する予定のメモリにコピーしないことです。
これを解決するには、次のようなことを行う必要があります。

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

使用法は次のようになります。

char* err;
GetLastError(&err);

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

詳細については、このmsdn 記事を参照してください

于 2008-11-06T19:30:21.357 に答える