I have a piece of code in vb.net to open a web link for an application and to download a file from the page. The web browser loads the page and the program auto clicks the link on the page to download the file which then makes the "View Downloads - Internet Explorer" window in IE 11 to pop up as shown below:
Internet Explorer 11- VIew Downloads window
I managed to activate the window but not able to click the Save button to automatically download the file without user intervention. The code that I tried to activate and click the button is as below
Private Declare Auto Function FindWindow Lib "user32" (ByVal ClassName As String, ByVal WindowTitle As String) As IntPtr
Private Declare Auto Function FindWindowEx Lib "user32" (ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal ClassName As String, ByVal WindowTitle As String) As IntPtr
Private Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As IntPtr
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Dim ParentWndHandle As IntPtr
ParentWndHandle = FindWindow("#32770", "View Downloads - Internet Explorer")
If ParentWndHandle <> IntPtr.Zero Then
Dim ChildWndHandle As IntPtr
ChildWndHandle = FindWindowEx(ParentWndHandle, vbNullString, "DirectUIHWND", vbNullString)
Dim btn1 As IntPtr = FindWindowEx(ChildWndHandle, IntPtr.Zero, "Button", "&Save")
SendMessage(ChildWndHandle, WM_ACTIVATE, WA_ACTIVE, 0)
SendMessage(ChildWndHandle, WM_COMMAND, VK_RETURN, IntPtr.Zero)
End If
End Sub
I think your issue might be the same as this thread: You need to use SetActiveWindow before SendMessage.
Or can you extract the file url? If so, you can refer to this doc to use the simple DownloadFile method to download files:
My.Computer.Network.DownloadFile(
"http://www.example.com/downloads/abc.txt",
"C:\Documents and Settings\All Users\Documents\abc.txt")
Related
The Goal:
I am trying to create a Visual Basic program that will execute some code whenever any new program window is displayed on screen. Just for an easy to understand example: When I launch a program like File Explorer, I want a message box to be displayed when the window for File Explorer is displayed on screen.
The Problem:
Using the code I provided below, my desired outcome works correctly. However, it will also display a message box whenever something like a context menu is displayed as well. I do not want this. I only want a message box to be displayed whenever an actual program window is displayed. I've tried adding checks for checking if the window has 'minimize', 'maximize', and 'close' buttons. But after adding those checks, a message box no longer gets displayed at all, even with a window that has caption buttons, like File Explorer.
This is my code:
Private Declare Function GetForegroundWindow Lib "user32.dll" () As IntPtr
Declare Auto Function SetWinEventHook Lib "user32.dll" (ByVal eventMin As Integer, ByVal eventMax As Integer, ByVal hmodWinEventProc As IntPtr, ByVal lpfnWinEventProc As WinEventDelegate, ByVal idProcess As Integer, ByVal idThread As Integer, ByVal dwflags As Integer) As IntPtr
Declare Auto Function UnhookWinEvent Lib "user32.dll" (ByVal hWinEventHook As IntPtr) As Boolean
Delegate Sub WinEventDelegate(ByVal hWinEventHook As IntPtr, ByVal eventType As Integer, ByVal hwnd As IntPtr, ByVal idObject As Integer, ByVal idChild As Integer, ByVal dwEventThread As Integer, ByVal dwmsEventTime As Integer)
Const WINEVENT_OUTOFCONTEXT As Integer = 0
Const EVENT_OBJECT_CREATE As Integer = &H8000
Private hook As IntPtr = IntPtr.Zero
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
hook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, IntPtr.Zero, AddressOf WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT)
End Sub
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
UnhookWinEvent(hook)
End Sub
Private Sub WinEventProc(ByVal hWinEventHook As IntPtr, ByVal eventType As Integer, ByVal hwnd As IntPtr, ByVal idObject As Integer, ByVal idChild As Integer, ByVal dwEventThread As Integer, ByVal dwmsEventTime As Integer)
Dim windowTitle As String = GetWindowText(hwnd)
If windowTitle <> "" AndAlso IsPopupWindow(hwnd) Then
msgbox("New Window Detected")
End If
End Sub
Private Function IsPopupWindow(ByVal hwnd As IntPtr) As Boolean
Dim style As Long = GetWindowLong(hwnd, GWL_STYLE)
Return (style And WS_POPUP) = WS_POPUP
End Function
Declare Auto Function GetWindowLong Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
Private Const GWL_STYLE As Integer = -16
Private Const WS_POPUP As Long = &H80000000
Private Function GetWindowText(ByVal hwnd As IntPtr) As String
Dim textLength As Integer = GetWindowTextLength(hwnd) + 1
Dim text As String = New String(" "c, textLength)
GetWindowText(hwnd, text, textLength)
Return text.Trim()
End Function
Declare Auto Function GetWindowText Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal lpString As String, ByVal nMaxCount As Integer) As Integer
Declare Auto Function GetWindowTextLength Lib "user32.dll" (ByVal hWnd As IntPtr) As Integer
What approach could I use to better listen for the creation of new program windows? Or, how could I fix my code?
EVENT_OBJECT_CREATE gets triggered for all kinds of objects, not just windows. You will have to retrieve the created object's window class name via GetClassName() and ignore whichever classes you don't want to process. Menus have a standard class name of #32768.
I can get text from external application text box but now I want to get text from my desired text box from external application.
My English is not so good that's why see Image Below.
The Below Code Return The First Text Box Value Only.
Imports System.Runtime.InteropServices
Public Class Form1
Private Const WM_GETTEXT As Integer = &HD
Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As Integer, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function FindWindowEx(ByVal parentHandle As IntPtr, _
ByVal childAfter As IntPtr, _
ByVal lclassName As String, _
ByVal windowTitle As String) As IntPtr
End Function
Declare Auto Function FindWindow Lib "user32.dll" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'Find the running notepad window
Dim Hwnd As IntPtr = FindWindow(Nothing, TextBox1.Text)
'Alloc memory for the buffer that recieves the text
Dim Handle As IntPtr = Marshal.AllocHGlobal(100)
'send WM_GWTTEXT message to the notepad window
Dim NumText As Integer = SendMessage(Hwnd, WM_GETTEXT, 50, Handle)
'copy the characters from the unmanaged memory to a managed string
Dim Text As String = Marshal.PtrToStringUni(Handle)
'Display the string using a label
Label1.Text = Text
'Find the Edit control of the Running Notepad
Dim ChildHandle As IntPtr = FindWindowEx(Hwnd, IntPtr.Zero, "Edit", Nothing)
'Alloc memory for the buffer that recieves the text
Dim Hndl As IntPtr = Marshal.AllocHGlobal(200)
'Send The WM_GETTEXT Message
NumText = SendMessage(ChildHandle, WM_GETTEXT, 200, Hndl)
'copy the characters from the unmanaged memory to a managed string
Text = Marshal.PtrToStringUni(Hndl)
'Display the string using a label
Label2.Text = Text
End Sub
End Class
You'll have to loop through children of the main window (External Application) and get their properties.
You'll use the following:
<DllImport("User32.dll")> _
Public Function EnumChildWindows _
(ByVal WindowHandle As IntPtr, ByVal Callback As EnumWindowProcess, _
ByVal lParam As IntPtr) As Boolean
End Function
Public Delegate Function EnumWindowProcess(ByVal Handle As IntPtr, ByVal Parameter As IntPtr) As Boolean
Public Function GetChildWindows(ByVal ParentHandle As IntPtr) As IntPtr()
Dim ChildrenList As New List(Of IntPtr)
Dim ListHandle As GCHandle = GCHandle.Alloc(ChildrenList)
Try
EnumChildWindows(ParentHandle, AddressOf EnumWindow, GCHandle.ToIntPtr(ListHandle))
Finally
If ListHandle.IsAllocated Then ListHandle.Free()
End Try
Return ChildrenList.ToArray
End Function
For for details, check this How can I get properties of controls contained in a popup message box using VB.Net
' try this on excel vbe
External_application_handle=findwindow(vbNullString,"External_application")
textbox_1_handle=findwindowex(External_application_handle,0&,"Edit",vbNullString)
next_handle=textbox_1_handle
textbox_2_handle=findwindowex(External_application_handle,next_handle,"Edit",vbNullString")
Length = SendMessage(textbox_2_handle, WM_GETTEXTLENGTH, 0,0)
buffer$=space(Length)
call sendmessage(textbox_2_handle,Length+1,buffer$)
msgbox buffer
I want to send "{TAB}" Key to another application window(send the key to the window not to textbox).
I tried:
SendMessage(hWnd, WM_SETHOTKEY, VK_TAB, 0)
Nothing happened.
my goal is:
send tab key to my application Or other application when the application window is not in focus.
(i know that sendkey is not professional in this case there is no choice(This is the first time that I'm using it).)
I made many attempts and I always returned to the same result:
Nothing happened.
Does anyone know the answer?
SendKeys requires the application that you are sending the Keys to, to be active.
From above Link:
Use SendKeys to send keystrokes and keystroke combinations to the active application.
I order to get around this limitation you will have to resort to using the WinApi Functions.
FindWindow pInvoke.net
FindWindowEx pInvoke.net
sendMessage pInvoke.net
See this MSDN Forum Post for an example
Here is a modified example from that Posting:
Public Class Form1
Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd As IntPtr, ByVal hWndChildAfterA As IntPtr, ByVal lpszClass As String, ByVal lpszWindow As String) As IntPtr
Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As String) As IntPtr
Const WM_SETTEXT As Integer = &HC
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim destination As IntPtr = FindWindow(Nothing, "Untitled - Notepad")
Dim destControl As IntPtr = FindWindowEx(destination, IntPtr.Zero, "Edit", Nothing)
SendMessage(destControl, WM_SETTEXT, IntPtr.Zero, "Hello" & vbTab & "GoodBye" & vbCrLf)
End Sub
End Class
Added an Additional Example using WM_KEYDOWN I created another small application with the Window Title set to TestForm and overrode the WndProc Method to determine if the application got the TabKey.
Sending Form
Public Class Form1
Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As IntPtr
Const WM_KEYDOWN As Integer = &H100
Const VK_TAB As Integer = &H9
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim destination As IntPtr = FindWindow(Nothing, "TestForm")
SendMessage(destination, WM_KEYDOWN, VK_TAB, 0)
End Sub
End Class
Test Form
Put a breakpoint on MyBase.WndProc(m) and look at m to see what has been sent.
Public Class Form1
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
End Sub
End Class
Having struggled with this type of this a few times before, i would suggest a couple of things to look at.
The 1st is autoit which includes a dll you can reference from vb.net, and is very simple you use, and well documented. I tend to use that whenever i need to control a 3rd party program.
The other is the ui automation classes
See this for an example:
http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html
you need make the other window active first. check Change focus to another window in VB.NET . then use send key.
I'm adding a SDE feature class into ArcMap and before it adds in I have to click the ok button on the "Connection Details" Window. Is there a way to click the ok button by code? I was thinking maybe it could be done by using Window notification code (e.g. code below), however I'm not seeing any option for button click Ok or Cancel. Maybe it could be done by "Windows.Forms.DialogResult.Ok" somehow or by getting the focus of the ok button?
Thanks
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Const WM_CLOSE = &H10
'Close SDE connection details dialog
Dim WinWnd As Long, Ret As String
'Ask for a Window title
Ret = "Connection Details"
If Ret = "" Then Exit Sub
'Search the window
WinWnd = FindWindow(vbNullString, Ret)
'If WinWnd = 0 Then Messagebox.show "Couldn't find the window ...": Exit Sub
'Post a message to the window to close itself
PostMessage WinWnd, WM_CLOSE, 0&, 0&
I can think of two ways to do so:
You can find the OK button position (using FindWindowEx and GetWindowRect), place the cursor on the button (SetCursorPosition) and simulate a mouse click (mouse_event.) Or you can set focus on the button and simulate pressing Enter key (with keyb_event).
Send BM_CLICK message to OK button's handle.
I personally like the second approach better:
<Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True, CharSet:=Runtime.InteropServices.CharSet.Auto)> _
Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function
Public BM_CLICK As Integer = &HF5
SendMessage(`OK BUTTON HANDLE`, BM_CLICK, 0, 0); // The button handle can be found with FindWindowEx
My VB.NET application is suposed to monitor what application currently is running in the topmost window. I have tried the following approach using a timer:
Declare Function GetActiveWindow Lib "user32" () As System.IntPtr
Declare Function GetForegroundWindow Lib "user32" () As System.IntPtr
Public Declare Auto Function GetWindowText Lib "user32" _
(ByVal hWnd As System.IntPtr, _
ByVal lpString As System.Text.StringBuilder, _
ByVal cch As Integer) As Integer
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim Caption As New System.Text.StringBuilder(256)
Dim hWnd As IntPtr = GetForegroundWindow()
GetWindowText(hWnd, Caption, Caption.Capacity)
'Caption now holds the title of the topmost window
End Sub
By this I can see that for example Outlook or Internet Explorer is the topmost window as the name is in Window's title bar. However, if the user crates a new mail in Outlook the title of the window is "Untitled message" givning no hint of what application is running in the the window.
How do I get what application is connected to the topmost window?p>
Help is appreciated!
You need to pinvoke GetWindowThreadProcessId(). That gets you the ID of the process that owns the window. Back to managed code, Process.GetProcessById() gives you details of the process.