表示したダイアログのボタンを即押しするには?

解決


じょじょえん  2005-06-14 03:43:35  No: 122559

初めて質問いたします。

現在VisualBasic6.0(SP5)とWIN32APIを使って
「他アプリケーション(市販されたプログラム)の操作」をするプログラムを
作っています。

やりたい処理は「コマンドボタンをクリックしたときに表示されるダイアログ
から目的のキャプションがついたボタン(「はい」「いいえ」など)を探し出す」
(その後に探し出したボタンをクリックする)ものなのですが、ボタンクリック
で出てきたダイアログからボタンを即座に探し出すことができません。
(ダイアログを既に開いた状態で同処理を行うとボタン検索ができます。
アプリケーションのフォームとダイアログのタイトルは両方とも同じです)

アプリケーションのクラスとダイアログのクラス(#32770)を使って
ウィンドウハンドルを導くことはできるのですが、APIを本格的に
使うのは初めてなので解決法をうまく導くことができません(T-T) 

解決策に繋がるものをご教授願えれば幸いです。

---------(やりたい処理のソース(API定義は割愛))
Public Function MsgPic(ByVal strWName As String, ByVal strBName As String) As Boolean
  
    Dim WINDOW_NAME As String   '* フォーム・ダイアログのキャプション
    Dim BUTTON_NAME As String   '* ボタンのキャプション
    Dim hWnd      As Long
    Dim hChild    As Long
    Dim i         As Long
    Dim lRet      As Long
        
    MsgPic = False
    
    WINDOW_NAME = strWName
    BUTTON_NAME = strBName

    'フォームのハンドルを取る
    hWnd = FindWindow(vbNullString, WINDOW_NAME)
    If hWnd = 0 Then
        Exit Function
    End If

    'ダイアログのハンドルを取る
    hChild = FindWindowEx(hWnd, 0, "#32770", WINDOW_NAME)
    If hChild = 0 Then
        Exit Function
    End If

    'ウィンドウ内の部品名をリストに列記
    frmMain.List1.Clear
    lRet = EnumChildWindows(hChild, AddressOf EnumChildProc, 0)
   
    'リストから目的ボタンのキャプションを探す
    For i = 0 To frmMain.List1.ListCount - 1
       ’目標ボタンのキャプションと一致するか  
      If InStr(1, frmMain.List1.List(i), BUTTON_NAME) > 0 Then
            MsgPic = True
            Exit Function
       End If
    Next i
    
End Function

Public Function EnumChildProc(ByVal hWnd As Long, lParam As Long) As Long

    Dim Ret As Long
    Dim Leng As Long
    Dim Name As String
        
    'バッファ確保
    Name = String(255, Chr(0))
    Leng = Len(Name)
       
    '名前を取得する
    Ret = GetWindowText(hWnd, Name, Leng)
    '* 子ウィンドウがなくなるまで繰り返す
    If Ret <> 0 Then
        frmMain.List1.AddItem Name
    End If
        
    EnumChildProc = 1

End Function


3−t  2005-06-14 09:00:05  No: 122560

>即座に探し出すことができません
という原因は

    'フォームのハンドルを取る
    hWnd = FindWindow(vbNullString, WINDOW_NAME)
    If hWnd = 0 Then
        Exit Function
    End If

    'ダイアログのハンドルを取る
    hChild = FindWindowEx(hWnd, 0, "#32770", WINDOW_NAME)
    If hChild = 0 Then
        Exit Function
    End If

のいずれかでウィンドウハンドルを取得するのに失敗しているからですか?
確認してみてください。


じょじょえん  2005-06-14 18:36:57  No: 122561

>3−t様

昨日上げたソースに「どこまで処理が進むか」チェックしてみたところ、

'ダイアログのハンドルを取る
    hChild = FindWindowEx(hWnd, 0, "#32770", WINDOW_NAME)
    If hChild = 0 Then
        Exit Function
    End If

の所でこけてしまう(ハンドル取得に失敗する)ようです。
コマンドボタン(ダイアログを出すもの)のクリック後に
sleepを入れたりdoeventsをいれてダイアログを認識させようと
試みたのですが、うまくいきません。
アプリケーションのフォームに配置されているコマンドボタン
ならうまく取れるのですが・・・。


3−t  2005-06-14 19:23:24  No: 122562

'ダイアログのハンドルを取る
    hChild = FindWindowEx(hWnd, 0, "#32770", WINDOW_NAME)
    If hChild = 0 Then
        Exit Function
    End If

でハンドルが取得できない原因は何ですか?
ダイアログが表示されていないからですか?
確認してみてください。


じょじょえん  2005-06-14 20:49:17  No: 122563

>3−t様
>ハンドルが取得できない原因は何ですか?
ダイアログが表示されていないからですか?

(別関数にて)他アプリケーションのクリックするコマンドボタンが
持っているハンドルを取得しSendMessageでボタンクリックさせると
ダイアログが表示されるのですが、そのダイアログのハンドルを
取得する為にアプリケーションのハンドル(FindWindow)
→ダイアログのハンドル(FindWindowEx)と追って探そうとすると
FindwindowExの結果=0で処理から抜けてしまうようです。
(アプリケーションとダイアログにはウィンドウの親子関係はない?)

例:市販アプリケーションの「ファイル出力」ボタンをクリックさせると
『この内容でファイル出力を行いますか?(はい)(いいえ)』という
内容のダイアログが表示される。
この表示されたダイアログにある(はい)ボタンを探し出したい。
((はい)ボタンを見つけた場合、別関数でボタンクリックを実行する)

ちなみにVB側のソースでは他アプリケーションをAppActivateで
アクティブにしてからクリック処理などを行っています。


3−t  2005-06-14 21:13:34  No: 122564

ダイアログが表示されている状態で実行すれば取得できるのであれば
考えられるのはFindWindowExを実行するタイミングの問題と思ったわけですが

ステップ実行して、ダイアログが表示されるのを確認してから処理を実行しても同じ結果ですか?


じょじょえん  2005-06-14 22:02:48  No: 122565

>3−t様

>ダイアログが表示されている状態で実行すれば取得できるのであれば
>考えられるのはFindWindowExを実行するタイミングの問題と思ったわけですが
>ステップ実行して、ダイアログが表示されるのを確認してから処理を実行しても同じ結果ですか?

ステップ処理で順追って処理を進めるとボタンクリック用関数の
ラスト(BM_CLICKをSendMessageしてダイアログを表示されたところ)
で止まってしまい、ダイアログの検索までたどり着きませんでした。
表示されたダイアログのボタンをEnterキーなどを使って手動でクリック
するとダイアログは消えますが、ダイアログを消した後にダイアログの
検索が実行されました。(手動クリック後にクリック関数を抜ける)

ちなみにクリック用の関数ソースは以下のとおりです。
-----------
Public Sub BtnPush(ByVal strWCls As String, ByVal strWName As String, ByVal strBCls As String, ByVal strBName As String)
  
    Dim WINDOW_CLS  As String   '* フォームのクラス
    Dim WINDOW_NAME As String   '* フォームのキャプション
    Dim BUTTON_CLS  As String   '* ボタンのクラス
    Dim BUTTON_NAME As String   '* ボタンのキャプション
    Dim hWnd      As Long
    Dim hChild    As Long
    Dim sWndText  As String
    Dim lRet      As Long

    WINDOW_CLS = strWCls
    WINDOW_NAME = strWName
    BUTTON_CLS = strBCls
    BUTTON_NAME = strBName    
            
    '大元のハンドルを取る
    hWnd = FindWindow(WINDOW_CLS, WINDOW_NAME)
    If hWnd = 0 Then
        Exit Sub
    End If
   
    'ボタンのハンドルを取る
    hChild = FindWindowEx(hWnd, 0, BUTTON_CLS, BUTTON_NAME)
    If hChild = 0 Then
        Exit Sub
    End If
    SendMessage hChild, WM_ACTIVATE, 1, 0&
    SendMessage hChild, BM_CLICK, 0, 0&
End Sub

クリック関数の呼び出し例(ファイル出力ボタンをクリックさせる場合)

Call BtnPush("TSearchCondition", "SearchCondition", "TButton", "ファイル出力")

-------


3−t  2005-06-14 22:44:14  No: 122566

SendMessage→PostMessageにしても止まってしまいますか?


じょじょえん  2005-06-14 23:07:21  No: 122567

>3−t様
>SendMessage→PostMessageにしても止まってしまいますか?

ボタンクリック用関数のSendMessageをPostMessageに替えて
ステップ処理させたところ、BM_CLICKした後の処理に向かう
(ボタンクリック処理が終了する)ようになりました。
PostMessageを使った方法で試してみようと思います。

t−3様  多数のアドバイスありがとうございました。<(_ _)>


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加