具体的にはログアウトして終了したい
朝方のどこか(5:00くらい?)にマーケットスピード2からログアウトしてしまうため、再度ログインが必要となる。テストしようにもこの状態になるのは1日1回、しかも社会人であればその日は取引できないという中で対応していくのは難しいので、いったん深夜にマーケットスピード2をログアウト終了し、朝方7~8時にタスクスケジューラでエクセルを立ち上げる(その際にマーケットスピード2へ自動ログイン)。という対応を取った。というわけでUIAutomationでログアウトボタンを押して、ログアウトして終了ボタンを押す。というVBAを作る必要がある。
とっつきまでが相当面倒
VBA、自動操作でまだ簡単そうだったのがこのUIAutomation、別のアプリを使った方が楽なのではとも思うが、そうすると動作に安定感が少し欠ける。自動売買は確実に動作してほしく、VBA内で完結させたいためこの手法を用いる。
導入
VBAの画面からツール→参照設定よりUIAutomationClientにチェックを入れる。問題はここから。
参考サイトで電卓を用いてこのライブラリの勉強をした方がいいかもしれない。ざっくりと流れは以下のようになる
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\inspect.exe
2021/11/06の私の環境では上記にinspect.exeがあるのでそれを起動する。
実際にマーケットスピード2のログアウトボタンを押すとinspect上にマーケットスピード2のツリーやログアウトボタンの階層やプロパティが表示される。プロパティでボタンの特定に実際に利用できるのはNameプロパティとClassNameプロパティくらいらしい。ログアウトボタンを押した後のログアウトして終了ボタンは同じハンドルで操作できるのは有難く、マーケットスピード2での操作は割と簡単。
環境によると思いますので動作保証はできませんが、コードは以下のようになる。
Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Sub marketspeed_end() Dim Hwnd As Long Hwnd = FindWindow(vbNullString, "MarketSpeed2") Call UiClick2(Hwnd, "ログアウト") Application.Wait (Now() + TimeValue("00:00:02")) Call UiClick2(Hwnd, "ログアウトして終了") End Sub Sub UiClick2(ByVal Hwnd As Long, strBtn As String) Dim uiAuto As CUIAutomation: Set uiAuto = New CUIAutomation Dim uiElm As IUIAutomationElement Dim uiCnd As IUIAutomationCondition Dim uiInvoke As IUIAutomationInvokePattern Set uiElm = uiAuto.ElementFromHandle(ByVal Hwnd) If strBtn = "ログアウト" Then Set uiCnd = uiAuto.CreatePropertyCondition(UIA_NamePropertyId, "ログアウト") Set uiElm = uiElm.FindFirst(TreeScope_Children, uiCnd) Debug.Print (uiElm.CurrentClassName) ElseIf strBtn = "ログアウトして終了" Then Set uiCnd = uiAuto.CreatePropertyCondition(UIA_NamePropertyId, "ログアウトして終了") Set uiElm = uiElm.FindFirst(TreeScope_Subtree, uiCnd) Debug.Print (uiElm.CurrentClassName) End If Set uiInvoke = uiElm.GetCurrentPattern(UIA_InvokePatternId) uiInvoke.Invoke End Sub
FindWindow(vbNullString, “MarketSpeed2”)でマーケットスピード2のウィンドウのIDを取得する。立ち上げてなければ当然存在しないためエラーが出る。
UiClick2でログアウトとログアウトして終了を押す操作を行う。
uiAuto.CreatePropertyConditionで検索対象を指定して(第一引数が検索対象のプロパティ、第二引数が検索対象のプロパティ名)、uiElm.FindFirstで検索する。見つかったらさらに下層の対象まで探す必要がある場合もあるが、 uiElm.FindFirst の第一引数にTreeScope_Subtreeを指定すると、重複する要素がなければ一撃で対象の層まで検索することができる( 第一引数にTreeScope_Childrenを指定すると下の1層のみ検索します)
逆にNameやClassNameが重複した要素があると、想定した要素が検索できておらず、違うボタンを押してしまうこともある。そのため、debug.printでイミディエイトウィンドウに何を取ってきているか表示する(Nameプロパティで検索したならClassNameプロパティ、ClassNameプロパティで検索したならNameプロパティをdebug.printするといいと思います。)
もちろん重複を防ぐためにできるだけ特徴的な名前のプロパティを指定する必要があります。深い階層の場合、一撃で意図したボタンを検索することはほぼ不可能なため、中間に特徴的な名前のプロパティがあればそれを経由して何回か検索することになります。
幸いマーケットスピード2ではログアウトとログアウトして終了は割とユニークな名前の為、それぞれ一度の検索でボタンにたどり着くことができます。
問題はエクセルだがそちらは以下の記事で。
コメント
こんにちは。
最近エクセルを作り始めて、いつも参考にさせていただいてます。
マーケットスピードのアップデートで、アドイン設定しているエクセルを開いたままだとアップデートができなくなっていませんか?
そちらの解決策もあれば、教えていただけると嬉しいです。
コメントありがとうございます。
私はエクセル自体は早朝4時ごろには終了するようにVBAに記載していて、そのあとタスクスケジューラでマケスピ起動して何分か後にタスクスケジューラから終了させています。
その後、数分してタスクスケジューラからエクセルを起動させています。
もっと良い方法があるかもしれないですが、