【VBA×WindowsAPI】Buttonコントロールを操作する
Buttnコントロール(プッシュボタン/オプションボタン/チェックボックス)は、ユーザーがクリックした際に何らかのアクションを発生させるためのコントロールです。本来、Excel VBAだけでは操作不能なExcel以外のアプリケーションのButtonコントロールですが、Windows APIと組み合わせることでボタンの押下をプログラムとして処理することが可能になります。これにより、ユーザーが手入力している作業をExcel外の領域でも自動化することができます。
本ページではそんなButtonコントロールをVBAで操作する方法について解説していきます。コントロールの種類の調べ方をはじめ、テキストボックスやコンボボックス等のその他コントロールの自動化は下記メインページを参照下さい。
Buttonコントロールを操作
Buttonコントロールはユーザーがクリックすることで何らかのアクションが実行されるコントロールです。名前からするといわゆる”プッシュボタン”がイメージされがちですが、チェックボックスやオプションボタン(ラジオボタン)などもこのButtonコントロールに含まれています。
本ページではButtonコントロールに対して「ボタンを押下する方法(プッシュ/オプションボタン)」「値を切り替える方法(チェックボックス)」「値を取得する方法(チェックボックス)」の3つの方法を解説します。RPA操作において操作の最後は[実行]ボタンや[保存]ボタンのようなプッシュボタンの押下であるケースが多いため、Buttonコントロールの操作はかなり重要な要素の1つとなります。
VBAで別アプリケーションのButtonコントロールを操作するには下記のWindows APIを利用します。
それぞれ関数のより詳細な使い方の解説は各関数のリンクページを参照下さい。
FindWindow関数 :指定のウィンドウのハンドルを取得する
FindWindowEx関数 :指定のウィンドウ内にある子ウィンドウのハンドルを取得する
SendMessage関数 :指定のウィンドウにメッセージを送信する
「そもそもWindows APIって何?」という方はコチラ(メインページ)も併せて参照下さい。
サンプルコード
指定のButtonコントロールを操作するサンプルコードは下記の通りです。プッシュボタンの押下、オプションボタンの押下(切り替え)、チェックボックスの値の取得と切り替えを行っています。
メモ帳の「検索」ウィンドウ([Ctrl]+[F])を開いた状態で下記を実行するとコメント記載の処理が各Buttonコントロールに対して行われます。サンプルコードではButtonコントロールとして「検索」ウィンドウの各ボタンを取得していますが、別の領域のButtonコントロールのハンドルを取得すればそのButtonコントロールを操作することが可能です。(1行ずつ実行すると処理内容が確認しやすいです)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
Option Explicit Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr Private Const BM_CLICK As Long = &HF5 'ボタンクリック Private Const BM_GETCHECK As Long = &HF0 'ボタンのチェック状態を取得 Private Const BM_SETCHECK As Long = &HF1 'ボタンのチェック状態をセット Private Const BST_UNCHECKED As Long = &H0 'チェック状態 Private Const BST_CHECKED As Long = &H1 '非チェック状態 '---------------------------------------------------------------- ' メイン処理 '---------------------------------------------------------------- Sub main() Dim hWndSearch As LongPtr Dim hWndBtnPush As LongPtr Dim hWndBtnChk As LongPtr Dim hWndBtnOpt As LongPtr '[検索]ウィンドウハンドル取得 hWndSearch = FindWindow("#32770", "検索") '[キャンセル]ボタンのハンドルを取得 hWndBtnPush = FindWindowEx(hWndSearch, 0, "Button", "キャンセル") '[折り返しあり]チェックボックスのハンドルを取得 hWndBtnChk = FindWindowEx(hWndSearch, 0, "Button", "折り返しあり(&R)") '[上へ]オプションボタンのハンドルを取得 hWndBtnOpt = FindWindowEx(hWndSearch, 0, "Button", "上へ(&U)") 'チェックボックスにチェックを付ける Call SetCheckBoxValue(hWndBtnChk, True) 'オプションボタン押下 Call PushButton(hWndBtnOpt) 'チェックボックス/オプションボタンの値を取得 Debug.Print GetCheckBoxValue(hWndBtnChk) Debug.Print GetCheckBoxValue(hWndBtnOpt) 'プッシュボタン押下 Call PushButton(hWndBtnPush) End Sub '---------------------------------------------------------------- ' Buttonコントロール(プッシュボタン/オプションボタン)を押下する '---------------------------------------------------------------- Private Sub PushButton(ByVal hWndBtn As LongPtr) 'ボタン押下 Call SendMessage(hWndBtn, BM_CLICK, 0, 0) End Sub '---------------------------------------------------------------- ' Buttonコントロール(チェックボックス)の値を切り替える '---------------------------------------------------------------- Private Sub SetCheckBoxValue(ByVal hWndBtn As LongPtr, ByVal bCheck As Boolean) If bCheck = True Then Call SendMessage(hWndBtn, BM_SETCHECK, BST_CHECKED, 0) 'チェックON Else Call SendMessage(hWndBtn, BM_SETCHECK, BST_UNCHECKED, 0) 'チェックOFF End If End Sub '---------------------------------------------------------------- ' Buttonコントロール(チェックボックス/オプションボタン)の値を取得する '---------------------------------------------------------------- Private Function GetCheckBoxValue(ByVal hWndBtn As LongPtr) As Boolean Dim hRet As LongPtr 'チェック状態の取得 hRet = SendMessage(hWndBtn, BM_GETCHECK, 0, 0) Select Case hRet Case BST_CHECKED: GetCheckBoxValue = True Case BST_UNCHECKED: GetCheckBoxValue = False End Select End Function |
コード解説
Windows APIを使ってButtonコントロールの文字列を操作するには下記の手順を行います。操作対象のButtonコントロールハンドルの取得はウィンドウ(アプリケーション)の構造により取得手順が変わるので、Spy++等のツールを使用してウィンドウの構造を調べる必要があります。構造の確認ができたらFindWindowEx関数を使うことで該当コントロールのハンドルを取得することが可能です。
2. 取得したハンドルにボタン押下のメッセージを送信 (プッシュボタン/オプションボタン)
2. 取得したハンドルにチェックの切り替えのメッセージを送信 (チェックボックス)
2. 取得したハンドルにチェック状態取得のメッセージを送信 (チェックボックス)
取得したハンドルにボタン押下のメッセージを送信
Buttonコントロールのハンドルに対して”ボタン押下のメッセージ”を送信することで、そのButtonコントロールを押下する(押下されたことにする)ことができます。メッセージの送信はSendMessage関数を使い、下記のように書きます。
Call SendMessage(hWndBtn, BM_CLICK, 0, 0)
第1引数のhWndBtnにはボタン押下を行う対象のButtonコントロール(基本的にはプッシュボタンかオプションボタン)のハンドル、第2引数にはボタン押下のメッセージ「BM_CLICK」(定数値)、第3引数、第4引数は今回の場合では使用しないので「0」をそれぞれ入力します。
「BM_CLICK」は該当のヘッダーファイル内に定義されていますが、VBAでは関数の呼び出しを行っているだけなので定数自体の定義はされていません。そのため「Const BM_CLICK = &HF5」というかたちでコードの初めに定義しています。(引数として直接「&HF5」を入力しても可)
これにより、指定のButtonコントロールを押下することができます。ボタンの種類としてはプッシュボタンとオプションボタンのいずれかが想定されており、プッシュボタンの場合は押下、オプションボタンの場合は値の切り替えというような手動でマウスクリックしたときと同じ処理が行われます。チェックボックスのハンドルを渡すことでもチェックの切り替えは可能ですが、チェックボックスに対するフォーカスの有無によって動作が不安定であることや、チェックボックス用のメッセージが提供されていることから、チェックボックスの操作においては後述の方法を用いる方が安定した結果が得られます。
取得したハンドルにチェックの切り替えのメッセージを送信
Buttonコントロールのハンドルに対して”チェック切り替えのメッセージ”と合わせてチェックON/OFFのパラメータを送信することで、そのButtonコントロールのチェック状態をONもしくはOFFに切り替えることができます。メッセージの送信はSendMessage関数を使い、下記のように書きます。
Call SendMessage(hWndBtn, BM_SETCHECK, BST_CHECKED, 0) ‘チェックON
Call SendMessage(hWndBtn, BM_SETCHECK, BST_UNCHECKED, 0) ‘チェックOFF
第1引数のhWndBtnにはチェックの切り替えを行う対象のButtonコントロール(チェックボックス)のハンドル、第2引数にはチェックの切り替えメッセージ「BM_SETCHECK」(定数値)、第3引数にはチェック状態を表す「BST_CHECKED」(定数値)もしく「BST_UNCHECKED」(定数値)、第4引数は今回の場合では使用しないので「0」をそれぞれ入力します。
「BM_SETCHECK」「BST_CHECKED」「BST_UNCHECKED」はそれぞれ該当のヘッダーファイル内に定義されていますが、VBAでは関数の呼び出しを行っているだけなので定数自体の定義はされていません。そのため「Const BM_SETCHECK = &HF1」「Const BST_CHECKED = &H1」「Const BST_UNCHECKED = &H0」というかたちでコードの初めに定義しています。
チェックの切り替えは第3引数に入力する定数値により指定することができ、「BST_CHECKED」を入力した場合はチェック状態をONに、「BST_UNCHECKED」を入力した場合はチェック状態をOFFに設定することができます。
取得したハンドルにチェック状態取得のメッセージを送信
Buttonコントロールのハンドルに対して”チェック状態取得のメッセージ”を送信することで、そのButtonコントロールのチェック状態を取得することができます。メッセージの送信はSendMessage関数を使い、下記のように書きます。
hRet = SendMessage(hWndBtn, BM_GETCHECK, 0, 0)
第1引数のhWndBtnにはチェック状態の取得対象のButtonコントロール(チェックボックス)のハンドル、第2引数にはチェック状態取得のメッセージ「BM_GETCHECK」(定数値)、第3引数、第4引数は今回の場合では使用しないので「0」をそれぞれ入力します。これによりチェック状態を表した定数値が戻り値hRetとして取得できます。
「BM_GETCHECK」は該当のヘッダーファイル内に定義されていますが、VBAでは関数の呼び出しを行っているだけなので定数自体の定義はされていません。そのため「Const BM_GETCHECK = &HF0」というかたちでコードの初めに定義しています。
戻り値hRetには「BST_CHECKED」もしく「BST_UNCHECKED」が返されます。
これら定数は上項のチェック切り替えをする際に引数として入力するものと同じです。hWndBtnのチェックがONの場合は「BST_CHECKED」、OFFの場合は「BST_UNCHECKED」が返されます。この戻り値からチェックの有無で分岐処理をすることが可能となっています。
関連情報
VBA×WindowsAPIまとめページ
その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。
参考
Microsoft公式:ウィンドウ メッセージ (Windows とメッセージ) – Win32 apps