2016-11-15 43 views
5

我有一個可視化的基本應用程序,它需要找到帶有消息框的Microsoft Access,然後將回車鍵發送到消息框。vb.net在另一個應用程序中使用FindWindowex查找消息框

我關注了這個帖子(FindWindow FindWindowEx)。

它發現訪問和它帶來的前景,但它並不想找到該消息框,並把它前面:

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

回答

6

代碼沒有使用正確的winapi函數。 FindWindowEx()可以找到子窗口,但MsgBox()顯示的窗口不是子窗口。它是一個頂級窗口,您可以使用FindWindow()找到這種窗口。

但是,該功能不足以找到要關閉的特定消息框。需要一個更好的方法,可以使用EnumThreadWindows()枚舉同一線程擁有的窗口。 MsgBox()的好處是隻有一個這樣的窗口,因爲對話框是模態的。

SendKeys()的確不夠好,它只有在消息框處於前景時才能正常工作。更好的方法是通過發送BM_CLICK消息來實際點擊按鈕。測試代碼,使用訪問形式:

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 

通常的建議是favor UI Automation

+0

謝謝!我會現在測試,並給予反饋:) – Wilest

+0

我保存這個......上帝知道爲什麼。 – Jaxedin

相關問題