VB6でフォームに入力されたUnicode文字列の取得を行う

土曜日 , 5, 7月 2014 Leave a comment

Visual Basic 6(以下VB6)では、標準コントロールを用いてUnicode文字列を表示しようとすると文字化けを起こしてしまい正しく表示することができません。
表示に関しては、マイクロソフトのサポート情報「[HOWTO] Visual Basic のフォームで UNICODE 文字列の読み込みと表示を行う方法」で紹介されているように、Forms 2.0コントロールを使うことで正しくUnicode文字列の表示が行えるようになります。
しかし、Forms 2.0コントロールではユーザが入力した内容を正しく取得することができず、テキストボックスを用いて入力値を取得すると文字化けを起こしてしまいます。

いろいろと試していくと、TextプロパティやClipboardオブジェクトなど、VB6が持っている機能に触れそうな処理を通過してしまうと文字化けを起こしてしまうようだということがわかりました。
これを回避するため、APIを使いクリップボードに入力された文字列を変数にコピーし、ADO Streamを使い文字コードの変換を行っています。
細やかな制御が求められる場面では、タイミングが合わず意図しない文字列を取得してしまう可能性もありますが、使用場面に応じてアレンジしてみてください。 
なお、動作確認はWindows 7 32bit版で行っています。 
 

Option Explicit
'============================================================================
' Win32関連の宣言と定義
'============================================================================
Public Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function CloseClipboard Lib "user32" () As Long
Public Declare Function EmptyClipboard Lib "user32" () As Long
Public Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long

Public Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Public Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Public Const GMEM_MOVABLE = &H2
Public Const CF_UNICODETEXT = 13

Public Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal destination As Long, ByVal source As Long, ByVal Length As Long)

Public Type KEYBDINPUT
    wVk         As Integer
    wScan       As Integer
    dwFlags     As Long
    time        As Long
    dwExtraInfo As Long
    no_use1     As Long
    no_use2     As Long
End Type
Public Type INPUT_TYPE
    dwType      As Long
    xi          As KEYBDINPUT
End Type

Public Const KEYEVENTF_KEYUP = &H2
Public Const KEYEVENTF_EXTENDKEY = &H1
Public Const VK_CTRL = &H11
Public Const VK_C = &H43
Public Const VK_V = &H56
Public Const INPUT_KEYBOARD = 1

Public Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Public Declare Function SendInput Lib "user32" (ByVal nInputs As Long, pInputs As INPUT_TYPE, ByVal cbsize As Long) As Long

'============================================================================
' - 機能 -
'  textboxに入力されたUNICODE文字列を取得する
'
' - 引数 -
'
'    textbox    Forms 2.0のテキストボックス
'
' - 返り値 -
'    textboxに入力された内容
'
'============================================================================
Public Function GetUnicodeText(ByRef textbox As Control) As String
Dim pInput As INPUT_TYPE
Dim data() As Byte
Dim wFormat As Long
Dim hMem As Long
Dim Size As Long
Dim p As Long
Dim oStream As Object
    
    '-
    ' 対象となるコントロールにフォーカスを移動
    '-
    textbox.SetFocus
    textbox.SelStart = 0
    textbox.SelLength = Len(textbox.Text)
    DoEvents

    '-
    ' API経由でCtrl+C相当の操作
    '-
    pInput.dwType = INPUT_KEYBOARD
    With pInput.xi
        .wVk = VK_CTRL
        .wScan = MapVirtualKey(VK_CTRL, 0)
        .dwFlags = KEYEVENTF_EXTENDKEY Or 0
        .time = 0
        .dwExtraInfo = 0
    End With
    SendInput 1, pInput, Len(pInput)
    DoEvents
    
    pInput.dwType = INPUT_KEYBOARD
    With pInput.xi
        .wVk = VK_C
        .wScan = MapVirtualKey(VK_C, 0)
        .dwFlags = KEYEVENTF_EXTENDKEY Or 0
        .time = 0
        .dwExtraInfo = 0
    End With
    SendInput 1, pInput, Len(pInput)
    DoEvents
    
    pInput.dwType = INPUT_KEYBOARD
    With pInput.xi
        .wVk = VK_C
        .wScan = MapVirtualKey(VK_C, 0)
        .dwFlags = KEYEVENTF_EXTENDKEY Or KEYEVENTF_KEYUP
        .time = 0
        .dwExtraInfo = 0
    End With
    SendInput 1, pInput, Len(pInput)
    DoEvents
    
    pInput.dwType = INPUT_KEYBOARD
    With pInput.xi
        .wVk = VK_CTRL
        .wScan = MapVirtualKey(VK_CTRL, 0)
        .dwFlags = KEYEVENTF_EXTENDKEY Or KEYEVENTF_KEYUP
        .time = 0
        .dwExtraInfo = 0
    End With
    SendInput 1, pInput, Len(pInput)
    DoEvents
    
    '-
    ' クリップボードの内容をAPI経由で変数にコピー
    '-
    If OpenClipboard(ByVal 0&) Then
        hMem = GetClipboardData(CF_UNICODETEXT)
        If hMem Then
            Size = GlobalSize(hMem)
            p = GlobalLock(hMem)
            ReDim data(0 To Size)
            MoveMemory VarPtr(data(0)), p, Size
            GlobalUnlock hMem
        End If
        CloseClipboard
    End If

    '-
    ' ADOストリームで文字コードを変換
    '-
    Set oStream = CreateObject("ADODB.Stream")
    oStream.Type = 1   ' 1:adTypeBinary
    oStream.Open
    oStream.Write data
    oStream.Position = 0
    oStream.Type = 2   ' 2:adTypeText
    
    GetUnicodeText = oStream.ReadText(-1)
    
    oStream.Close
    
    Set oStream = Nothing
    
End Function
Tags:,

Please give us your valuable comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください