MASATOの開発日記


前の開発日記 次の開発日記 一覧

2001/10/10

前回からあっというまに1ヶ月が経ちました。 でもまだこの日記は公開してません。 まさに自分のためだけの日記。

必殺template

最近、MFCのCMapのキーとして、CTimeを使いたいと思う事がありました。 実現方法は簡単。 template<> inline UINT AFXAPI HashKey<CTime&>(CTime& key) という関数を作り、そこにハッシュキーを求めるコードを書くだけです。 たった1関数を作るだけでCTimeがハッシュ対応に!

javaをみてみましょう。MFCのCTimeと似たクラスとして、 javaにはjava.util.Dateクラスがあります。 この基底クラスであるObjectクラスは、ハッシュ用の関数hashCode()を持っていて、 Dateクラスもこれをオーバーライドしていますので、 ハッシュキーを求めることは簡単です。 おおなんとjavaは最初からハッシュ対応だ!

結局どちらが良いという問題では無いです。 C++は、合わないクラスさえも強引に合わせてしまうtemplateパワーがあり、 javaには最初から合っている素晴らしいクラスライブラリが用意されているという 二つのオブジェクト指向言語の文化の違いを見た気がしました。

ある意味templateがあるからC++はjavaのObjectのような全てのクラスの基底となるクラスが 必要ないのかもしれませんね。 逆に言うと、javaはObjectクラスがあるからtempalateが必要無いのかも・・・。

javaと比較しているから話がややこしくなるのですが、 とにかくC++の世界ではtemplateは強力です。 うまく使いこなせばかなり便利です。じゃじゃ馬ではありますが。

BSTRとCStringの相互変換

環境Visual C++ 6.0
言語C++
使用ライブラリWin32SDK
使用ライブラリMFC
使用ライブラリSTL

msxml.dllを使ってXMLを扱っていた時に、基本的に文字列はBSTR、 即ちUnicodeを使っている事に気が付きました。 恐らくActiveXまわりの文字列操作はみんなBSTRでしょう。 ということは、いざActiveXコンポーネントのメソッドを呼び出すとき、 CStringからBSTR及びその逆の変換を行う必要があります。 今回は、この方法について説明します。

まずはCStringからBSTRへの変換から。

CString str = "...";
BSTR bstr = str.AllocSysString();
// bstrを使って色々する。
::SysFreeString(bstr);

簡単ですね(^^;) 最後に::SysFreeStringで では、次のBSTRからCStringへの変換方法を説明します。

BSTR bstr = ::SysAllocString(L"...");
CString str = bstr;
::SysFreeString(bstr);

うわ、さらに簡単ですね。 ここまで簡単ですとつまらないので、 std::stringとBSTRへの変換を説明します。 これはそこそこ面倒ですので、関数という形で説明します。

BOOL SXDoc::AsciiToBSTR(const std::string& str, BSTR* bstr)
{
  int len = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
  if (len == 0)return FALSE;
  BSTR bs = ::SysAllocStringLen(NULL, len);
  if (bs == NULL)return FALSE;
  if (::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, bs, len) == 0)return FALSE;
  if (bstr != NULL)*bstr = bs;
  else ::SysFreeString(bs);
  return TRUE;
}

では続いてBSTRからstd::stringの変換です。

BOOL SXDoc::BSTRToAscii(const BSTR bstr, std::string* str)
{
  int len = WideCharToMultiByte(CP_ACP, 0, bstr, -1, NULL, 0, NULL, NULL);
  LPSTR s = new CHAR[len];
  WideCharToMultiByte(CP_ACP, 0, bstr, -1, s, len, NULL, NULL);
  if (str != NULL)*str = s;
  delete s;
  return TRUE;
}

双方とも、一度長さを求めてから実際の変換を行っています。 CStringに比べ、std::stringは結構面倒でしたね。 これはWin32を使うならばMFCを使えというM$のお告げでしょうか。 std::stringも悪いクラスでは無いのですが、 Win32という土俵の上で、Win32用に特化してあるCStringと使い勝手を争うと、 結局CStringに及ばない気がします。

前の開発日記 次の開発日記 一覧