Vb.net find a message in another application using FindWindowex

I have a visual base application that should find Microsoft Access, which has a message box, and then send Enter to the message box.

I followed this post ( FindWindow FindWindowEx ).

It finds Access and brings it to the fore, but it does not want to find the message box and brings it to the fore:

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

+5
source share
1 answer

The code does not use the correct winapi function. FindWindowEx () can find child windows, but the window displayed by MsgBox () is not a child window. This is the top-level window that you can find in FindWindow ().

But this function is not good enough to find the specific message box that you want to close. A more convenient approach is required, which you can use by listing windows belonging to the same thread with EnumThreadWindows (). The good thing about MsgBox () is that there will only be one such window, since the dialog is modal.

SendKeys () is also not accurate enough, it only works correctly if the message field is in the foreground. A much better approach is actually to press a button by sending a BM_CLICK message. Tested code using the access form:

 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 

It is generally recommended that you approve UI automation .

+6
source

Source: https://habr.com/ru/post/1259761/


All Articles