

お世話になります。

Windows7で統計・解析環境「R」のGUI版に対してコマンドテキストを送信し、その結果を取得するアプリを作成しています。

見よう見まねでFindWindowEx関数でRGUIの親ウインドウハンドル、MDIのウインドウハンドル、そしてRConsole自体のハンドルを取得する事に成功しました。

※ハンドルはWinSpectorで確認

取得したハンドルに対してSendMessage関数で文字列を飛ばそうと思うのですが実行しても全然文字を入力してくれません。

ウインドウハンドル自体は取得できているので問題ないと思っているのですが何か足りない物があるのでしょうか？

ご示唆頂けるとありがたく思います。

よろしくお願いします。

[code]

    Option Strict Off
    Option Explicit On
    Friend Class Form1
        Inherits System.Windows.Forms.Form
    
        'クラス名、キャプションから子ウィンドウのハンドルを取得
        Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hwndParent As Integer, ByVal hwndChildAfter As Integer, ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
    
        Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Integer, ByVal Msg As Integer, ByVal wParam As Integer,ByVal lParam As String) As Integer
    
        Private Const WM_IME_CHAR As Short = &H286S '文字コード送信
        Private Const WM_SETTEXT As Short = &HCS '文字列送信
    
        Private Sub Command1_Click(ByVal eventSender As System.Object, _
                                   ByVal eventArgs As System.EventArgs) Handles Command1.Click
            Dim lnghWnd As Integer 'トップレベル（親）のウィンドウハンドル
            Dim lnghWndMDI As Integer
            Dim lnghWndTarget As Integer 'ターゲット（子）のウィンドウハンドル
            Dim lngRc As Integer 'APIの返却値
    
            lngRc = Shell("C:\Program Files\R\R-3.3.1\bin\x64\Rgui.exe", AppWinStyle.NormalFocus)
            System.Threading.Thread.Sleep(3000)
    
    
            '
            '-------------------------------------
            ' ターゲットウィンドウのハンドルを取得
            '-------------------------------------
            lnghWnd = FindWindowEx(0, 0, "Rgui Workspace", "RGui (64-bit)")
            lnghWndMDI = FindWindowEx(lnghWnd, 0, "MDIClient", "")
            lnghWndTarget = FindWindowEx(lnghWndMDI, 0, "Rgui Document", "R Console")
    
            '-------------------------------------
            ' 送信
            '-------------------------------------
            Dim strDt As String
    
            '-------------------------------------
            ' １文字ずつ送信　50ミリ(0.05)秒間隔
            '-------------------------------------
            Dim lngDt As Integer
            Dim i As Integer
    
            For i = 1 To Len(Text1.Text)            '文字数分繰り返す
                strDt = Mid(Text1.Text, i, 1)       '１文字
                lngDt = Asc(strDt)                  'ASCIIコードに変換
                lngRc = SendMessage(lnghWndTarget, WM_IME_CHAR, lngDt, 0) '1文字送信
    
                System.Threading.Thread.Sleep(50) '指定ミリ秒待つ
            Next i
    
        End Sub
    
    
        Private Sub Form1_Load(ByVal eventSender As System.Object, _
                               ByVal eventArgs As System.EventArgs) Handles MyBase.Load
            Text1.Text = "q()" & vbCrLf
        End Sub
    
        Private Sub Form1_FormClosing(ByVal eventSender As System.Object, _
                                      ByVal eventArgs As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            Dim Cancel As Boolean = eventArgs.Cancel
            Dim UnloadMode As System.Windows.Forms.CloseReason = eventArgs.CloseReason
            End
            eventArgs.Cancel = Cancel
        End Sub
    End Class
    
[/code]


CC BY-SA 3.0
2016-08-12T14:49:38.740
28227
2016-08-15T02:48:27.353
2016-08-15T02:48:27.353
4236
10607
question
vb.net winapi
WinAPIでRGUIにテキストが送信出来ない


キー入力はWindow Messageひとつで完了するような単純なものではありません。key down / key upだけでなく、Shift / Ctrl
/
Altなどのキーの状態管理などいろいろな操作が必要です。ネイティブコードであれば[`SendInput`](https://msdn.microsoft.com/en-
us/library/ms646310\(v=vs.85\).aspx)を使用しますが、.NETであれば[`SendKeys.SendWait`](https://msdn.microsoft.com/ja-
jp/library/system.windows.forms.sendkeys.sendwait\(v=vs.100\).aspx)が用意されているのでこちらを使うのが楽でしょう。その際、Enterキーについては`{ENTER}`と記述するなど、特殊キーの扱いについては[SendKeysクラスの解説](https://msdn.microsoft.com/ja-
jp/library/system.windows.forms.sendkeys\(v=vs.100\).aspx#Anchor_3)を参照してください。

その上で、キー入力はアプリケーションに紐づくものではなく、アクティブなウィンドウに対して行われるものですので、事前に`SetActiveWindow`にて設定する必要があり、更にアクティブにするためには当該アプリケーションを`SetForegroundWindow`にて前面にする必要があります。

[code]

    SetForegroundWindow(lnghWndTarget)
    SetActiveWindow(lnghWndTarget)
    SendKeys.SendWait("q{(}{)}{ENTER}")
    
[/code]

* * *

それとは別に`HWND`に対して32bitの`Integer`を使用していますが、64bit環境のようですので`IntPtr`にすべきです。


CC BY-SA 3.0
2016-08-15T02:47:54.753
28267
2016-08-15T02:47:54.753
4236
28227
answer