vb.net在另一个应用程序中使用FindWindowex查找消息框

问题描述:

我有一个可视化的基本应用程序,它需要找到带有消息框的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

代码没有使用正确的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