如何用VB.NET的FindWindowEx在另一程序中定位messagebox窗口?

2026-05-06 08:571阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计800个文字,预计阅读时间需要4分钟。

如何用VB.NET的FindWindowEx在另一程序中定位messagebox窗口?

我有Visual Basic应用,需要找到Microsoft Access,它有一个消息框,然后按下Enter键到消息框。我跟着这篇文章(FindWindow, FindWindowEx),它找到了Access并将其带到前台,但它不想找到消息框并将其带到前台。

我有一个visual basic应用程序需要找到Microsoft Access,它有一个消息框,然后Send Enter到消息框.

如何用VB.NET的FindWindowEx在另一程序中定位messagebox窗口?

我跟着这篇文章(FindWindow FindWindowEx).

它找到Access并将其带到前台,但它不想找到消息框并将其带到前面:

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



代码未使用正确的winapi函数. FindWindowEx()可以找到子窗口,但MsgBox()显示的窗口不是子窗口.它是一个顶级窗口,您可以使用FindWindow()找到它.

但该功能不足以找到您要关闭的特定消息框.需要一种更好的方法,您可以使用的方法是使用EnumThreadWindows()枚举同一线程拥有的窗口.关于MsgBox()的好处是,由于对话框是模态的,因此只有一个这样的窗口.

SendKeys()也不够精确,如果消息框在前台,它只能正常工作.更好的方法是通过向BM_CLICK消息发送实际单击按钮.使用Access表单测试的代码:

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.

本文共计800个文字,预计阅读时间需要4分钟。

如何用VB.NET的FindWindowEx在另一程序中定位messagebox窗口?

我有Visual Basic应用,需要找到Microsoft Access,它有一个消息框,然后按下Enter键到消息框。我跟着这篇文章(FindWindow, FindWindowEx),它找到了Access并将其带到前台,但它不想找到消息框并将其带到前台。

我有一个visual basic应用程序需要找到Microsoft Access,它有一个消息框,然后Send Enter到消息框.

如何用VB.NET的FindWindowEx在另一程序中定位messagebox窗口?

我跟着这篇文章(FindWindow FindWindowEx).

它找到Access并将其带到前台,但它不想找到消息框并将其带到前面:

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



代码未使用正确的winapi函数. FindWindowEx()可以找到子窗口,但MsgBox()显示的窗口不是子窗口.它是一个顶级窗口,您可以使用FindWindow()找到它.

但该功能不足以找到您要关闭的特定消息框.需要一种更好的方法,您可以使用的方法是使用EnumThreadWindows()枚举同一线程拥有的窗口.关于MsgBox()的好处是,由于对话框是模态的,因此只有一个这样的窗口.

SendKeys()也不够精确,如果消息框在前台,它只能正常工作.更好的方法是通过向BM_CLICK消息发送实际单击按钮.使用Access表单测试的代码:

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.