Get Active Desktop Window

  • Thread starter Thread starter Alex
  • Start date Start date
A

Alex

I'm not sure if this is the right discussion group, but here is what I need
to do and I'm not sure where to start.
I have a windows service that needs to "monitor" the desktop and log
everytime a new window get's focus. Once I capture the event, I'll have to
look at the title and perform some business rules.

How do I do the monitoring part? I looked at pInvoke but I didn't see
anything there.

Thanks
Alex
 
I don't know if there is an event, but I think you could use User32.dll ->
EnumWindows, EnumChildWindows and GetForegroundWindow. I'm not sure that a
service would be able to get these as desktop interaction is frowned upon
pre-Vista, and prohibited post-Vista.
 
Hi Alex,

getting the window title of a window created in a different process isnt
that easy. I dont know if it is possible within net framework (via interop
or something else) -- i dont think so, but it should be possible in C++. The
main problem would be to communicate between the different processes that
have created the top level windows (and there childs). To retrieve the title
of a window, you normally send a WM_GETTEXT message to the window. This
message contains a memory adress, where the title text should be stored.
Well, each process has its own adress range and is protected from access of
a different process. So if you send the message to another process, the
process is not able to write to your memory and you will never get the text.

To get arround this, you need to implement a DLL that create a shared memory
block. The shared memory block can then be accessed by multiple processes.
http://msdn.microsoft.com/en-us/library/ms686958(VS.85).aspx

The next step you need to do, is to create a system wide hook to load your
dll into all existing processes. (Spy++ works this way.... and you always
need administrative permissions for that). Then you can send the WM_GETTEXT
message with a shared memory adress to that process and the process is able
to write to this memory adress.
http://msdn.microsoft.com/en-us/library/ms632589(VS.85).aspx

And this could become a very difficult task...

-J-
 
Thanks for the reply. I was planning to do this in C#, but I guess it's not
the right tool. I thought it would be hard, but I just wanted to see if there
may be an easier solution. What I basically want to do is to monitor when a
window gets focus, grab the title, and depending on it, perform some basic
database operation.

Thanks
 
If you only want to detect when the user switches to a different top level
window, then use GetForegroundWindow in combination with a timer .... Maybe
polling this information is bad, i cant think of a better solution right
now. The following code assumes that textbox1 is a TextBox-control and
timer1 is a enabled timer.
private void timer1_Tick(object sender, EventArgs e)
{
IntPtr wnd = GetForegroundWindow();
textBox1.Text = wnd.ToInt32().ToString();
}

/// <summary>
/// The GetForegroundWindow function returns a handle to the foreground
window.
/// </summary>
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();

-J-
 
John,
To retrieve the title
of a window, you normally send a WM_GETTEXT message to the window. This
message contains a memory adress, where the title text should be stored.
Well, each process has its own adress range and is protected from access of
a different process. So if you send the message to another process, the
process is not able to write to your memory and you will never get the text.

If you actually try this you'd see that it works just fine. Windows
knows how to marshal parameters of system messages such as WM_GETTEXT
across process boundaries. It's only when you deal with custom
messages (RegisterWindowMessage or WM_USER+x) that you need to worry
about this yourself.



Mattias
 
Matthias, yes, you are right. I've done something wrong with the marshaling
type and thats the reason why it wasnt working in my previous tests.

Alex, here is the code to get the title of the current selected top levels
screen. You need:
- a form
- a enabled timer
- a text box called textbox1
- a text box called textbox2
- wire the Tick-Event of timer1 to timer1_Tick

Its very easy to extend the example for child windows. Just use the
GetWindow (GW_CHILD / GW_HWNDNEXT) to iterate through all childs, subchilds
and so on. At the end you should move the instantiation of StingBuilder to
e.g. the constructor or something else, so that the object is created only
once and reused all the time.

I hope this helps.

-J-

<code>
private void timer1_Tick(object sender, EventArgs e)
{
IntPtr wnd = GetForegroundWindow();
textBox1.Text = wnd.ToInt32().ToString();

StringBuilder text = new StringBuilder(2000);
SendMessage(wnd, WM_GETTEXT, new IntPtr(2000), text);
textBox2.Text = text.ToString();
}

/// <summary>
/// The GetForegroundWindow function returns a handle to the foreground
window.
/// </summary>
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder lParam);

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);

enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}

const int WM_GETTEXT = 0xD;
</code>
 
Back
Top