C++/CLI 文字列操作


電波襲来篇
基本解説篇
機能解説篇
用語集泥沼篇
仕様書ドラフト翻訳篇
統合アーカイブと一緒篇
PDFLib-Lite
ラッパーの脅威篇

スクリプト言語まとん・ブログ
「まとん」まとめ

Back
Home

始めに

 C++/CLI はおそらく旧来のライブラリを .net のアセンブリに変更されるのに一番利用されると考えています。
 そのとき、一番面倒なのは、旧来の MBCS や wchar_t 型と System::String をどうやりとりすればいいのかという点です。

 ここでは、MultiByte ないし、 WideChar の System::String 型とのやりとりについて記述しておきます。

MultiByte から System::String に

 これは特に問題も疑問の余地もないですよね。
std::string text = "サンプル・テキスト";  // めんどくさいので char * はこれで代用
String^ textString = gcnew String(text.c_str());

String^ textString = Marshal::PtrToStringAnsi(text.c_str());  // Marshal を使うとこれ

WideChar から System::String に

 これも特に疑念の余地はありませんよね。
std::wstring wide_text = L"ワイド文字列";  // めんどくさいので wchar_t * はこれで代用
String^ textString = gcnew String(wide_text.c_str());

String^ textString = Marshal::PtrToStringUni(wide_text.c_str());  // Marshal を使うとこれ

 Marshal クラスにはそのほかに BSTR 用の PtrToStringBSTR や 自動識別の PtrToStringAuto も用意されています。TCHAR を使っているときは、PtrToStringAuto を使った方が便利でしょう。

System::String 型から MultiByte に

 ここから段々と面倒な手続きが必要になってきます。
 キーワードは、ピンニング、マーシャル・アズです。
 追加で、System.Runtime.InteropServices の Marshal クラスを見ておくといろいろと便利です。
std::string text;  // 文字列を受け止めるバッファ
String^ textString = gcnew String("適当なサンプル文字列");  // 変換する文字列

// System::String をChar 型 = wchar_t 型の配列にする
array<Char>^ warr = textString->ToCharArray();

// 配列がガベージ・コレクトによって移動しないようピンニング
pin_ptr<Char> wptr = &warr[0];

// 変換後文字サイズを取得
char *buffer = 0;
int len = ::WideCharToMultiByte(CP_UTF8, 0, wptr, num, buffer, 0, NULL, NULL);
if ( len > 0 ) {

    // 文字バッファを取得して
    buffer = new char[len + 1];
    memset(buffer, 0, len+1);

    // UNICODE を MultiByte に変換
    ::WideCharToMultiByte(CP_UTF8, 0, wptr, num, buffer, len, NULL, NULL);

    // バッファをMultiByteの文字型に代入
    text = buffer;
    if ( buffer ) delete [] buffer;
}

 もっといい方法が .NET Framework 2.0 では提供されていました。
std::string text;  // 文字列を受け止めるバッファ
String^ textString = gcnew String("適当なサンプル文字列");  // 変換する文字列

IntPtr mptr = Marshal::StringToHGlobalAnsi(textString);

text = static_cast<const char*>(mptr.ToPointer());
Marshal::FreeHGlobal(mptr);


System::String 型から WideChar 型に

 これはちょっと微妙。どうやってコピーするかによると思う。
 基本的にはピンニングして、コピーすればいい。
String^ textString = gcnew String("適当なサンプル文字列");  // 変換する文字列

// System::String をChar 型 = wchar_t 型の配列にする
array<Char>^ warr = textString->ToCharArray();

// 配列がガベージ・コレクトによって移動しないようピンニング
pin_ptr<Char> wptr = &warr[0];

// 文字列を受け止めるバッファ
std::wstring wide_text(wptr);
String^ textString = gcnew String("適当なサンプル文字列");  // 変換する文字列

IntPtr wptr = Marshal::StringToHGlobalUni(textString);

// 文字列を受け止めるバッファ
std::wstring wide_text(static_cast<const wchar_t*>(wptr.ToPointer()));

Marshal::FreeHGlobal(wptr);

System::String 型から TCHAR 型に

 MFC ないし、ATL(WTL) の CString を使ってまとめて書くと次のようになります。
String^ textString = gcnew String("適当なサンプル文字列");  // 変換する文字列

IntPtr tptr;

#ifdef _UNICODE
tptr = Marshal::StringToHGlobalUni(textString);
#else
tptr = Marshal::StringToHGlobalAnsi(textString);
#endif

CString result_text = (LPCTSTR)tptr.ToPointer();

Marshal::FreeHGlobal(tptr);
 すごく簡単ですね。

 これで基本的な置き換えはおっけーです。
(´-`).。oO(そういえば、marshall_as<> はどこへ行ってしまったのだろう?)
(´-`).。oO(なるほど、System.Runtime.InteropServices.Marshal になったわけか…)



Topに戻る