Solved

How to catch that external window became active?

Posted on 2009-07-14
9
732 Views
Last Modified: 2012-05-07
Is there a way to have C# application run in background and catch the event, when any open window gets focus?
0
Comment
Question by:kutiJack
  • 6
  • 3
9 Comments
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 250 total points
ID: 24852207
You could try something like this....
Imports System.Runtime.InteropServices

Public Class Form1
 

    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
 

    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 GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As IntPtr, ByVal lpString As System.Text.StringBuilder, ByVal cch As Integer) As Integer

    Public Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As IntPtr) As Integer
 

    Private uMsgNotify As Integer
 

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load

        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

                    Dim curWindow As IntPtr = GetForegroundWindow()

                    Dim windowText As New System.Text.StringBuilder()

                    windowText.Length = GetWindowTextLength(curWindow) + 1

                    GetWindowText(curWindow, windowText, windowText.Length)

                    Debug.Print("Current Window: " & curWindow.ToString("X") & ": " & windowText.ToString)

            End Select

        End If

        MyBase.WndProc(m)

    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

Open in new window

0
 

Author Comment

by:kutiJack
ID: 24853526
Your VB code works well, but please, could you explain me, why  some windows throw on WINDOWACTIVATED event value of 4 and some value of 32772?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24853767
What kind of windows?...are they by chance system windows like the desktop, start menu etc?...
0
 

Author Comment

by:kutiJack
ID: 24858248
Hello, sorry for my late response. Now things have changed, all windows show value of 32772 on WINDOWACTIVATED event. All other events give propre values according to enumeration you provided. This is little strange to me.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:kutiJack
ID: 24858264
I have Windows XP Professional
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24860643
I'm running Visual Studio 2008 Standard on a 64-bit Vista Home Premium system.

Can you post your converted code?

0
 

Author Comment

by:kutiJack
ID: 24861539
Here is the converted code, but your original VB code produces the same value 32772 on window activation



using System.Diagnostics;

using System;

using System.Xml.Linq;

using System.Windows.Forms;

using System.Collections;

using System.Drawing;

using Microsoft.VisualBasic;

using System.Data;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.InteropServices;
 

namespace WindowsApplication1

{

	public partial class Form1

	{

		public Form1()

		{

			InitializeComponent();

			

			//Added to support default instance behavour in C#

			if (defaultInstance == null)

				defaultInstance = this;

		}

		

		#region Default Instance

		

		private static Form1 defaultInstance;

		

		/// <summary>

		/// Added by the VB.Net to C# Converter to support default instance behavour in C#

		/// </summary>

		public static Form1 Default

		{

			get

			{

				if (defaultInstance == null)

				{

					defaultInstance = new Form1();

					defaultInstance.FormClosed += new FormClosedEventHandler(defaultInstance_FormClosed);

				}

				

				return defaultInstance;

			}

		}

		

		static void defaultInstance_FormClosed(object sender, FormClosedEventArgs e)

		{

			defaultInstance = null;

		}

		

		#endregion

		

		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

		}

		

		[DllImport("user32.dll",EntryPoint="RegisterWindowMessageA", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

		public static extern int RegisterWindowMessage(string lpString);

		[DllImport("user32", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

		public static extern int DeregisterShellHookWindow(IntPtr hWnd);

		[DllImport("user32", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

		public static extern int RegisterShellHookWindow(IntPtr hWnd);

		[DllImport("user32", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

		public static extern IntPtr GetForegroundWindow();

		

		[DllImport("user32",EntryPoint="GetWindowTextA", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

		public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int cch);

		[DllImport("user32",EntryPoint="GetWindowTextLengthA", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)]

		public static extern int GetWindowTextLength(IntPtr hWnd);

		

		private int uMsgNotify;

		

		public void Form1_Load(object sender, System.EventArgs e)

		{

			uMsgNotify = RegisterWindowMessage("SHELLHOOK");

			RegisterShellHookWindow(this.Handle);

		}

		

		protected override void WndProc(ref System.Windows.Forms.Message m)

		{

			if (m.Msg == uMsgNotify)

            {

               

				switch (m.WParam.ToInt32())

				{

					case  (int) (ShellEvents.HSHELL_WINDOWACTIVATED):

						IntPtr curWindow = GetForegroundWindow();

						System.Text.StringBuilder windowText = new System.Text.StringBuilder();

						windowText.Length = GetWindowTextLength(curWindow) + 1;

						GetWindowText(curWindow, windowText, windowText.Length);

						Debug.Print("Current Window: " + curWindow.ToString("X") + ": " + windowText.ToString());

						break;

				}

			}

			base.WndProc(ref m);

		}

		

		public void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)

		{

			DeregisterShellHookWindow(this.Handle);

		}

		

	}

}

Open in new window

0
 

Author Closing Comment

by:kutiJack
ID: 31603302
Thank you for your code. I tried events on virtual machine with clean XP and all values are now "4", so the confusion lies somewhere in my OS.
0
 

Author Comment

by:kutiJack
ID: 24863432
I tried to run application on virtual machine with clean XP and everything went all right, all activation events threw value of 4. So, the cause is probably in my OS. Maby I will find it soon. Thank you.
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Suggested Solutions

Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

705 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

21 Experts available now in Live!

Get 1:1 Help Now