DOBON.NET DOBON.NETプログラミング掲示板過去ログ

IME変換前のテキストを入力する

環境/言語:[VB .NET 2003]
分類:[.NET]

以前お世話になりました、たいちうと申します。

【やりたいこと】
今回は「かな」と「漢字」を続けて入力するシステムで、入力の省力化を要求されています。
ユーザーが入力した「かな」を、次の「漢字」テキストボックスにコピーし、
漢字に変換したいのです。

例)田中と入力する場合
1.「かな」テキストボックスに"たなか"と入力。
2.「漢字」テキストボックスにフォーカスが移ると、"たなか"と表示。
3.スペースを押すことで、"田中"と変換される。

【試したこと】
http://w3.sfdata.ne.jp/ML/VB/msg14810.html を参考に次のソースコードを
試したところ、ImmSetCompositionStringでfalseが返ってきてしまいます。


Form1にTextBox1とTextBox2を貼り付ける。

'「入力コンテキスト」を取得する
Private Declare Function ImmGetContext Lib "imm32.dll" _
(ByVal hWnd As Int32) As Int32

'IMEを開く(あるいは閉じる)
Private Declare Function ImmSetOpenStatus Lib "imm32.dll" _
(ByVal hIMC As Int32, ByVal fOpen As Int32) As Int32

'ImmSetCompositionString APIのdwIndex
Private Enum eSCS
'変換文字列か読み文字列のいずれか、またはその両方を設定
SCS_SETSTR = &H9
'変換文字列か読み文字列のいずれか、またはその両方の属性を設定
SCS_CHANGEATTR = &H11
'変換文字列か読み文字列のいずれか、またはその両方の文節情報を設定
SCS_CHANGECLAUSE = &H24
'IMEにRECONVERTSTRING 構造体に格納された文字列を逆変換するよう指示
SCS_SETRECONVERTSTRING = &H10000
'IMEにRECONVERTSTRING構造体を調整するよう指示
SCS_QUERYRECONVERTSTRING = &H20000
End Enum

'変換文字列および読み文字列の文字、属性、または文節を設定
Private Declare Function ImmSetCompositionString Lib "imm32.dll" _
Alias "ImmSetCompositionStringA" _
(ByVal hIMC As Int32, _
ByVal dwIndex As eSCS, _
ByVal lpComp As Char(), _
ByVal dwCompLen As Int32, _
ByVal lpRead As Object, _
ByVal dwReadLen As Int32) As Int32

'「入力コンテキスト」を解放する
Private Declare Function ImmReleaseContext Lib "imm32.dll" _
(ByVal hWnd As Int32, ByVal hIMC As Int32) As Int32

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
TextBox1.Text = "へんかんまえのかんじ"
TextBox2.Text = ""
End Sub

Private Sub TextBox2_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox2.GotFocus
Try
Dim strKana As String= TextBox1.Text
Dim intLen As Integer = StrConv(strKana, vbHiragana).Length
Dim hIMC As Integer = ImmGetContext(TextBox2.Handle.ToInt32)
TextBox2.Text = ""
If hIMC <> 0 Then
Dim r As Boolean = ImmSetOpenStatus(hIMC, 1)
Debug.WriteLine("result of ImmSetOpenStatus : " & r.ToString)
Dim buf() As Char = strKana.ToCharArray()
r = ImmSetCompositionString(hIMC, eSCS.SCS_SETSTR, buf, intLen, vbNullString, 0)
Debug.WriteLine("result of ImmSetCompositionString : " & r.ToString)
ImmReleaseContext(TextBox2.Handle.ToInt32, hIMC)
End If
Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try
End Sub


【質問】
WinApiの呼び出し方が間違っているのだと思うのですが、
VB .NET 2003ではどのように書くのが正解なのか判りませんでした。
どなたかお教えいただけないでしょうか。
よろしくお願いします。
2010/04/15(Thu) 23:17:05 編集(投稿者)

