Enumerate all windows which are "always on top"

696 Views Asked by At

I want to write a utility for our web test server which kills all processes having an "always on top" window. I guess it is window style WS_EX_TOPMOST, however, I'm not 100% sure.

Is there a way in C#:

  • to enumerate all windows which are "always on top"
  • and to retrieve the corresponding process?
2

There are 2 best solutions below

6
On BEST ANSWER

Here's a working example which finds all processes which have a topmost window. Be careful though: Windows Explorer always has a topmost window and you probably don't want to kill that process.

class Program
{
    const int WS_EX_TOPMOST = 0x00000008;
    const int WS_VISIBLE = 0x10000000;
    const int GWL_STYLE = -16;
    const int GWL_EXSTYLE = -20;

    static void Main(string[] args)
    {
        var topmostWindowHandles = new ArrayList();
        EnumWindows(EnumWindowsCallback, topmostWindowHandles);

        var processesToKill = new HashSet<uint>();
        foreach (IntPtr hWnd in topmostWindowHandles)
        {
            uint processId = 0;
            GetWindowThreadProcessId(hWnd, out processId);
            processesToKill.Add(processId);
        }

        foreach (uint pid in processesToKill)
        {
            Process proc = Process.GetProcessById((int)pid);
            Console.WriteLine("Killing " + proc.ProcessName);
            // kill process, except explorer.exe
        }
    }

    static bool EnumWindowsCallback(IntPtr hWnd, ArrayList lParam)
    {
        int exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
        int style = GetWindowLong(hWnd, GWL_STYLE);
        if ((exStyle & WS_EX_TOPMOST) == WS_EX_TOPMOST 
            && (style & WS_VISIBLE) == WS_VISIBLE)
        {
            lParam.Add(hWnd);
        }
        return true;
    }

    public delegate bool EnumWindowsProc(IntPtr hwnd, ArrayList lParam);

    [DllImport("user32.dll")]
    [return:MarshalAs(UnmanagedType.Bool)]
    static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ArrayList lParam);

    [DllImport("user32.dll")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);
}
4
On

Here's a solution which finds all processes with a topmost main window:

class Program
{
    static void Main(string[] args)
    {
        int WS_EX_TOPMOST = 0x00000008;
        int GWL_EXSTYLE = -20;
        foreach (Process proc in Process.GetProcesses())
        {
            IntPtr hWnd = proc.MainWindowHandle;
            int res = GetWindowLong(hWnd, GWL_EXSTYLE);
            if ((res & WS_EX_TOPMOST) == WS_EX_TOPMOST)
            {
                Console.WriteLine("Topmost window found for process " + proc.ProcessName);
            }
        }
    }

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);
}

This only checks if the main window of a process is topmost. I leave this answer because it might help with this specific problem (finding topmost main windows).