C# で IME 操作(5)
ImmGetCompositionString() 全般についての処理。
ImmGetCompositionString() で返されるバッファは、あらかじめ null を入れてその大きさを取得して、それからバッファを確保して、もう一度呼び出して取得する。
これは、どの ImmGetCompositionString() でも同じなので、それをラップしておく。
/// <summary> /// Marshal.AllocHGlobal で確保された IntPtr を using 文の中で使用出来るようにするためのクラス /// </summary> private class SafePtr : IDisposable { #region IDisposable メンバ public void Dispose() { if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; length = 0; } } #endregion private IntPtr ptr = IntPtr.Zero; private int length; public SafePtr(int size) { ptr = Marshal.AllocHGlobal(size); length = size; } ~SafePtr() { // 念のため…… Dispose(); } public IntPtr Ptr { get { return ptr; } } public int Length { get { return length; } } } /// <summary> /// IMEStatic.GetCompositionString によって取得出来た情報を SafePtr にセットします。 /// </summary> /// <param name="gcs"></param> /// <returns>ImmGetCompositionString によって得られたデータ</returns> private SafePtr GetCompositionString(int gcs) { int length = GetCompositionString(Handle, gcs, IntPtr.Zero, 0); if (length == 0) { return null; } SafePtr ptr = new SafePtr(length); try { GetCompositionString(Handle, gcs, ptr.Ptr, length); } catch (Exception) { ptr.Dispose(); ptr = null; throw; } return ptr; }
で、ImmGetCompositionString() を2回呼び出す代わりに、この GetCompositionString() を using 文の中で使用すれば、リークの心配もない。
でも、よく考えてみれば、SafePtr で返す必要もなくて、GetCompositionString() の最後で、
byte[] buf = new byte[ptr.Length]; Marshal.Copy(ptr.Ptr, buf, 0, buf.Length); return buf;
とかやって byte[] とかに変換して返したほうがいいのかもしれない(;´Д`)