Introduction
Hello again! Today’s topic is a very popular topic on programming forums like CodeGuru. There is always a need to obtain an outside application’s window handle, to be able to manipulate that window from inside your program. This is precisely what we will do today. Some experienced programmers might say use Spy++ to get the handles. Yes, that is a good point, but curiosity will always kill the cat. 😉
Design
Open Visual Studio 2012 and choose either C# or VB.NET as your platform. Design your form to resemble Figure 1.
Figure 1 – Our Design
Code
As usual, let’s start by adding the necessary Namespaces:
VB.NET
Imports System.Runtime.InteropServices 'APIs Imports System.Text ' StringBuilder
C#
using System.Runtime.InteropServices; //APIs using System.Text; //StringBuilder
We use the InteropServices namespace for dealing with APIs and the Text namespace will be used for advanced text manipulation functions, such as the StringBuilder.
Let’s now add the APIs as well as their associated constants:
VB.NET
'Retrieves a handle to the foreground window <DllImport("user32.dll")> _ Private Shared Function GetForegroundWindow() As Integer End Function 'Copies the text of the specified window's title bar (if it has one) into a buffer <DllImport("user32.dll")> _ Private Shared Function GetWindowText(hWnd As Integer, text As StringBuilder, count As Integer) As Integer End Function 'This function changes the size, position, and z-order of a child, pop-up, or top-level window. <DllImport("user32.dll")> _ Public Shared Function SetWindowPos(hWnd As IntPtr, hWndInsertAfter As IntPtr, X As Integer, Y As Integer, cx As Integer, cy As Integer, _ uFlags As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function Shared ReadOnly HWND_TOPMOST As New IntPtr(-1) 'Places the window above all non-topmost windows Shared ReadOnly HWND_TOP As New IntPtr(0) ' Places the window at the top of the Z order. Const SWP_NOSIZE As UInt32 = &H1 'Retains current size Const SWP_NOMOVE As UInt32 = &H2 ' Retains the current position Const TOPMOST_FLAGS As UInt32 = SWP_NOMOVE Or SWP_NOSIZE
C#
[DllImport("user32.dll")] static extern int GetForegroundWindow(); //Retrieves a handle to the foreground window [DllImport("user32.dll")] static extern int GetWindowText(int hWnd, StringBuilder text, int count); //Copies the text of the specified window's title bar (if it has one) into a buffer [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] //This function changes the size, position, and z-order of a child, pop-up, or top-level window. public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); //Places the window above all non-topmost windows static readonly IntPtr HWND_TOP = new IntPtr(0); // Places the window at the top of the Z order. const UInt32 SWP_NOSIZE = 0x0001; //Retains current size const UInt32 SWP_NOMOVE = 0x0002; // Retains the current position const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
We actually only need the GetForegroundWindow and GetWindowText APIs to obtain window handles and captions. The Third API (SetWindowPos) will be responsible for setting our form “Always on Top”. This means that our form will always be visible and above all the other windows that are open, and this will make it easier to see the window information.
First things first. Let’s add the call to the SetWindowPos API to allow our form to be always on top. The best place to add it will be inside the form’s constructor. In VB.NET you’d have to add the New constructor manually. Have a look here in case you don’t know how.
VB.NET
Public Sub New() ' This call is required by the designer. InitializeComponent() SetWindowPos(Me.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS) ' Add any initialization after the InitializeComponent() call. End Sub
C#
public frmHandles() { InitializeComponent(); //Make Form TopMost SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS); }
If we were to run our program now, you would see that our form is on top of the other open applications. We need to get the external window details now, so add the next code segment:
VB.NET
Private Sub GetWindowDetails() Const intCharCount As Integer = 256 'Number Of Characters For String Buffer Dim intWindowHandle As Integer = 0 'Window Handle Dim strWindowText As New StringBuilder(intCharCount) 'Set Up String Builder To Hold Text From GWT API intWindowHandle = GetForegroundWindow() 'get Current Active Window If GetWindowText(intWindowHandle, strWindowText, intCharCount) > 0 Then 'If It Has A Caption lblWindowText.Text = strWindowText.ToString() 'Retrieve Window Caption 'Retrieve Window Handle lblWindowHandle.Text = intWindowHandle.ToString() End If End Sub Private Sub tmrHandle_Tick(sender As Object, e As EventArgs) Handles tmrHandle.Tick GetWindowDetails() 'Call Get Window Details Sub End Sub
C#
private void GetWindowDetails() { const int intCharCount = 256; //Number Of Characters For String Buffer int intWindowHandle = 0; //Window Handle StringBuilder strWindowText = new StringBuilder(intCharCount); //Set Up String Builder To Hold Text From GWT API intWindowHandle = GetForegroundWindow(); //get Current Active Window if (GetWindowText(intWindowHandle, strWindowText, intCharCount) > 0) //If It Has A Caption { this.lblWindowText.Text = strWindowText.ToString(); //Retrieve Window Caption this.lblWindowHandle.Text = intWindowHandle.ToString(); //Retrieve Window Handle } } private void tmrHandle_Tick(object sender, EventArgs e) { GetWindowDetails(); //Call Get Window Details Sub }
We created a sub procedure named GetWindowDetails. This sub is later called from a Timer control’s Tick event. Inside this sub we obtain the window handle via the GetForegroundWindow API. We obtain the Window’s text (caption) and store it inside a StringBuilder object. If this window indeed has a caption, we display the window text as well as the window’s handle. This handle could further used to do any sort of manipulation, such as closing that window or minimizing that window.
This is just a small example of how to obtain this type of information from external windows, so obviously there are many many more tools you could use to take it further. I just aimed to give you the principles.
Conclusion
I hope you have enjoyed this article and that you will put this knowledge to good use. The source files are attached. Until next time, cheers!