プロが教える店舗&オフィスのセキュリティ対策術

現在、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

A 回答 (11件中1~10件)

>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)
    • good
    • 0
この回答へのお礼

ご回答有難うございます。

この#6で教えていただいたとおり
やってみたら、できました。
有難うございます。

自分の勉強のためにも、
他の回答もじっくり読ませていただいてから
質問を締め切ろうと思っています。
ご了承ください。

お礼日時:2004/06/21 23:48

っていうかよく読むと、、、


「VBA」
でしたね。。。今気づきました。。。

下の長文サンプル無視で、GetDlgCtrlIDを使用するってことだけ読み取ってください。


(taka_tetsuさん。またよろしくです。)
(とーどーあにぃも、またよろしくです。)
また忙しくなるのでロムる予感。
    • good
    • 0
この回答へのお礼

ご回答有難うございます。


>下の長文サンプル無視で、GetDlgCtrlIDを使用するってことだけ読み取ってください。

VBAでコントロール配列を実現しなきゃいけないと
思ってました(^^;
GetDlgCtrlIDを使用するとよいのですね。
了解しました。

お礼日時:2004/06/21 23:42

wParamの上位と下位、逆でしたね(^^;;

    • good
    • 0

>WM_COMMANDにしてるのはコマンドボタンです。


>VBがやってるわけではありません。

言葉が足りなかったようですね^^;
私はこの説明を受けたとき、VB製のコントロールを含め、VBと捉えております。


それと、補足ありがとうございます。

以前の書き込みの時は、VB製のアプリ同士の連携しかしたことがなかったので、スキル不足でした。^^;


それとコントロールIDは下位の方だと思うのですが・・・
いかがでしょう?
    • good
    • 0

>「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とウィンドウハンドルしかどのボタンから来たメッセージか判断する方法がないんですから。
    • good
    • 0

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でクリックを直接呼べばよい」
とのレスを戴きました。
    • good
    • 0

えーとですね。

。。
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
    • good
    • 0

#3


でできます。

この回答への補足

早速のご回答ありがとうございます。
また、返信が遅れて申し訳ありません。

#3の方の補足に書かせていただいたのですが、
電卓ウィンドウが前面に出てくるところまでは
よいのですが、EditBoxに変化が起きません。

また、ご教授頂ければ幸いです。

補足日時:2004/06/19 16:12
    • good
    • 0

BN_CLICKEDで出来るかも。



参考URL:http://oshiete1.goo.ne.jp/kotaeru.php3?q=199357

この回答への補足

早速のご回答ありがとうございます。
また、返信が遅れて申し訳ありません。

教えていただいた参考URLを参考にやってみましたが、
電卓ウィンドウは前面にでてくるのですが、EditBox
は「0」のままで「8」が入ってくれません。
また、ご教授頂ければ幸いです。

---変更した点---
Private Const WM_COMMAND = &H111
Private Const BN_CLICKED = &H0&
を追加し、

SendMessageの行を
Call SendMessage(lngWindWnd, WM_COMMAND, BN_CLICKED, ByVal hCalc)

に変更しました。

補足日時:2004/06/19 16:01
    • good
    • 0

まず、マウスメッセージはPostMessageで送りましょう。


次に、WM_LBUTTONDOWNのあとに、WM_LBUTTONUPを送る必要があります。
    • good
    • 1

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A