Monday, September 28, 2009

How to enumerate running programs in .NETCF

I've been helping someone out in the MSDN Smart Device Forums lately with enumerating running programs. I thought I should share it since I don't much results from internet search engines on the topic. So here we go...

To enumerate top-level windows we use the EnumWindows method. To enumerate the running programs the same way the Task manager in Windows Mobile does, we just filter out what we don't need. What we don't want are windows that:

1. Have a parent window - We check by calling GetParent()
2. Is not visible - We check by calling IsWindowVisible()
3. Tool windows - We check by getting the current extended style (through GetWindowLong() of the window and checking if WS_EX_TOOLWINDOW is set

Here's a simple smart device console application the loads and displays a list of running programs:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
 
namespace EnumWindowsNETCF
{
    class Program
    {
        static Dictionary<string, IntPtr> visibleWindows = new Dictionary<string, IntPtr>();
        static StringBuilder lpString;
        static bool visible;
        static bool hasOwner;
        static bool isToolWindow;
 
        delegate int WNDENUMPROC(IntPtr hwnd, uint lParam);
        const int GWL_EXSTYLE = -20;
        const uint WS_EX_TOOLWINDOW = 0x0080;
 
        [DllImport("coredll.dll")]
        static extern int EnumWindows(WNDENUMPROC lpEnumWindow, uint lParam);
 
        [DllImport("coredll.dll")]
        static extern bool IsWindowVisible(IntPtr hwnd);
 
        [DllImport("coredll.dll")]
        static extern IntPtr GetParent(IntPtr hwnd);
 
        [DllImport("coredll.dll")]
        static extern bool GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
 
        [DllImport("coredll.dll")]
        static extern int GetWindowLong(IntPtr hwnd, int nIndex);
 
        static int Callback(IntPtr hwnd, uint lParam)
        {
            hasOwner = GetParent(hwnd) != IntPtr.Zero;
            visible = IsWindowVisible(hwnd);
            isToolWindow = (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) != 0;
            lpString.Remove(0, lpString.Length);
            GetWindowText(hwnd, lpString, 1024);
 
            string key = lpString.ToString();
            if (!hasOwner &&
                visible &&
                !isToolWindow &&
                !string.IsNullOrEmpty(key) &&
                !visibleWindows.ContainsKey(key))
            {
                visibleWindows.Add(key, hwnd);
            }
 
            return 1;
        }
 
        static void Main()
        {
            lpString = new StringBuilder(1024);
            EnumWindows(Callback, 0);
 
            foreach (var key in visibleWindows.Keys)
            {
                IntPtr hwnd = visibleWindows[key];
                visible = IsWindowVisible(hwnd);
                lpString.Remove(0, lpString.Length);
                GetWindowText(hwnd, lpString, 1024);
 
                Debug.WriteLine("Handle: " + hwnd + "; Is Visible: " + visible + "; Text: " + lpString);
            }
        }
    }
}

I hope you find this useful, otherwise it can always be an addition to your utility library.

6 comments:

  1. Hi,

    I tried it, it complied successfully, when I run this, nothing happened. I put breakpoint on int Callback(IntPtr hwnd, uint lParam) but nothing happened.

    Please guide me

    ReplyDelete
  2. What platform are you running on? I just re-tested the code on a windows mobile 5 and 6 emulators and it seems to work fine.

    ReplyDelete
  3. Ok, I tried with console application again and it worked. But I could not get it properly:

    I got output as below with windows mobile 6 emulator:

    Handle: 2080835968; Is Visible: True; Text: CursorWindow
    Handle: 2080846080; Is Visible: True; Text: Desktop
    Handle: 2080871872; Is Visible: True; Text: Phone
    Handle: 2080914320; Is Visible: True; Text: Contacts
    Handle: 2080900864; Is Visible: True; Text: Messaging
    Handle: 2080916016; Is Visible: True; Text: Calendar

    Though, there was only desktop, no other window was open.

    Can u please clear me?

    ReplyDelete
  4. I mean no windows was open then why it showed Visible as True?

    Thank you

    ReplyDelete
  5. Applications by default will minimize when the window close button is clicked.

    Unless these applications are focibly shutdown (e.g. through the running programs control panel applet) then these applications are still running in the background

    ReplyDelete
  6. I got handle of Phone window following your blog, and hook the window like below:

    Private Sub SetHook()
    mOldWndProc = SetWindowLong(mhWnd, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(mProc))
    End Sub
    'Restores the original window procedure for the control.
    Private Sub Unhook()
    SetWindowLong(mhWnd, GWL_WNDPROC, mOldWndProc)
    End Sub
    Protected Overridable Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    If msg = WM_HOTKEY Then
    Dim fuModifiers As Int32 = LoWord(lParam)
    Dim uVirtKey As Int32 = HiWord(lParam)
    Dim isCorrectKey As Boolean = (uVirtKey = VK_TBACK)
    If (lParam And &H1000) = 0 Then 'this is key down event
    If isCorrectKey Then
    Dim e As New KeyPressEventArgs(ChrW(uVirtKey Or fuModifiers))
    RaiseEvent OnKeyPress(New Object, e)
    End If
    Else 'this is keyup event
    End If
    'return 1 so that OS won't process the key. We must return 1 for both KeyUp and KeyDown
    If isCorrectKey Then Return 1
    End If
    'if we are here, the key was unhandled, call the parent handler
    Return CallWindowProc(mOldWndProc, hwnd, msg, wParam, lParam)
    End Function


    After hook, when I click on Phone to open window, it raise error:

    A native exception has occurred in Test.exe, Select Quit and restart program.
    OR
    The remote connection to the device has been lost. Please verify the device connection and restart debugging.
    Please can u help me to fix it. Thank you

    ReplyDelete