Solved

Last activated application, vb.net

Posted on 2006-11-28
15
3,710 Views
Last Modified: 2012-06-22
Does anyone here know how to get the below code to work with GetActiveWindow versus getting foreground window?


Imports System.Runtime.InteropServices

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("SHELLHOOK")
        RegisterShellHookWindow(Me.Handle)

    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg = uMsgNotify Then
            Select Case m.WParam.ToInt32
                Case ShellEvents.HSHELL_WINDOWACTIVATED
                    Debug.WriteLine("window activated")
                    Dim curWindow As IntPtr = GetForegroundWindow()
                    If (Not curWindow.Equals(IntPtr.Zero)) 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.Zero) Then
            SetForegroundWindow(lastWindow)
            System.Threading.Thread.Sleep(100)
            SendKeys.Send("Hello World...")

        End If

    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        DeregisterShellHookWindow(Me.Handle)
    End Sub


End Class
************************************************************
0
Comment
Question by:TechMonster
  • 8
  • 7
15 Comments
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
You sure you want GetActiveWindow()?
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.
0
 

Author Comment

by:TechMonster
Comment Utility
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?
 
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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?
0
 

Author Comment

by:TechMonster
Comment Utility
"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.  
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
        If e.Button = Windows.Forms.MouseButtons.Left Then            
            ' for informational purposes...
            overWindow = WindowFromPoint(Windows.Forms.Cursor.Position.X, Windows.Forms.Cursor.Position.Y)

            mainWindow = GetAncestor(overWindow, GA_ROOT)
            windowText = New String(Microsoft.VisualBasic.Chr(0), GetWindowTextLength(mainWindow) + 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.VisualBasic.Chr(0), GetWindowTextLength(overWindow) + 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.MouseEventArgs) 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(mainWindow) Then
                Dim ThreadID1 As Integer
                Dim ThreadID2 As Integer
                ThreadID1 = GetWindowThreadProcessId(Me.Handle, 0)
                ThreadID2 = GetWindowThreadProcessId(overWindow, 0)

                Call AttachThreadInput(ThreadID1, ThreadID2, True)

                Putfocus(overWindow)
                SendMessage(overWindow, EM_REPLACESEL, &O0, TextBox1.Text)
                Call AttachThreadInput(ThreadID1, ThreadID2, False)
            Else
                Putfocus(overWindow)
                SendMessage(overWindow, EM_REPLACESEL, &O0, TextBox1.Text)
            End If
        End If
    End Sub

End Class
0
 

Author Comment

by:TechMonster
Comment Utility
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."

 

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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.
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Author Comment

by:TechMonster
Comment Utility
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.  
 
 
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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...
0
 

Author Comment

by:TechMonster
Comment Utility
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!


0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
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.
0
 

Author Comment

by:TechMonster
Comment Utility
I would lean more towards the SetCapture route..or low level mouse hook(never heard of it before).  They seem to be more intuitive.  

0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
Comment Utility
0
 

Author Comment

by:TechMonster
Comment Utility
Idle Mind - Any updates on this?
0
 

Author Comment

by:TechMonster
Comment Utility
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Since .Net 2.0, Visual Basic has made it easy to create a splash screen and set it via the "Splash Screen" drop down in the Project Properties.  A splash screen set in this manner is automatically created, displayed and closed by the framework itsel…
Creating an analog clock UserControl seems fairly straight forward.  It is, after all, essentially just a circle with several lines in it!  Two common approaches for rendering an analog clock typically involve either manually calculating points with…
This video discusses moving either the default database or any database to a new volume.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now