tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルVBで作った別アプリを制御
記事No11855
投稿日: 2017/08/01(Tue) 15:36
投稿者耳たぶ黒
お世話になります。超初心者の耳たぶ黒です。
Win10、VB2015proで作業しています。

質問内容 自分で作成した他のVBアプリ(同じもの複数2〜9個)の特定のボタンを同時に押すアプリを作りたい。そんな事ってできますか?

背景として、VBで6点をbluetoothを使用して受信データを記録するアプリを作りました。その延長線上で24点を順番に記録するアプリを試しに作成したのですが、アプリを起動してからしばらくすると記録時間が1点目と24点目で3〜4秒時間差が発生してしまいました。あくまで同時に記録できないと意味がないので、これはないのかな〜と思いました。(順番じゃなく、同時進行で記録できるプログラムが思いつかない)
試しに、既存の6点を記録するアプリを4つ起動し、データを記録してみたのですが先に作った24点を順番に記録するアプリに見られた時間差の現象が無いようなので、こちらの記録方法でいこうと思っています。アドバイスいただけると助かります。宜しくお願いいたします。

[ツリー表示へ]
タイトルRe: VBで作った別アプリを制御
記事No11859
投稿日: 2017/08/02(Wed) 19:01
投稿者魔界の仮面弁士
> 質問内容 自分で作成した他のVBアプリ(同じもの複数2〜9個)の特定のボタンを同時に押すアプリを作りたい。そんな事ってできますか?

アプリの作り次第ではありますが、たとえばこういう手はあります。

'参照設定:
' UIAutomationClient
' UIAutomationTypes
Imports System.Windows.Automation
Public Class Form1
    Private procs As New List(Of Process)()

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '電卓を10個起動しておき、起動完了まで待機
        Dim tasks As New List(Of Task)()
        For n = 1 To 10
            Dim p = Process.Start("CALC.EXE")
            procs.Add(p)
            tasks.Add(Task.Factory.StartNew(AddressOf p.WaitForInputIdle))
        Next
        Task.WaitAll(tasks.ToArray())
    End Sub

    Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
        'フォームが閉じられたら電卓も閉じる
        For Each p In procs
            Try
                p.CloseMainWindow()
                p.Dispose()
            Catch
            End Try
        Next
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '電卓群の「5」ボタンを取得
        Dim buttonName As String = "5"
        Dim condition As New AndCondition(
            New PropertyCondition(AutomationElement.NameProperty, buttonName),
            New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button))
        Dim buttons = procs.SelectMany(
            Function(p) AutomationElement.FromHandle(p.MainWindowHandle).FindAll(
                            TreeScope.Element Or TreeScope.Descendants, condition
                        ).Cast(Of AutomationElement)()
            ).Select(
                Function(p) TryCast(p.GetCurrentPattern(InvokePattern.Pattern), InvokePattern)
            ).ToArray()

        '「5」ボタン群を一斉にクリック
        Array.ForEach(buttons, Sub(b) b.Invoke())
    End Sub

End Class



あるいは、適当なプロセス間通信で自作アプリ側にコマンドを投げるようにし、
コマンドの受信側となる自作アプリ側に
 「特定のコマンドが渡されたら、該当ボタンの PerfomeClick メソッドを呼び出す」
という機能を用意しておくとか。

[ツリー表示へ]
タイトルRe^2: VBで作った別アプリを制御
記事No11864
投稿日: 2017/08/03(Thu) 17:49
投稿者耳たぶ黒
魔界の仮面弁士さん、回答ありがとうございます。

凄いですねこのプログラム、私は超初心者なんでUIAutomationなんてたどりつけませんでした。
ネットで調べていたら、APIでやれるのかな〜って思ってました。

すごく助かります。ありがとうございました。
このプログラム素晴らしいのですが、私のアプリに対応させようとすると私に知識が無くて困ってます。


   Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
>         '電卓群の「5」ボタンを取得
>         Dim buttonName As String = "5"
→5にはボタンのSPY++で言うところのキャプションの値を代入すれば良いのでしょうか?

>         Dim condition As New AndCondition(
>             New PropertyCondition(AutomationElement.NameProperty, buttonName),
>             New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button))

→上の文のcontroltype.ButtonのButtonはSPY++で調べた時のクラスの項目を記入するのでしょうか?
私のアプリの押したいボタンを確認したところ、クラス WindowsForms10.BUTTON.app.0.141b4となっていました。これをこのままControlTypeの後ろに記入したのですが、エラーで動きませんでした。
アドバイスいただけると助かります。

[ツリー表示へ]
タイトルRe^3: VBで作った別アプリを制御
記事No11866
投稿日: 2017/08/04(Fri) 10:01
投稿者魔界の仮面弁士
SPY++ は hWnd をもつオブジェクトしか取得できませんよね。
しかし MSAA や UIAutomation は、XAML アプリの子要素や
タイトルバーの[最小化][最大化]ボタンなどといった、
固有のウィンドウハンドルを持たないオブジェクトも取得・操作できます。

関連情報として:
http://hanatyan.sakura.ne.jp/vbnetbbs/wforum.cgi?mode=allread&no=11508#11513
http://hanatyan.sakura.ne.jp/vbnetbbs/wforum.cgi?mode=allread&no=8989#8992


> →5にはボタンのSPY++で言うところのキャプションの値を代入すれば良いのでしょうか?
キャプションと同じになることもありますが、実際には別物です。
(そもそも Spy++ では、電卓ボタンのキャプションを拾えないような…)

たとえば 電卓の "C" ボタンの Name は、Windows 10 でも Windows 7 でも "クリア" ですし、
"CE" ボタンの方は、Windows 7 が "項目をクリア"、Windows 10 が "入力のクリア" です。


なお、自作アプリの場合は、AutomationIdProperty を使った方が良いでしょう。
これは、デザイン時のコントロール名(SaveButton とか txtUserName など)です。


> →上の文のcontroltype.ButtonのButtonはSPY++で調べた時のクラスの項目を記入するのでしょうか?
UIオートメーションのコントロールタイプは、SPY++ のクラス名とは別物です。
指定可能な値は下記を参照してみてください。
https://msdn.microsoft.com/ja-jp/library/system.windows.automation.controltype.aspx

ただ、AutomationId が分かっているのであれば、ControlType の AND 条件は不要かと。

[ツリー表示へ]
タイトルRe^4: VBで作った別アプリを制御
記事No11867
投稿日: 2017/08/04(Fri) 11:28
投稿者耳たぶ黒
魔界の仮面弁士様 いつもありがとうございます。

アプリを調べるのをINSPECTに変更しました。SPY++で調べるのが間違ってたんですね。
そうしたら、AutomationIDも分かりました。

教えていただいたプログラムを少し変更して無事自作アプリを動かすことができました。ありがとうございます。

IDはButton2でした。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '電卓群の「接続ボタン」ボタンを取得

        Dim condition As New PropertyCondition(AutomationElement.AutomationIdProperty, "Button2")
        Dim buttons = procs.SelectMany(
            Function(p) AutomationElement.FromHandle(p.MainWindowHandle).FindAll(
                            TreeScope.Element Or TreeScope.Descendants, condition
                        ).Cast(Of AutomationElement)()
            ).Select(
                Function(p) TryCast(p.GetCurrentPattern(InvokePattern.Pattern), InvokePattern)
            ).ToArray()

        '「接続ボタン」ボタン群を一斉にクリック
        Array.ForEach(buttons, Sub(b) b.Invoke())
    End Sub

[ツリー表示へ]