Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically minimize opened window folders

How can I get the list of opened of folders, enumerate through it and minimize each folder programmatically?

At times some opened folders do steal focus from the tool when jumping from one form in the application to another. Preventing this is of high priority for our client. The customers are visually impaired people, so they access the machine only via screen readers. Minimizing other windows (folders) is not at all a problem, in fact a requirement.

I tried this:

foreach (Process p in Process.GetProcessesByName("explorer"))
{
    p.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
}

As expected it did no good.

Update:

From the answers here, I tried this:

    delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

    [DllImport("user32.dll")]
    static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);

    static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processID)
    {
        List<IntPtr> handles = new List<IntPtr>();

        EnumThreadDelegate addWindowHandle = delegate(IntPtr hWnd, IntPtr param)
        {
            handles.Add(hWnd);
            return true;
        };

        foreach (ProcessThread thread in Process.GetProcessById(processID).Threads)                              
            EnumThreadWindows(thread.Id, addWindowHandle, IntPtr.Zero);

        return handles;
    }

    const int SW_MINIMIZED = 6;

    [DllImport("user32.dll")]
    static extern int ShowWindow(IntPtr hWnd, int nCmdShow);

    private void button1_Click(object sender, EventArgs e)
    {
        foreach (IntPtr handle in EnumerateProcessWindowHandles(Process.GetProcessesByName("explorer")[0].Id))
            ShowWindow(handle, SW_MINIMIZED);
    }

This creates a whole lot of invisible explorer windows to be suddenly listed in the taksbar out of no where. I am bit noob in dealing with Windows API, so the code itself will actually help.

like image 914
nawfal Avatar asked Feb 13 '12 00:02

nawfal


4 Answers

Please try this (the code is somewhat messy but for the purpose you should be able to go through it ;))

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using System.Globalization;

namespace WindowsFormsApplication20
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            foreach (IntPtr handle in EnumerateProcessWindowHandles(Process.GetProcessesByName("explorer")[0].Id))
            {
                SendMessage(handle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
            }
        }

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        static string GetDaClassName(IntPtr hWnd)
        {
            int nRet;
            StringBuilder ClassName = new StringBuilder(100);
            //Get the window class name
            nRet = GetClassName(hWnd, ClassName, ClassName.Capacity);
            if (nRet != 0)
            {
                return ClassName.ToString();
            }
            else
            {
                return null;
            }
        }

        delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);

        static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processID)
        {
            List<IntPtr> handles = new List<IntPtr>();

            EnumThreadDelegate addWindowHandle = delegate(IntPtr hWnd, IntPtr param)
            {
                string className = GetDaClassName(hWnd);

                switch (className)
                {
                    case null:
                        break;
                    case "ExploreWClass":
                        handles.Add(hWnd);
                        break;
                    case "CabinetWClass":
                        handles.Add(hWnd);
                        break;
                    default:
                        break;
                }

                return true;
            };

            foreach (ProcessThread thread in Process.GetProcessById(processID).Threads)
                EnumThreadWindows(thread.Id, addWindowHandle, IntPtr.Zero);

            return handles;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);

        const int WM_SYSCOMMAND = 274;
        const int SC_MINIMIZE = 0xF020;
    }
}

Best regards,

Żubrówka

like image 160
Żubrówka Avatar answered Oct 10 '22 07:10

Żubrówka


//Create Instance Of Shell Class by referencing COM Library "Microsoft Shell Controls And Automation" -shell32.dll

Shell32.ShellClass objShell = new Shell32.ShellClass();
//Show Desktop
((Shell32.IShellDispatch4)objShell).ToggleDesktop();

Edit: to show your application (Activate or Maximize/Restore) after toggling actually turned out to be quite difficult:

I tried:

Application.DoEvents();

System.Threading.Thread.Sleep(5000);

Even overriding the WndProc didn't manage to capture the event:

private const Int32 WM_SYSCOMMAND = 0x112;
        private const Int32 SC_MINIMIZE = 0xf020;
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_SYSCOMMAND)
            {
                if (m.WParam.ToInt32() == SC_MINIMIZE)
                    return;
            }
            base.WndProc(ref m);
        }

So I suggest instead of Minimising all other windows, just stick yours on top during the operation, then once your finished turn off Always On Top:

  [DllImport("user32.dll")]
    static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);

const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

public static void MakeTopMost (IntPtr hWnd)
{
    SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
}
like image 28
Jeremy Thompson Avatar answered Oct 10 '22 08:10

Jeremy Thompson


There is a less 'hacky' solution than the accepted answer available here: Minimize a folder

It's based on the Shell Objects for Scripting. Sample:

const int SW_SHOWMINNOACTIVE = 7;

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

static void MinimizeWindow(IntPtr handle)
{
    ShowWindow(handle, SW_SHOWMINNOACTIVE);
}

//call it like:

foreach (IWebBrowser2 window in new Shell().Windows())
{
    if (window.Name == "Windows Explorer")
        MinimizeWindow((IntPtr)window.HWND);
}

The same thing can be achieved using the Internet Explorer Object Model

// add a reference to "Microsoft Internet Controls" COM component
// also add a 'using SHDocVw;'
foreach (IWebBrowser2 window in new ShellWindows())
{
    if (window.Name == "Windows Explorer")
        MinimizeWindow((IntPtr)window.HWND);
}
like image 32
Simon Mourier Avatar answered Oct 10 '22 08:10

Simon Mourier


If you are willing to use p-invoke you can use EnumThreadWindows to enumerate all windows of a process. Then use ShowWindow to minimize them.

like image 30
rasmus Avatar answered Oct 10 '22 08:10

rasmus