This question already has an answer here:
How to make a window active in vb.net
(1 answer)
Closed 5 years ago.
I'm writing a simple Visual Basic app to help me launch global hotkeys by the press of a taskbar button.
To do this, I basically set the app to minimize itself back to the taskbar. I then want to activate the taskbar itself (not the previously active program) so I can use SendKeys to do these keypresses. In my test, the keypresses get registered. Its just that I can't seem to find out how to actually activate the taskbar from my program.
If I use AppActivate, I need the processID or the window title.
So it seems best to use Windows API's to do it, but I'm not getting the result I'm after either and I must be doing something wrong.
Here's my code:
Public Class Form1
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
Private Sub Form1_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.GotFocus
Me.WindowState = FormWindowState.Minimized
Dim intReturn As Integer = FindWindow("Shell_traywnd", "")
AppActivate(intReturn)
SendKeys.Send("%1")
MsgBox("test")
End Sub
End Class
The error I'm getting is that there's no process by this ID running.
FindWindow will return a hwnd handle, not a processID. You will need to use the function SetForegroundWindow to activate it.
Your code becomes as follows:
Public Class Form1
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Integer) As Integer
Private Sub Form1_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.GotFocus
Me.WindowState = FormWindowState.Minimized
Dim intReturn As Integer = FindWindow("Shell_traywnd", "")
SetForegroundWindow(intReturn)
SendKeys.Send("%1")
MsgBox("test")
End Sub
End Class
Related
I am trying to detect whether or not a window is open (and being used by the user). I have used code from this forum but can't get it to work, here is what I've got:
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Sub btnCheckWindow_Click(sender As Object, e As EventArgs) Handles btnCheckWindow.Click
Dim lngFindIt As Long
lngFindIt = FindWindow(vbNullString, "lkhsdlfhslfh")
If lngFindIt = 0 Then
MsgBox("It is not here")
Else
MsgBox("I found the sucker.")
End If
End Sub
Upon running the program and clicking a button I get "I found the sucker." despite definitely not having a window called "lkhsdlfhslfh" existing let alone open.
How do I fix this?
Your method signature is incorrect. It should return IntPtr, not Long.
Try the following:
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Private Sub btnCheckWindow_Click(sender As Object, e As EventArgs) Handles btnCheckWindow.Click
Dim result As IntPtr= FindWindow(Nothing, "lkhsdlfhslfh")
If result = IntPtr.Zero Then
MsgBox("Window not found.")
Else
MsgBox("Found it.")
End If
End Sub
Alternatively, you could use <DllImport>, which is the standard way in .NET:
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Private Shared Function FindWindow(
ByVal lpClassName As String,
ByVal lpWindowName As String) As IntPtr
End Function
Note that unless you're dealing with an ancient program, you should probably use a Unicode charset. This means using FindWindowW (instead of FindWindowA) if you go with Declare or CharSet.Unicode if you go with <DllImport>.
I am having trouble bringing a window to focus. All examples show using FindWindow function and calling SetForegroundWindow, but this did not work.
Here is what that code looked like
thandle = FindWindow(Nothing, "title of window")
SetForegroundWindow(thandle)
I then tried the ShowWindow functions. The below code worked if the window was minimized, and if the window wasn't maximized but it refused to bring focus to the window if it was already maximized.
If IsIconic(thandle) Then
ShowWindow(thandle, 9)
Else
ShowWindow(thandle, 3)
So then I came up with the work around that if the window isn't minimized, minimize it and then maximize it.
If IsIconic(thandle) Then
ShowWindow(thandle, 9)
Else
ShowWindow(thandle, 7)
ShowWindow(thandle, 9)
End If
I would really like to know why SetForegroundWindow does not bring the window to the foreground
Here is my code:
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 Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim thandle = FindWindow(Nothing, "Calculator")
SetForegroundWindow(thandle)
End Sub
I'm attempting to send automated keystrokes to an application that does not support copy+paste via a small VB form. The form loads data from a text file and uses SendKeys to fire it over once I click a button.
Everything appears to work except for the ShowWindow portion. I'm currently testing using Notepad and, with one exception, I can't seem to get ShowWindow to kick focus to Notepad. Obviously I'm worried it will do the same to the application I'll eventually be running this against (I don't currently have access to it). The only ShowWindow parameter that makes Notepad active is SW_SHOWMAXIMIZED. SW_SHOW and SW_SHOWNORMAL don't appear to do anything while SW_RESTORE will restore Notepad if minimized but my VB form remains the active window.
I'm not a programmer but I had made the mistake of telling my boss I dabbled in Pascal Turbo in high school (over a decade ago) so I'm the one stuck with trying to make this work. My current code cobbled together from S.O. and other sources:
(I'm running Windows 7 and using MVSE2013)
Imports System.Runtime.InteropServices
Public Class Form1
Private Declare Function FindWindow _
Lib "user32" _
Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As ShowWindowCommands) As Boolean
End Function
Enum ShowWindowCommands As Integer
SW_SHOWNORMAL = 1
SW_SHOWMAXIMIZED = 3
SW_RESTORE = 9
End Enum
Private Sub Form1_Load
[form]
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim lHwnd As IntPtr = FindWindow("Notepad", vbNullString)
If lHwnd <> IntPtr.Zero Then
ShowWindow(lHwnd, ShowWindowCommands.SW_SHOWNORMAL)
SendKeys.Send(TextBox1.Text)
Else
[blah blah error handling]
End If
End Sub
I'd try another technique like SetForegroundWindow but I read it doesn't play nice with Windows 7.
Found what I hope will be a passable workaround from PInvoke. I ended up swapping this block:
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow _
As ShowWindowCommands) As Boolean
End Function
For this:
Public Declare Function BringWindowToTop Lib "user32" (ByVal hwnd As IntPtr) As Boolean
And then this line:
ShowWindow(lHwnd, ShowWindowCommands.SW_SHOWNORMAL)
For this:
BringWindowToTop(lHwnd)
I realize there are functional differences between the two but the change works in my specific instance so I'm happy.
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.
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.