■No26709に返信(たいちうさんの記事)
> http://w3.sfdata.ne.jp/ML/VB/msg14810.html を参考に
懐っ。9年前の私の投稿だ…。(^_^;)


> VB .NET 2003ではどのように書くのが正解なのか判りませんでした。
こんな感じで処理できるかと思います。

・As Any からの置き換えが Object 型になっている箇所を修正しました。
・ANSI 版 API ではなく、Unicode 版 API を優先利用するようにしました。
・ハンドルが Int32 型で宣言されていたため、IntPtr 型に置き換えました。
・[BOOL] が Int32 型で処理されていたため、Boolean 型に置き換えました。。
・StrConv が誤って使われていたため、Encoding クラスに修正しました。
・GotFocus イベントが利用されていたため、Enter イベントに差し替えました。
・コメントやエラー処理は記述していません。適宜補ってください。


'Imports System
'Imports System.Runtime.InteropServices
'Imports System.Text
'Imports System.Windows.Forms

Private Declare Function ImmGetContext Lib "imm32" _
 (ByVal hWnd As IntPtr _
 ) As IntPtr

Private Declare Function ImmSetOpenStatus Lib "imm32" _
 (ByVal hIMC As IntPtr, _
 <MarshalAs(UnmanagedType.Bool)> ByVal fOpen As Boolean _
 ) As <MarshalAs(UnmanagedType.Bool)> Boolean

Private Enum eSCS As Integer 'As UInteger
 SCS_SETSTR = &H9
 SCS_CHANGEATTR = &H11
 SCS_CHANGECLAUSE = &H24
 SCS_SETRECONVERTSTRING = &H10000
 SCS_QUERYRECONVERTSTRING = &H20000
End Enum

Private Declare Auto Function ImmSetCompositionString Lib "imm32" _
 (ByVal hIMC As IntPtr, _
 ByVal dwIndex As eSCS, _
 ByVal lpComp As String, _
 ByVal dwCompLen As Int32, _
 ByVal lpRead As String, _
 ByVal dwReadLen As Int32 _
 ) As <MarshalAs(UnmanagedType.Bool)> Boolean

Private Declare Function ImmReleaseContext Lib "imm32" _
 (ByVal hWnd As IntPtr, _
 ByVal hIMC As IntPtr _
 ) As <MarshalAs(UnmanagedType.Bool)> Boolean

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
 TextBox1.Text = "へんかんまえのかんじ"
 TextBox2.Text = ""
End Sub

Private Sub TextBox2_Enter(ByVal sender As Object, ByVal e As EventArgs) Handles TextBox2.Enter
 TextBox2.Clear()
 Dim strKana As String = TextBox1.Text
 Dim length As Integer
 If Environment.OSVersion.Platform = PlatformID.Win32NT Then
  length = Encoding.Unicode.GetByteCount(strKana)
 Else
  length = Encoding.GetEncoding(0).GetByteCount(strKana)
 End If
 Dim hIMC As IntPtr = ImmGetContext(TextBox2.Handle)
 If hIMC.Equals(IntPtr.Zero) Then
  Return
 End If
 ImmSetOpenStatus(hIMC, True)
 ImmSetCompositionString(hIMC, eSCS.SCS_SETSTR, strKana, length, Nothing, 0)
 ImmReleaseContext(TextBox2.Handle, hIMC)
End Sub
魔界の仮面弁士さま

回答ありがとうございます。
以前こちらで質問したときもお助けいただきましたが、
今回のリンク先もそうでしたか。

変更していただいたソースコードですが、
私の環境で実行すると、TextBox1のテキストの直下に、
一瞬だけ変換前テキストが表示され、消えてしまいました。

色々試してみたところ、GotFocusイベントに処理を書いたときには、
希望通りの動作となりました。
当面はこのイベントで処理しようと思いますが、
GotFocusは非推奨のようですので、もしもベターな方法をご存知でしたら、
ご教示お願いします。

大変助かりました。ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板