昔書いてたメモ帳から転記。今更感がマックスの、備忘録メモ。
ちょこっとCOMクライアントとかのテストコード書く際に、ワイド文字列(主にWindowsで言うところのUNICODE)と、マルチバイト文字列の相互変換が煩わしいときが多々ある。
まぁ、変換用に関数一個作っとけばいい話なんですが・・・。正直、Win32 APIのMultiByteToWideChar/WideCharToMultibyte は使いたくない。理由はただ一つ。コイツらの使い勝手の悪さときたらどうしようもない。ってとこ。引数が5個も6個もいるし、何より、最低限2回のAPIコールが必要。↓のような感じ。
/* マルチバイト文字列 ==> ワイド文字列 */ #include <windows.h> //ヒープを使用。 PWSTR AllocString(PCSTR& pStr) { PWSTR pWStr = NULL; SIZE_T cchWStr = 0; if(pStr == NULL) goto cleanup; cchWStr = MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,pStr,-1,NULL,0); if(cchWStr <= 0) goto cleanup; if((pWStr = (PWSTR)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,cchWStr*sizeof(WCHAR))) == NULL) goto cleanup; if(!MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,pStr,-1,pWStr,cchWStr)) FreeString(pWStr); cleanup: return pWStr; } //ヒープ解放 BOOL FreeString(PWSTR& pWStr) { BOOL bRet = FALSE; if(pWStr && (bRet = HeapFree(GetProcessHeap(),0,reinterpret_cast<PVOID>(pWStr)))) pWStr = NULL; return bRet; }
でも、こんな感じだと、明らかにテストしたいコードより遙かに長いコード行・・・何か腹立つ。
お金の掛からないVC++ Express Edition を使っていて贅沢は言えませんが・・・なんかで代用できないものか・・・。
で、最近MSDNのドキュメント見てて気付いた。
_bstr_t クラスって便利やないかい!、と。
もともとは、COMでの文字列表現、BSTR型のラップするスマートポインタみたいなクラス。BSTR型はちょっと特殊で簡単に言えば文字列の長さとバッファを合わせたような型。BSTR型をPWSTR型と混同しているケースを極たまに見ます。まぁ、そんなことはどうでもよく。
_bstr_t クラスは、PCWSTR,PCSTRの両方をコンストラクタで受け付けてくれます。しかも、キャスト演算子をオーバーロードしてくれてるので、引数にPCWSTRもしくはPCSTRが必要なAPIや関数にそのまま放り込めます。
※注意点
これらのキャスト演算子は内部バッファへのナマのポインタを返すので、やたらめったら使用すると、おそらくどこかでクラッシュするバグを抱えるでせう。
#pragma comment(lib,"user32.lib") #pragma comment(lib,"comsuppw.lib") #include <windows.h> #include <comutil.h> #include <tchar.h> int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { _bstr_t bStr("テストでげす"); //ANSI版 MessageBoxA(NULL,bStr,"ANSI版",MB_OK); //UNICODE版 MessageBoxW(NULL,bStr,L"UNICODE版",MB_OK); return 0; } /* ANSIバージョンのAPIは、内部でマルチバイト文字<==>ワイド文字の変換を行って UNICODE版APIをコールしているだけのようなので、このコード自体無意味。 */
スコープを抜けると自動的にSysFreeStringをコールしてくれるみたいなので、解放処理も必要なし。
万歳!