2016-11-15 62 views
5

Mesaj kutusu olan Microsoft Access'i bulması gereken bir Visual Basic uygulaması var ve mesaj kutusuna Enter'a bas.vb.net FindWindowex kullanarak başka bir uygulamada messagebox bul

Bu mesajı takip ettim (FindWindow FindWindowEx).

O Erişim bulur ve ön plana getiriyor ama mesaj kutusunu bulup önüne getirmek istemiyor:

enter image description here

Public Class Form1 

Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As IntPtr) As Long 

Private Declare Auto Function FindWindow Lib "user32.dll" (_ 
ByVal lpClassName As String, _ 
ByVal lpWindowName As String _ 
) As IntPtr 

Private Declare Auto Function FindWindowEx Lib "user32.dll" (_ 
ByVal hwndParent As IntPtr, _ 
ByVal hwndChildAfter As IntPtr, _ 
ByVal lpszClass As String, _ 
ByVal lpszWindow As String _ 
) As IntPtr 

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    Dim hWnd As IntPtr 
    hWnd = FindWindow("OMain", Nothing) 

    MsgBox(hWnd) 'FINDS 1640402 

    Dim hWndChild1 As IntPtr = _ 
    FindWindowEx(hWnd, IntPtr.Zero, "#32770 (Dialog)", "Microsoft Access") 

    MsgBox(hWndChild1) 'FIRST PROBLEM IT FINDS ZERO HERE 

    Dim hWndChild1Button As IntPtr = _ 
    FindWindowEx(hWndChild1, IntPtr.Zero, "Button", "OK") 

    MsgBox(hWndChild1Button) 'ALSO FINDS ZERO HERE 

    If hWndChild1Button <> IntPtr.Zero Then 
    SetForegroundWindow(hWndChild1Button) 
    SendKeys.SendWait("{Enter}") 
    End If 

End Sub 
End Class 

enter image description here enter image description here

enter image description here enter image description here

cevap

6

Bu kod doğru winapi işlevini kullanmıyor. FindWindowEx() alt pencereleri bulabilir, ancak MsgBox() tarafından görüntülenen pencere bir alt pencere değildir. FindWindow() ile bulabileceğiniz türden üst düzey bir penceredir.

Ancak bu işlev kapatmak istediğiniz belirli mesaj kutusunu bulmak için yeterince iyi değil. EnumThreadWindows() ile aynı iş parçacığının sahip olduğu pencereleri sıralamak için kullanabileceğiniz daha iyi bir yaklaşım gereklidir. MsgBox() ile ilgili güzel bir şey, diyalog kutusunun modal olması nedeniyle sadece böyle bir pencere olacak.

SendKeys() yeterince iyi değil, yalnızca ileti kutusu ön planda ise düzgün çalışır. Gerçekten daha iyi bir yaklaşım, BM_CLICK mesajını göndererek düğmeyi tıklamaktır.

Imports System.Runtime.InteropServices 
Imports System.ComponentModel 
Imports System.Text 

Module Module1 
    Sub Main() 
     '' Find the MS-Access host window 
     Dim access = FindWindow("OMain", Nothing) 
     If access = IntPtr.Zero Then Throw New Win32Exception() 
     '' Enumerate the windows owned by the same thread 
     Dim pid As Integer 
     Dim tid = GetWindowThreadProcessId(access, pid) 
     If tid = 0 Then Throw New Win32Exception() 
     EnumThreadWindows(tid, AddressOf ClickOkButton, Nothing) 
    End Sub 

    Private Function ClickOkButton(hWnd As IntPtr, lp As IntPtr) As Boolean 
     '' Verify the class name is #32770 
     Dim buf As New StringBuilder(256) 
     GetClassName(hWnd, buf, 256) 
     If buf.ToString <> "#32770" Then Return True 
     '' Find the OK button (control ID 2) 
     Dim okbutton = GetDlgItem(hWnd, 2) 
     If okbutton = IntPtr.Zero Then Return True 
     '' Activate the dialog, just in case 
     SetActiveWindow(hWnd) 
     '' Click the button 
     SendMessage(okbutton, BM_CLICK, IntPtr.Zero, IntPtr.Zero) 
     '' Done, no need to continue enumerating windows 
     Return False 
    End Function 
End Module 

Friend Module NativeMethods 
    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> 
    Friend Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr 
    End Function 

    <DllImport("user32.dll", SetLastError:=True)> 
    Friend Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer 
    End Function 

    Friend Delegate Function EnumThreadDelegate(hWnd As IntPtr, lParam As IntPtr) As Boolean 

    <DllImport("user32.dll", SetLastError:=True)> 
    Friend Function EnumThreadWindows(dwThreadId As Int32, lpfn As EnumThreadDelegate, lParam As IntPtr) As Boolean 
    End Function 

    <DllImport("user32.dll", CharSet:=CharSet.Auto)> 
    Friend Function GetClassName(ByVal hWnd As System.IntPtr, ByVal lpClassName As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer 
    End Function 

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> 
    Friend Function GetDlgItem(ByVal hDlg As IntPtr, id As Integer) As IntPtr 
    End Function 

    <DllImport("user32.dll", SetLastError:=True)> 
    Friend Function SetActiveWindow(ByVal hWnd As IntPtr) As IntPtr 
    End Function 

    <DllImport("user32.dll")> 
    Friend Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByVal lp As IntPtr) As IntPtr 
    End Function 

    Friend Const BM_CLICK As Integer = &HF5 
End Module 

Olağan tavsiyem favor UI Automation şudur: Bir Erişim formu kullanarak, kodu test edilmiştir.

+0

Teşekkür ederiz! Şimdi test edeceğim ve geri bildirim vereceğim :) – Wilest

+0

Bunu kaydediyorum ... tanrım nedenini biliyor. – Jaxedin