TechMonster
asked on
Last activated application, vb.net
Does anyone here know how to get the below code to work with GetActiveWindow versus getting foreground window?
Imports System.Runtime.InteropServ ices
Public Class Form1
Inherits System.Windows.Forms.Form
' Shell Events Constants
Public Enum ShellEvents
HSHELL_WINDOWCREATED = 1
HSHELL_WINDOWDESTROYED = 2
HSHELL_ACTIVATESHELLWINDOW = 3
HSHELL_WINDOWACTIVATED = 4
HSHELL_GETMINRECT = 5
HSHELL_REDRAW = 6
HSHELL_TASKMAN = 7
HSHELL_LANGUAGE = 8
HSHELL_ACCESSIBILITYSTATE = 11
End Enum
' API Declares
Public Declare Function RegisterWindowMessage Lib "user32.dll" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Integer
Public Declare Function DeregisterShellHookWindow Lib "user32" (ByVal hWnd As IntPtr) As Integer
Public Declare Function RegisterShellHookWindow Lib "user32" (ByVal hWnd As IntPtr) As Integer
Public Declare Function GetForegroundWindow Lib "user32" () As IntPtr
Public Declare Function SetForegroundWindow Lib "user32" Alias "SetForegroundWindow" (ByVal hWnd As IntPtr) As Integer
Private uMsgNotify As Integer
Private lastWindow As IntPtr
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.TopMost = True
uMsgNotify = RegisterWindowMessage("SHE LLHOOK")
RegisterShellHookWindow(Me .Handle)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Messa ge)
If m.Msg = uMsgNotify Then
Select Case m.WParam.ToInt32
Case ShellEvents.HSHELL_WINDOWA CTIVATED
Debug.WriteLine("window activated")
Dim curWindow As IntPtr = GetForegroundWindow()
If (Not curWindow.Equals(IntPtr.Ze ro)) AndAlso (Not curWindow.Equals(Me.Handle )) Then
lastWindow = curWindow
End If
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If Not lastWindow.Equals(IntPtr.Z ero) Then
SetForegroundWindow(lastWi ndow)
System.Threading.Thread.Sl eep(100)
SendKeys.Send("Hello World...")
End If
End Sub
Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.Canc elEventArg s) Handles MyBase.Closing
DeregisterShellHookWindow( Me.Handle)
End Sub
End Class
************************** ********** ********** ********** ****
Imports System.Runtime.InteropServ
Public Class Form1
Inherits System.Windows.Forms.Form
' Shell Events Constants
Public Enum ShellEvents
HSHELL_WINDOWCREATED = 1
HSHELL_WINDOWDESTROYED = 2
HSHELL_ACTIVATESHELLWINDOW
HSHELL_WINDOWACTIVATED = 4
HSHELL_GETMINRECT = 5
HSHELL_REDRAW = 6
HSHELL_TASKMAN = 7
HSHELL_LANGUAGE = 8
HSHELL_ACCESSIBILITYSTATE = 11
End Enum
' API Declares
Public Declare Function RegisterWindowMessage Lib "user32.dll" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Integer
Public Declare Function DeregisterShellHookWindow Lib "user32" (ByVal hWnd As IntPtr) As Integer
Public Declare Function RegisterShellHookWindow Lib "user32" (ByVal hWnd As IntPtr) As Integer
Public Declare Function GetForegroundWindow Lib "user32" () As IntPtr
Public Declare Function SetForegroundWindow Lib "user32" Alias "SetForegroundWindow" (ByVal hWnd As IntPtr) As Integer
Private uMsgNotify As Integer
Private lastWindow As IntPtr
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.TopMost = True
uMsgNotify = RegisterWindowMessage("SHE
RegisterShellHookWindow(Me
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Messa
If m.Msg = uMsgNotify Then
Select Case m.WParam.ToInt32
Case ShellEvents.HSHELL_WINDOWA
Debug.WriteLine("window activated")
Dim curWindow As IntPtr = GetForegroundWindow()
If (Not curWindow.Equals(IntPtr.Ze
lastWindow = curWindow
End If
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If Not lastWindow.Equals(IntPtr.Z
SetForegroundWindow(lastWi
System.Threading.Thread.Sl
SendKeys.Send("Hello World...")
End If
End Sub
Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.Canc
DeregisterShellHookWindow(
End Sub
End Class
**************************
ASKER
Idle Mind,
Not really sure. I have used the getforegroundwindow and it works for the most part but has recently failed when used with a "web-based" application running on citrix.
The user uses the mouse to designate where the text from my program is going to paste. They click on the destination application and then go back to my program and press "Go."
I was hoping there would an alternate way to capture the last activated application since it is failing with vb.net.
Interesting enough I know a different c++ application works fine and is using hooking to remember the last application. I just don't know the code they are using.
Can you help?
Not really sure. I have used the getforegroundwindow and it works for the most part but has recently failed when used with a "web-based" application running on citrix.
The user uses the mouse to designate where the text from my program is going to paste. They click on the destination application and then go back to my program and press "Go."
I was hoping there would an alternate way to capture the last activated application since it is failing with vb.net.
Interesting enough I know a different c++ application works fine and is using hooking to remember the last application. I just don't know the code they are using.
Can you help?
So basically you need a way to let the user pick a "target" window?
Do you only need the "main" window or do you need to get the hWnd of a specific control in the target window?
Do you only need the "main" window or do you need to get the hWnd of a specific control in the target window?
ASKER
"you need a way to let the user pick a "target" window?" <-- Exactly.
Just the main window should do it. The user picks a text field within the window which places the cursor in it. When they go back to my program and press go it will (should) remember that same window, set it as the active window, then paste some information from my program into the window where the cursor was.
For the most part the getforeground window DID work. Works great with Word and Notepad and some other applications but, if they had an application running with "on top" (the most forefront application) on then it will fail thinking that the forefront application was the last activated window.
Just the main window should do it. The user picks a text field within the window which places the cursor in it. When they go back to my program and press go it will (should) remember that same window, set it as the active window, then paste some information from my program into the window where the cursor was.
For the most part the getforeground window DID work. Works great with Word and Notepad and some other applications but, if they had an application running with "on top" (the most forefront application) on then it will fail thinking that the forefront application was the last activated window.
Try this...
Add three Labels, a TextBox, and a small PictureBox to a form. Make the PictureBox so you can see it by setting the BorderStyle, BackColor or Image properties.
Open up NotePad or Wordpad and then drag the PictureBox onto that window and drop it.
You could use SendKeys.Send() instead of SendMessage().
You could make your app hide or minimize when the user "drags" your PictureBox (making it reappear on MouseUp).
Public Class Form1
Public Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Integer, ByVal yPoint As Integer) As IntPtr
Public Declare Function GetAncestor Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal gaFlags As Integer) As IntPtr
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As IntPtr, ByVal lpString As String, ByVal cch As Integer) As Integer
Public Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As IntPtr) As Integer
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As IntPtr, ByVal lpClassName As String, ByVal nMaxCount As Integer) As Integer
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As IntPtr, ByVal lpdwProcessId As Integer) As Integer
Public Declare Function AttachThreadInput Lib "user32" (ByVal idAttach As Integer, ByVal idAttachTo As Integer, ByVal fAttach As Integer) As Integer
Public Declare Function Putfocus Lib "user32" Alias "SetFocus" (ByVal hWnd As IntPtr) As Integer
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
Public Const GA_ROOT As Integer = 2
Public Const EM_REPLACESEL As Integer = &HC2
Private overWindow As IntPtr
Private mainWindow As IntPtr
Private windowText As String
Private className As String
Private controlText As String
Private Sub PictureBox1_MouseMove(ByVa l sender As Object, ByVal e As System.Windows.Forms.Mouse EventArgs) Handles PictureBox1.MouseMove
If e.Button = Windows.Forms.MouseButtons .Left Then
' for informational purposes...
overWindow = WindowFromPoint(Windows.Fo rms.Cursor .Position. X, Windows.Forms.Cursor.Posit ion.Y)
mainWindow = GetAncestor(overWindow, GA_ROOT)
windowText = New String(Microsoft.VisualBas ic.Chr(0), GetWindowTextLength(mainWi ndow) + 1)
GetWindowText(mainWindow, windowText, Len(windowText))
Label1.Text = "Main Target Window Caption: " & windowText
className = Space(256)
Dim retVal As Long
retVal = GetClassName(overWindow, className, 256)
className = className.Substring(0, retVal)
Label2.Text = "Target Window ClassName: " & className
controlText = New String(Microsoft.VisualBas ic.Chr(0), GetWindowTextLength(overWi ndow) + 1)
GetWindowText(overWindow, controlText, Len(controlText))
Label3.Text = "Target Window Caption: " & controlText
End If
End Sub
Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.Mouse EventArgs) Handles PictureBox1.MouseUp
If e.Button = Windows.Forms.MouseButtons .Left Then
' attempt to paste text into the window we are over
If Not Me.Handle.Equals(mainWindo w) Then
Dim ThreadID1 As Integer
Dim ThreadID2 As Integer
ThreadID1 = GetWindowThreadProcessId(M e.Handle, 0)
ThreadID2 = GetWindowThreadProcessId(o verWindow, 0)
Call AttachThreadInput(ThreadID 1, ThreadID2, True)
Putfocus(overWindow)
SendMessage(overWindow, EM_REPLACESEL, &O0, TextBox1.Text)
Call AttachThreadInput(ThreadID 1, ThreadID2, False)
Else
Putfocus(overWindow)
SendMessage(overWindow, EM_REPLACESEL, &O0, TextBox1.Text)
End If
End If
End Sub
End Class
Add three Labels, a TextBox, and a small PictureBox to a form. Make the PictureBox so you can see it by setting the BorderStyle, BackColor or Image properties.
Open up NotePad or Wordpad and then drag the PictureBox onto that window and drop it.
You could use SendKeys.Send() instead of SendMessage().
You could make your app hide or minimize when the user "drags" your PictureBox (making it reappear on MouseUp).
Public Class Form1
Public Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Integer, ByVal yPoint As Integer) As IntPtr
Public Declare Function GetAncestor Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal gaFlags As Integer) As IntPtr
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As IntPtr, ByVal lpString As String, ByVal cch As Integer) As Integer
Public Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As IntPtr) As Integer
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As IntPtr, ByVal lpClassName As String, ByVal nMaxCount As Integer) As Integer
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As IntPtr, ByVal lpdwProcessId As Integer) As Integer
Public Declare Function AttachThreadInput Lib "user32" (ByVal idAttach As Integer, ByVal idAttachTo As Integer, ByVal fAttach As Integer) As Integer
Public Declare Function Putfocus Lib "user32" Alias "SetFocus" (ByVal hWnd As IntPtr) As Integer
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
Public Const GA_ROOT As Integer = 2
Public Const EM_REPLACESEL As Integer = &HC2
Private overWindow As IntPtr
Private mainWindow As IntPtr
Private windowText As String
Private className As String
Private controlText As String
Private Sub PictureBox1_MouseMove(ByVa
If e.Button = Windows.Forms.MouseButtons
' for informational purposes...
overWindow = WindowFromPoint(Windows.Fo
mainWindow = GetAncestor(overWindow, GA_ROOT)
windowText = New String(Microsoft.VisualBas
GetWindowText(mainWindow, windowText, Len(windowText))
Label1.Text = "Main Target Window Caption: " & windowText
className = Space(256)
Dim retVal As Long
retVal = GetClassName(overWindow, className, 256)
className = className.Substring(0, retVal)
Label2.Text = "Target Window ClassName: " & className
controlText = New String(Microsoft.VisualBas
GetWindowText(overWindow, controlText, Len(controlText))
Label3.Text = "Target Window Caption: " & controlText
End If
End Sub
Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.Mouse
If e.Button = Windows.Forms.MouseButtons
' attempt to paste text into the window we are over
If Not Me.Handle.Equals(mainWindo
Dim ThreadID1 As Integer
Dim ThreadID2 As Integer
ThreadID1 = GetWindowThreadProcessId(M
ThreadID2 = GetWindowThreadProcessId(o
Call AttachThreadInput(ThreadID
Putfocus(overWindow)
SendMessage(overWindow, EM_REPLACESEL, &O0, TextBox1.Text)
Call AttachThreadInput(ThreadID
Else
Putfocus(overWindow)
SendMessage(overWindow, EM_REPLACESEL, &O0, TextBox1.Text)
End If
End If
End Sub
End Class
ASKER
I'm taking a look at your solution right now. Thanks for doing this.
The only concern of mine is the drop method. I plan on implementing a version of the solution that
Putsfocus over the window when they press on a "Enter" button on my program. The trick here is that I am not sure how to capture the "overwindow." when the click on the destination application. You see once they click on the destination application they stil have to go back to my program to select "enter."
The only concern of mine is the drop method. I plan on implementing a version of the solution that
Putsfocus over the window when they press on a "Enter" button on my program. The trick here is that I am not sure how to capture the "overwindow." when the click on the destination application. You see once they click on the destination application they stil have to go back to my program to select "enter."
That's fine...
The handle to the window is captured in the "overWindow" variable where you can use it later.
I am running code in the MouseUp event but you could do it from anywhere you want.
If you want you could change the cursor as the user drags or drag the outline of the PB for a better visual indicator.
So the user would drag and drop onto the target window to select it. Then they can go back and press the button whenever they need to.
The handle to the window is captured in the "overWindow" variable where you can use it later.
I am running code in the MouseUp event but you could do it from anywhere you want.
If you want you could change the cursor as the user drags or drag the outline of the PB for a better visual indicator.
So the user would drag and drop onto the target window to select it. Then they can go back and press the button whenever they need to.
ASKER
The code does work well and solves my intial problem of not being able to paste into a webbased application loaded on Citrix. The program I have will not use drag and drop method however.
The user clicks on the destination application text field
Then the user clicks on a "enter" button on my program which triggers some text within my program to be pasted into the destination application.
It is somewhat different then your solution but your solution I think is going to put me on the right direction. I should have something here shortly.
The user clicks on the destination application text field
Then the user clicks on a "enter" button on my program which triggers some text within my program to be pasted into the destination application.
It is somewhat different then your solution but your solution I think is going to put me on the right direction. I should have something here shortly.
You could make a small floating window that is always on top for the user drag from and designate the target field to make it easier to work with.
Let me know what else I can do...
Let me know what else I can do...
ASKER
Thanks Idle_Mind. I appreciate your help GREATLY!
The only thing I need to do is get the destination application via mouseclick
and then capture that destination application via a "enter Button" on from my applicaiton.
Your solution has gotten me further than I been in in weeks!
The only thing I need to do is get the destination application via mouseclick
and then capture that destination application via a "enter Button" on from my applicaiton.
Your solution has gotten me further than I been in in weeks!
You won't be able to get the target window via mouse click using the method I showed...only drag and drop.
To get the mouse click route to work, we either need to go back to the SetCapture route (which I'm still playing with...didn't anticipate problems converting it to VB.Net!), use a low level mouse hook, or poll the mouse with a timer (not very pretty).
Another option would be to use a low level keyboard hook so you can trap keypresses. Then the user would click on the target window to give it focus and press a key combination (F2 or something) to designate that field.
To get the mouse click route to work, we either need to go back to the SetCapture route (which I'm still playing with...didn't anticipate problems converting it to VB.Net!), use a low level mouse hook, or poll the mouse with a timer (not very pretty).
Another option would be to use a low level keyboard hook so you can trap keypresses. Then the user would click on the target window to give it focus and press a key combination (F2 or something) to designate that field.
ASKER
I would lean more towards the SetCapture route..or low level mouse hook(never heard of it before). They seem to be more intuitive.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Idle Mind - Any updates on this?
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/getactivewindow.asp
"The GetActiveWindow function retrieves the window handle to the active window attached to the calling thread's message queue. "
"attached to the calling thread's message queue"...so that will only get the active window of the app that contains Form1. It won't give you any windows from other processes.