IMEなどのFEPは変換対象の文字セットをどのように判断しているのだろう。
これがわからずにだいぶ苦労してしまった。
前回VC++から.Net Framework対応のFlexGridを使う手段を示したが、これには大きな欠点があった。
FlexGridの編集モードでテキストをFEP経由で入力すると文字化けしてしまうのだ。
どうやらFEPがターゲット(FlexGrid)をShift-JIS対応と勘違いして漢字を送ってくるからだ。
FlexGridはもちろんUnicode対応である。
IMEにターゲットがUnicodeであることを伝えたいが、その方法がわからない。
IMEを制御して変換を補正させることも考えたが、アプリケーションがIME依存になることは避けたい。
そこで先ほどのWM_CHARをフックする方法に辿りついた。
ここで送られてくるShift-JISをUnicodeに変換すればいい。
あとはこの変換処理を行うタイミングだ。
FlexGridの場合はStartEdit、BeforeEdit、KeyDownEditあたりで、Editorプロパティに設定される入力コントロールに対してフックをかければうまくいくようだ。
先ほどのWM_CHAR万能フッククラスを以下のようにコードセット変換用に書き換えた。
class SjisHook : NativeWindow { private const int WM_CHAR = 0x102; private List<byte> _mbStack = new List<byte>(); enum GetWindow_Cmd : uint { GW_HWNDFIRST = 0, GW_HWNDLAST = 1, GW_HWNDNEXT = 2, GW_HWNDPREV = 3, GW_OWNER = 4, GW_CHILD = 5, GW_ENABLEDPOPUP = 6 } [DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd); public SjisHook(Control c) { IntPtr handle = c.Handle; if (c is ComboBox) { handle = GetWindow(c.Handle, GetWindow_Cmd.GW_CHILD); } AssignHandle(handle); c.HandleDestroyed += new EventHandler(OnHandleDestroyed); c.HandleCreated += new EventHandler(OnHandleCreated); } internal void OnHandleDestroyed(object sender, EventArgs e) { ReleaseHandle(); this._mbStack.Clear(); } internal void OnHandleCreated(object sender, EventArgs e) { if (sender is Control) { AssignHandle(((Control)sender).Handle); this._mbStack.Clear(); } } protected override void WndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { case WM_CHAR: int w = m.WParam.ToInt32(); if (this._mbStack.Count == 0 && ((w >= 0x81 && w <= 0x9f) || (w >= 0xe0 && w <= 0xfc))) { this._mbStack.Add((byte)w); return; } else if (this._mbStack.Count == 1) { this._mbStack.Add((byte)w); try { if (ConvertCodeSetAndProc(this._mbStack.ToArray<byte>(), m)) { return; } } finally { this._mbStack.Clear(); } } else if ((w >= 0x21 && w <= 0x7e) || (w >= 0xa1 && w <= 0xdf)) { if(ConvertCodeSetAndProc(new byte[] {(byte)w}, m)) { return; } } else if (Char.IsControl((char)w)) { base.WndProc(ref m); return; } else { this._mbStack.Clear(); } break; } base.WndProc(ref m); } private bool ConvertCodeSetAndProc(byte[] bytes, System.Windows.Forms.Message m) { bool ret = false; byte[] by = System.Text.Encoding.Unicode.GetBytes(System.Text.Encoding.GetEncoding(932).GetString(bytes)); if (by.Length == 2) { Message wm = Message.Create(m.HWnd, m.Msg, new System.IntPtr((by[1] << 8) | by[0]), m.LParam); base.WndProc(ref wm); ret = true; } return ret; } }