現在、WinAPIを勉強しており、練習としてVBAを用いて、電卓アプリのボタンをクリックしようとしています。
キーを送るのではなく、クリックで行いたいたいと
考えています。
ボタンのハンドルを取得するところまではできましたが、sendMessageでクリックできず、EditBoxに数字が
入りません。
どのようにすればよいのかご教授ください。
よろしくお願い致します。
環境:
WinXP home、 Excel2002、Win付属アプリの電卓v5.1
---作成したプログラム----
'標準モジュールの中身
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Sub Main()
Dim lngWindWnd As Long 'ウィンドウハンドル
Dim ret As Long
Dim hCalc As Long
'アプリケーションタイトルより、ウィンドウハンドルを得ます
lngWindWnd = FindWindow(vbNullString, "電卓")
'8ボタンのハンドル(確実に取れていることを確認
hCalc = FindWindowEx(lngWindWnd, 0, "Button", "8")
ret = SetForegroundWindow(lngWindWnd)
ret = SendMessage(hCalc, WM_LBUTTONDOWN, 0, 0)
End Sub
No.6ベストアンサー
- 回答日時:
>ret = SendMessage(hCalc, WM_LBUTTONDOWN, 0, 0)
>ret = SendMessage(hCalc, WM_LBUTTONUP, 0, 0)
>
>の順に送ってみましたが,電卓ウィンドウが前面に出>てくるだけで,EditBoxに変化が起きませんでした。
まず、PostMessageにしましょう。
しなくても動くかもしれませんが、するべきです。
で、第3引数には、左ボタンをあらわすMK_LBUTTON、
第4引数は、ByVal 0とする必要があります。
#Declareステートメントで、As Anyと宣言しているため。
Win32api.txtのPostMessageの宣言をそのまま使うんだったら、ByVal lParam As Longなので、そのまま0でかまいません。
Const MK_LBUTTON = &H1
ret = PostMessage(hCalc, WM_LBUTTONDOWN, MK_LBUTTON, ByVal 0)
ret = PostMessage(hCalc, WM_LBUTTONUP, MK_LBUTTON, ByVal 0)
ご回答有難うございます。
この#6で教えていただいたとおり
やってみたら、できました。
有難うございます。
自分の勉強のためにも、
他の回答もじっくり読ませていただいてから
質問を締め切ろうと思っています。
ご了承ください。
No.11
- 回答日時:
っていうかよく読むと、、、
「VBA」
でしたね。。。今気づきました。。。
下の長文サンプル無視で、GetDlgCtrlIDを使用するってことだけ読み取ってください。
(taka_tetsuさん。またよろしくです。)
(とーどーあにぃも、またよろしくです。)
また忙しくなるのでロムる予感。
ご回答有難うございます。
>下の長文サンプル無視で、GetDlgCtrlIDを使用するってことだけ読み取ってください。
VBAでコントロール配列を実現しなきゃいけないと
思ってました(^^;
GetDlgCtrlIDを使用するとよいのですね。
了解しました。
No.9
- 回答日時:
>WM_COMMANDにしてるのはコマンドボタンです。
>VBがやってるわけではありません。
言葉が足りなかったようですね^^;
私はこの説明を受けたとき、VB製のコントロールを含め、VBと捉えております。
それと、補足ありがとうございます。
以前の書き込みの時は、VB製のアプリ同士の連携しかしたことがなかったので、スキル不足でした。^^;
それとコントロールIDは下位の方だと思うのですが・・・
いかがでしょう?
No.8
- 回答日時:
>「VBがWM_LBUTTONDOWNとWM_LBUTTONUPを認識して、内部でWM_COMMANDを発行してCLICKイベントが発生するので、WM_COMMANDでクリックを直接呼べばよい」
WM_COMMANDにしてるのはコマンドボタンです。
VBがやってるわけではありません。
>VBはコントロールIDで管理していないので、コントロールIDが常に「0」です。
>んでもって定数:BN_CLICKEDは「0」です。
今回は電卓がターゲットなので、VBアプリではありません。コントロールIDは持っているはずです。
#XPで8のボタンは&H84でした。
なので、
>SendMessageの行を
>Call SendMessage(lngWindWnd, WM_COMMAND, BN_CLICKED, ByVal hCalc)
ということなんで、wParamの指定の仕方が違いますね。
コントロールIDをGetDlgCtrlIDで取得して、上位16ビットにセットする必要があります。
Call SendMessage(lngWindWnd, WM_COMMAND, BN_CLICKED + GetDlgCtrlID(lngWindWnd) * &H10000, ByVal hCalc)
ですね。
>WM_COMMANDはボタンクリックのロジックを、直でたたき呼びます。
ということがおわかりでしたら、親ウィンドウでの処理の振り分けに何を使っているかがTAGOSAKU7さんなら想像つきますよね。
コントロールIDとウィンドウハンドルしかどのボタンから来たメッセージか判断する方法がないんですから。
No.7
- 回答日時:
PostMessage
SendMessage
について触れられているので、ついでに発言。。。
WM_LBUTTONDOWN
WM_LBUTTONUP
の順で送るなら、確かにPostMessageかと思います。
「マウスで押したことにする」という命令だから、その他のグラフィカルな部分にも影響するだろうし。。。
WM_COMMANDで送るならどちらでもよいかと。。。
私の場合は、割り込みをさせないためにWM_COMMANDの時はSendMessageを多用しております。
WM_COMMANDはボタンクリックのロジックを、直でたたき呼びます。
Spy++で見ると一目瞭然です。
それと今回は電卓なので、どちらでもよいかと思うのですが。。。
勝手にtaka_tetsuさんの発言に対しての補足させていただきます。。。
(決して悪意はありません。私の質問にあたなは答えてくれたことがあります。)
私も以前、マウスダウンとマウスアップで、他のアプリケーションを制御しようとしていました。
しかしVBでコマンドボタンのある画面を作り、そのコマンドボタンをtaka_tetsuさんと同様の方式を取ったところ、2回に1回だけ成功するというような状況に陥りました。
個人で登録しているメーリングリストに状況を質問をすると、
「VBがWM_LBUTTONDOWNとWM_LBUTTONUPを認識して、内部でWM_COMMANDを発行してCLICKイベントが発生するので、WM_COMMANDでクリックを直接呼べばよい」
とのレスを戴きました。
No.5
- 回答日時:
えーとですね。
。。VCとかで画面を作ったらわかるのですが、コントロール一つ一つにコントロールIDというのがあります。
VBはコントロールIDで管理していないので、コントロールIDが常に「0」です。
んでもって定数:BN_CLICKEDは「0」です。
本当はコントロールIDをSnedMessageの第3引数に渡します。
SendDlgItemMessage関数を利用する手もあります。(内部ではSendMessageで同じことをしています。)
でわ
※構成
Project1
└Form1
└Command1 ← 「Index = 0」にして、コントロール配列にしてください
※以下サンプル
Option Explicit
Private plngCalWnd As Long
Private Const DEF_CALC_CAP As String = "電卓"
Private Const WM_COMMAND As Long = &H111
Private Const BN_CLICKED As Long = &H0&
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As Any, ByVal cch As Long) As Long
Private Declare Function GetDlgCtrlID Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Sub Command1_Click(Index As Integer)
Dim varWk As Variant
Dim lngBtnWnd As Long
Dim lngDlgCtlID As Long
varWk = Split(Command1(Index).Tag, vbTab)
lngBtnWnd = varWk(0)
lngDlgCtlID = varWk(1)
Call SendMessage(plngCalWnd, WM_COMMAND, lngDlgCtlID, lngBtnWnd)
End Sub
Private Sub Form_Load()
'電卓取得
If Not GetCalc(plngCalWnd) Then
MsgBox "電卓起動失敗"
End
End If
'画面初期設定
Call InitForm
'電卓前面
Call AppActivate(DEF_CALC_CAP)
End Sub
'画面初期設定
Private Sub InitForm()
Dim rectCalc As RECT
Dim lngWnd As Long
'基本のボタンを見せない
Me.Command1(0).Visible = False
'電卓のサイズを取得
Call GetWindowRect(plngCalWnd, rectCalc)
'自分自身を電卓と同じサイズに変更
With rectCalc
Call MoveWindow(Me.hwnd, 0, 0, (.Right - .Left), (.Bottom - .Top), 1)
Do
'ボタンハンドルを取得
lngWnd = FindWindowEx(plngCalWnd, lngWnd, "Button", vbNullString)
'取得できないなら抜ける
If (lngWnd = 0) Then
Exit Do
End If
'電卓と同じボタンを作成
Call CreSameBtn(lngWnd, .Left, .Top + 23)
Loop
End With
End Sub
'指定ハンドルと同じキャプションのボタンを作成
Private Sub CreSameBtn(ByVal inBtnWnd As Long, ByVal inVectH As Long, ByVal inVectV As Long)
Const DEF_BUF_SIZE As Long = &HFF
Dim rectBtn As RECT
Dim lngBtnIndex As Long
Dim btnWk As CommandButton
Dim lngDlgCtlID As Long
Dim lngLen As Long
Dim strCap As String
Dim bytBuf(DEF_BUF_SIZE - 1) As Byte
'新たなコマンドボタンを作成
lngBtnIndex = Command1.UBound + 1
Load Command1(lngBtnIndex)
Set btnWk = Command1(lngBtnIndex)
btnWk.Visible = True
btnWk.TabStop = False
'コントロールIDを取得
lngDlgCtlID = GetDlgCtrlID(inBtnWnd)
'ハンドルとコントロールIDをボタンのタグに保存
btnWk.Tag = inBtnWnd & vbTab & lngDlgCtlID
'ボタンのキャプションを取得
lngLen = GetWindowText(inBtnWnd, ByVal VarPtr(bytBuf(0)), DEF_BUF_SIZE)
strCap = LeftByte(StrConv(bytBuf, vbUnicode), lngLen)
btnWk.Caption = strCap
'ボタンのサイズを取得
Call GetWindowRect(inBtnWnd, rectBtn)
With rectBtn
Call MoveWindow(btnWk.hwnd, (.Left - inVectH), (.Top - inVectV), (.Right - .Left), (.Bottom - .Top), 1)
End With
End Sub
'電卓取得
Private Function GetCalc(Optional otCalcWnd As Long) As Boolean
On Error Resume Next
otCalcWnd = FindWindow(vbNullString, DEF_CALC_CAP)
If otCalcWnd = 0 Then
Call Shell("Calc.exe")
otCalcWnd = FindWindow(vbNullString, DEF_CALC_CAP)
End If
GetCalc = (otCalcWnd <> 0&)
End Function
'LEFT for バイト長
Private Function LeftByte(inValue, ByVal inStart As Long) As String
LeftByte = StrConv(LeftB$(StrConv(inValue, vbFromUnicode), inStart), vbUnicode)
End Function
No.3
- 回答日時:
この回答への補足
早速のご回答ありがとうございます。
また、返信が遅れて申し訳ありません。
教えていただいた参考URLを参考にやってみましたが、
電卓ウィンドウは前面にでてくるのですが、EditBox
は「0」のままで「8」が入ってくれません。
また、ご教授頂ければ幸いです。
---変更した点---
Private Const WM_COMMAND = &H111
Private Const BN_CLICKED = &H0&
を追加し、
SendMessageの行を
Call SendMessage(lngWindWnd, WM_COMMAND, BN_CLICKED, ByVal hCalc)
に変更しました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Access(アクセス) Vba Userformを前面に出すについて 3 2022/04/15 12:29
- Visual Basic(VBA) Vba LongPtrについて教えてください 2 2022/08/19 11:14
- Excel(エクセル) 【マクロ】スクショ印刷がうまく動かない件 5 2022/12/06 17:37
- Visual Basic(VBA) batからexeを実行し戻り値を受け取る バッチからEXEの結果を受け取りたいのですが、 下記のバッ 1 2023/07/04 15:13
- Visual Basic(VBA) 別シートから年齢別の件数をカウントしたいの続き 5 2023/01/24 00:16
- Visual Basic(VBA) batからexeを実行し戻り値を受け取る EXEの実行内容の結果によって、戻り値を0か1かで返したい 1 2023/07/04 16:40
- Visual Basic(VBA) いつもお世話になっております、VBAで教えて頂きたいのですが 2 2022/05/05 22:20
- Visual Basic(VBA) Vbaで数式をポーランド記法に変換するコードを作って実行しようとするとフリーズします。 1 2022/05/24 17:53
- Visual Basic(VBA) VBA 別ブックからの転記の高速化について VBA 別ブックからの転記の高速化についてご教授下さい。 19 2022/07/26 13:07
- Visual Basic(VBA) VBAで質問ですが、皆さんはどの様に導き出しているのでしょうか? 6 2022/05/03 21:53
このQ&Aを見た人はこんなQ&Aも見ています
-
新NISA制度は今までと何が変わる?非課税枠の拡大や投資対象の変更などを解説!
少額から投資を行う人のための非課税制度であるNISAが、2024年に改正される。おすすめの銘柄や投資額の目安について教えてもらった。
-
ExcelVBAでAPIを使って外部ウインドウのエディットテキストを取得する方法
Visual Basic(VBA)
-
親ウインドウにあるOKボタンを押す方法
Visual Basic(VBA)
-
ウインドウハンドルのつかみ方について質問です。
Visual Basic(VBA)
-
-
4
VBAでコントロールのハンドルを取得したい
Visual Basic(VBA)
-
5
EnumChildWindowsの使い方(VBA)
Visual Basic(VBA)
-
6
他アプリケーション’(ウィンドウ)のハンドル取得方法
Visual Basic(VBA)
-
7
他のウィンドウのボタンを自動的に押したい
C言語・C++・C#
-
8
Excel VBAで他アプリケーションの文字列取得
Excel(エクセル)
-
9
WSH or VBの質問
Visual Basic(VBA)
-
10
他アプリの操作(メニューバー)
Visual Basic(VBA)
-
11
SendMessageが失敗するときがある
C言語・C++・C#
-
12
VB.netでFindWindowExやると・・・9222812402616107008!?
Visual Basic(VBA)
-
13
API32 コントロールのEditテキストの文字列の取得・出力について
Visual Basic(VBA)
-
14
VB.NETのSendMessageを教えてください
Visual Basic(VBA)
-
15
今更、VBAでRPA、キーボード操作自動化ってどうやるの?
Visual Basic(VBA)
-
16
VBA SendMessage 無限ループにどうして無限ループになるんですか
Visual Basic(VBA)
-
17
他のアプリケーションとの連携
Visual Basic(VBA)
-
18
LISTBOXで「他アプリ」を操作する
Visual Basic(VBA)
-
19
ダウンロードダイアログをVBAから操作するには?
Visual Basic(VBA)
-
20
VB.NETで子ウィンドウの列挙の仕方がわかりません。
Visual Basic(VBA)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
EXCELでactivexコントロールを...
-
悩みがあろうと、それなりに幸...
-
USB I/Oのデジタル信号をvbaで...
-
カメラスクロールするのを動画...
-
エクセル・VBA CheckBoxのオブ...
-
Labelコントロールの(左右)余...
-
ユーザーフォームで動的(Me.Con...
-
ListViewのチェックボックスに...
-
コンボボックスの文字によるif...
-
エクセル コントロールツール...
-
vb.netで画面のコントロールId...
-
WinAPIで電卓をクリック
-
(VBA)スピンボタンの大量...
-
VBAのフォームでTextBoxがいっ...
-
excelのリストボックスで選択し...
-
VBAのエラーについて、”実行時...
-
C#で角が丸いテキストボックス
-
excel vbaでユーザーフォームに...
-
C# Form上に配置されたコントロ...
-
EXCELのマクロでACCESSのカレン...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
カメラスクロールするのを動画...
-
エクセル・VBA CheckBoxのオブ...
-
vb.netで画面のコントロールId...
-
エクセルVBAでオプションボタン...
-
EXCELでactivexコントロールを...
-
ExcelVBAでListViewが使用できない
-
excelのリストボックスで選択し...
-
ユーザーフォームで動的(Me.Con...
-
フォーム上の現在アクティブな...
-
C#で自分のウインド・ハンド...
-
変数をコントロール型で使用す...
-
VBAのフォームでTextBoxがいっ...
-
コントロールを移動できない
-
Groupboxの配下のコントロール...
-
C#で角が丸いテキストボックス
-
(VBA)スピンボタンの大量...
-
間違えて配置してしまったコン...
-
エクセル コントロールツール...
-
'ckbl' コントロールは作成され...
-
OCXって何ですか?
おすすめ情報