CandidateListを取得する

IMEのCandidateListを取得する方法

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for Page3.xaml
    /// </summary>
    public partial class Page3 : Page
    {
        public Page3()
        {
            InitializeComponent();
        }
        public class Win32
        {

            [DllImport("user32.dll")]
            public static extern IntPtr DefWindowProc(IntPtr hWnd, uint Msg, uint wParam, IntPtr lPara);


            [DllImport("imm32.dll", SetLastError = true)]
            public static extern IntPtr ImmGetContext(IntPtr hWnd);

            [DllImport("Imm32.dll")]
            public static extern long ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);


            [DllImport("imm32.dll")]
            public static extern int ImmGetCandidateList(IntPtr hIMC, int iIndex, byte[] lpCandidateList, int iBuffLen);

            [DllImport("Imm32.dll")]
            public static extern int ImmNotifyIME(IntPtr hIMC, IntPtr dwAction, IntPtr dwIndex, IntPtr dwValue);

        }

        const int WM_APP = 0x8000;
        const int WM_CLOSE = 0x0010;

        const int GWL_WNDPROC = -4;

        //  WM_IME_

        const int WM_IME_CHAR = 0x0286;
        const int WM_IME_COMPOSITION = 0x010f;
        const int WM_IME_COMPOSITIONFULL = 0x0284;
        const int WM_IME_CONTROL = 0x0283;
        const int WM_IME_ENDCOMPOSITION = 0x010e;
        const int WM_IME_KEYDOWN = 0x0290;
        //  const int WM_IME_KEYLAST = 0x010f;
        const int WM_IME_KEYUP = 0x0291;
        const int WM_IME_NOTIFY = 0x0282;
        const int WM_IME_REPORT = 0x0280;
        const int WM_IME_REQUEST = 0x0288;
        const int WM_IME_SELECT = 0x0285;
        const int WM_IME_SETCONTEXT = 0x0281;
        const int WM_IME_STARTCOMPOSITION = 0x010d;

        //  WM_IME_SETCONTEXT lParam

        const int ISC_SHOWUICOMPOSITIONWINDOW = -2147483648;
        const int ISC_SHOWUIGUIDWINDOW = -2147483648;
        const int ISC_SHOWUISOFTKBD = -2147483648;
        const int ISC_SHOWUICANDIDATEWINDOW = 0x0001;
        const int ISC_SHOWUIALLCANDIDATEWINDOW = 0x000F;

        //  WM_IME_NOTIFY  wParam

        const int IMN_CHANGECANDIDATE = 0x0003;
        const int IMN_OPENCANDIDATE = 0x0005;
        const int IMN_SETCONVERSIONMODE = 0x0006;
        const int IMN_SETOPENSTATUS = 0x0008;
        const int IMN_SETCOMPOSITIONFONT = 0x000A;    // 10
        const int IMN_SETCOMPOSITIONWINDOW = 0x000B;  // 11

        const int GCS_COMPSTR = 0x0008;
        const int GCS_RESULTSTR = 0x0800;
        const int GCS_RESULTREADSTR = 0x0200;
        const int GCS_COMPREADSTR = 0x0001;

        //  ImmNotifyIMe  dwAction

        const int NI_CHANGECANDIDATELIST = 0x0013; //  現在選択している候補を変更した ( dwIndex:変更リストのインデックス  dwValue:使わない)                                                 (dwIndex:変更リストのインデックス
        const int NI_CLOSECANDIDATE = 0x0011;       //候補リストをクローズした  (dwValue:使わない)
        const int NI_COMPOSITIONSTR = 0x0015;   //   変換文字列を操作する (具体的な操作はdwIndexで指定する)
        const int NI_IMEMENUSELECTED = 0x0018;   //  指定のメニューのハンドル (dwIndex:メニューID dwValue:アプリケーション定義の値)
        const int NI_OPENCANDIDATE = 0x0010;     // 候補リストをオープン
        const int NI_SELECTCANDIDATESTR = 0x0012;  // 候補の一つを選択した (dwIndex:候補リストのインデックス  dwValue:選択した単語のインデックス)
        const int NI_SETCANDIDATE_PAGESIZE = 0x0017;  // 候補リストのページサイズを変更した(dwValue:0~31の数値)
        const int NI_SETCANDIDATE_PAGESTART = 0x0016;   // 候補リストを設定した (dwIndex:候補リストを指定する0~31の値)

        //  ImmNotifyIME  dwIndexの定数

        const int CPS_CANCEL = 0x0004;   //   変換文字列をクリアする
        const int CPS_COMPLETE = 0x0001;  //  変換文字列を確定文字にする
        const int CPS_CONVERT = 0x0002;  //   次の候補に変換する
        const int CPS_REVERT = 0x0003;  //   変換文字列を取り消し、確定前確定前に戻す

        //  ImmAssociateContextEx  dwFlags

        const int IACE_CHILDREN = 0x0001;
        const int IACE_DEFAULT = 0x0010;
        const int IACE_IGNORENOCONTEXT = 0x0020;


        int ItextLength = 0;

        IntPtr Hwnd;

        private string Us100ConverterStr2(byte[] str, int start, int byteNum)
        {
            if (byteNum + start > str.Length)
            {
                byteNum = str.Length - start;
            }

            byte[] str2 = new byte[byteNum];

            for (int cnt = 0; cnt < byteNum; cnt++)
            {
                str2[cnt] = str[cnt + start];
            }

            return Encoding.Default.GetString(str2);
        }

        private void WindowMain_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            InputMethod.Current.ImeState = InputMethodState.On;

            TextBoxInput.Focus();

        }

        private void WindowMain_Loaded(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("WindowMain Loaded ");

            var helper = new WindowInteropHelper(Application.Current.MainWindow);

            Hwnd = helper.Handle;

            HwndSource source = HwndSource.FromHwnd(Hwnd);

            source.AddHook(new HwndSourceHook(WndProc));


            //  IME Default CandidateWindow を隠す Start (非表示にするとImmGetCandidateList のサイズが設定される)

            var lp = ~ISC_SHOWUICANDIDATEWINDOW;

            var lParam = new IntPtr(lp);

            Win32.DefWindowProc(helper.Handle, WM_IME_SETCONTEXT, 1, lParam);   //  3 para は zero 以外

            //  IME Default CandidateWindow を隠す End 
        }



        public IntPtr WndProc(IntPtr hwnd, int imsg, IntPtr wParam, IntPtr lParam, ref bool bhandled)
        {
            switch (imsg)
            {
                case WM_IME_NOTIFY:    //  0x0282

                    Debug.WriteLine("WndProc  NOTIFY : " + wParam.ToString("0") + " : " + lParam.ToString("0"));

                    switch ((int)wParam)
                    {
                        case IMN_CHANGECANDIDATE:  //  0x0003

                            ItextLength = TextBoxInput.Text.Length;

                            bhandled = true;

                            var himc = Win32.ImmGetContext(hwnd);

                            var isize = Win32.ImmGetCandidateList(himc, 0, null, 0);

                            if (isize > 0)
                            {
                                Debug.WriteLine("CandidateChange  isize : " + isize.ToString("0"));

                                byte[] bytebuf = new byte[isize];

                                ListBoxA.Items.Clear();

                                Win32.ImmGetCandidateList(himc, 0, bytebuf, (int)isize);

                                int icount = System.BitConverter.ToInt32(bytebuf, 8);

                                for (int cnt = 0; cnt < icount; cnt++)
                                {
                                    int iOffset = System.BitConverter.ToInt32(bytebuf, cnt * 4 + 24);

                                    int len = 0;

                                    while (bytebuf[iOffset + len] != '\0')
                                    {
                                        len++;
                                    }

                                    ListBoxA.Items.Add(Us100ConverterStr2(bytebuf, iOffset, len));
                                }

                                Win32.ImmReleaseContext(hwnd, himc);
                            }

                            break;

                        default:

                            Debug.WriteLine("WM_IME_NOTIFY 3 以外 : " + wParam.ToString("0") + lParam.ToString("0"));

                            break;
                    }

                    break;

                default:

                    break;

            }

            if (!bhandled)
            {
                Win32.DefWindowProc(hwnd, (uint)imsg, (uint)wParam, lParam);
            }

            return IntPtr.Zero;
        }

        private void ListBoxA_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var iidx = ListBoxA.SelectedIndex;

            if (iidx >= 0)
            {
                var slist = ListBoxA.Items[iidx].ToString();

                TextBoxInput.Text = TextBoxInput.Text + slist;

                var himc = Win32.ImmGetContext(Hwnd);

                Win32.ImmNotifyIME(himc, (IntPtr)NI_SELECTCANDIDATESTR, (IntPtr)iidx, IntPtr.Zero);

                Win32.ImmReleaseContext(Hwnd, himc);

            }
        }
    }
}