Obtaining External Window Handles and Window Captions with Visual Studio 2012

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.

Our Design
Figure 1Our 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!

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read