非マネージドコードから Marshal.StringToXXX は使えない
.NET 1.1 までは、.NET のマネージドコードから COM コンポーネントの呼び出しには、RCW*1 を使用する方法しかありませんでした*2が、.NET 2.0 で C++/CLI を利用した CRCW*3 と呼ばれる方法が増えました。CRCW では非 blitable 型のマーシャリングのみを記述するだけで、あとは参照設定をして使うだけなので結構らくちんです。
さて、CRCW のマーシャリングを楽するため、C++ の一時オブジェクトを利用するために、
class S { public: S(String ^s) { ptr = Marshal::StringToHGlobalUni(s); } ~S() { Marshal::FreeHGlobal(ptr); } operator LPCWSTR() { return static_cast<LPCWSTR>(ptr.ToPointer()); } private: IntPtr ptr; };
のようなクラスを作成し、
void CRCW::WrapperClass::Method(String ^s1, String ^s2, int i1) { (*InterfacePtr)->Method( S(s1), S(s2), i1 ); }
みたいなかんじでお手軽メモリ管理をしようとしたのですが、標題の通りで失敗しました。まあ、たんにマネージドコードにすればよいだけなので、
ref class S { public: S(String ^s) { ptr = Marshal::StringToHGlobalUni(s); } ~S() { this->!S(); } !S() { Marshal::FreeHGlobal(ptr); } operator LPCWSTR() { return static_cast<LPCWSTR>(ptr.ToPointer()); } private: System::IntPtr ptr; };
と、ref を付けてファイナライザとデストラクタの関係を作ってしまえば、あとは C++/CLI が期待通りの処理をしてくれます。