Introduction

Couple of days ago, I got an email asked me to help with creating a button on top all open applications, this reminded me of the CodedUI Recorder. As you can see from the picture, when using CodedUI Testing, you will see the “Currently Recording” notification on every active application you are recording.

How?

The design is to make the title bar window of the target application as the parent\owner window of the Control you want to add. But this is not enough, we need to listen to many events like size change, style etc.. But I’ll get there later.

Here is what we need to do:

Find window handle with FindWindow

Get window position and title bar info using GetTitleBarInfo

Set window as owner\parent using SetWindowLong

SetWinEventHook for couple of events of the target application.

Using the Code

Step 1: Create Project

Create a WinForm or WPF project and add the following classes:

We will use this class to combine native methods so we can write our code more efficiently.

Step 3: Add Find Native Methods

FindWindow function retrieves a handle to the top-level window whose class name and window name match the specified strings. This function does not search child windows. This function does not perform a case-sensitive search. Add below methods to NativeMethods.

Step 7: Add GetWindowPosition

Into the Helpers class, add GetWindowPosition (below), GetWindowPosition first will initialize TITLEBARINFO (Make sure you set the sbSize) than use GetTitleBarInfo to get the TitleBar position on the screen.

Step 9: Add SetWindowLong To NativeMethod Class

The SetWindowLongPtr function changes an attribute of the specified window. The function also sets a value at the specified offset in the extra window memory. To write code that is compatible with both 32-bit and 64-bit versions of Windows, also add SetWindowLongPtr.

Step 10: Add SetWindowLong In Helpers Class

The only attribute we need to change in this case is - GWL_HWNDPARENT, our agenda is to set target window as parent\owner of our HoverControl.

//Specifies the zero-based offset to the value to be set.
//Valid values are in the range zero through the number of bytes of extra window memory,
//minus the size of an integer.
publicenum GWLParameter
{
GWL_EXSTYLE = -20, //Sets a new extended window style
GWL_HINSTANCE = -6, //Sets a new application instance handle.
GWL_HWNDPARENT = -8, //Set window handle as parent
GWL_ID = -12, //Sets a new identifier of the window.
GWL_STYLE = -16, // Set new window style
GWL_USERDATA = -21, //Sets the user data associated with the window.
//This data is intended for use by the application
//that created the window. Its value is initially zero.
GWL_WNDPROC = -4 //Sets a new address for the window procedure.
}

Instead of checking if this is 64bit or 32bit from our UI class, add SetWindowLong inside the helpers class.

Step 11: Add HoverControl On Top Target Application

First, we need to create new instance of our new HoverControl, set the position based on Target window TitleBar position (Part 2) and set the HoverControl as Child of Target window. Add button click event and let’s add the following code:

And here we are, the last part in this series – How to set Window Event using SetWinEventHook. the only thing that is left is to listen to Target window events (Example: LocationChange) so we can move our HoverControl accordingly. We are going to use some more NativeMethods to complete this task.

Step 12: Add SetWinEventHook & UnhookWinEvent To NativeMethods Class

We need to use SetWinEventHook because this function allows clients to specify which processes and threads they are interested in. Clients can call SetWinEventHook multiple times if they want to register additional hook functions or listen for additional events.

[DllImport("user32.dll")]
internalstaticexternIntPtr SetWinEventHook(
AccessibleEvents eventMin, //Specifies the event constant for the
//lowest event value in the range of events that are
//handled by the hook function. This parameter can
//be set to EVENT_MIN to indicate the
//lowest possible event value.
AccessibleEvents eventMax, //Specifies the event constant for the highest event
//value in the range of events that are handled
//by the hook function. This parameter can be set
//to EVENT_MAX to indicate the highest possible
//event value.
IntPtr eventHookAssemblyHandle, //Handle to the DLL that contains the hook
//function at lpfnWinEventProc, if the
//WINEVENT_INCONTEXT flag is specified in the
//dwFlags parameter. If the hook function is not
//located in a DLL, or if the WINEVENT_OUTOFCONTEXT
//flag is specified, this parameter is NULL.
WinEventProc eventHookHandle, //Pointer to the event hook function.
//For more information about this function
uint processId, //Specifies the ID of the process from which the
//hook function receives events. Specify zero (0)
//to receive events from all processes on the
//current desktop.
uint threadId, //Specifies the ID of the thread from which the
//hook function receives events.
//If this parameter is zero, the hook function is
//associated with all existing threads on the
//current desktop.
SetWinEventHookParameter parameterFlags //Flag values that specify the location
//of the hook function and of the events to be
//skipped. The following flags are valid:
);

An application-defined callback (or hook) function that the system calls in response to events generated by an accessible object. The hook function processes the event notifications as required. Clients install the hook function and request specific types of event notifications by calling SetWinEventHook.

Step 14: Add Events And Callbacks

First, we need to define what types of events we want to listen too and than create a dictionary with AccessibleEvents and Specific CallBack (or generic to all events). You can find more about WinEvents here. I’ve add event for LocationChanged and Destroy, LocationChanged will help me to find the position on the target window each time the user changes the position and Destroy when the target window is closed and we need to close our HoverControl.

Share

About the Author

Shai Raiten is VS ALM MVP, currently working for Sela Group as a ALM senior consultant and trainer specializes in Microsoft technologies especially Team System and .NET technology. He is currently consulting in various enterprises in Israel, planning and analysis Load and performance problems using Team System, building Team System customizations and adjusts ALM processes for enterprises. Shai is known as one of the top Team System experts in Israel. He conducts lectures and workshops for developers\QA and enterprises who want to specialize in Team System.

Comments and Discussions

I would like to add control the data entry application. The control will read the data from file and fill the entry box of the application. Is it possible from your applcation? if yes can you please tell me how to go about it.