How to programmatically minimize opened window folders

扶醉桌前 提交于 2019-11-28 10:57:52
Simon Mourier

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);
}

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

//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);
}

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.

I know this is an old post, but here is a much shorter, simpler way in case people are still looking for a solution:

Using Windows API:

Declare a windows handle: (minimizes the calling executable)

HWND wHandle;  //can be any scope - I use it in main 

Call the following anywhere (depending on scope of wHandle):

wHandle = GetActiveWindow(); 
ShowWindow(wHandle, SW_SHOWMINNOACTIVE);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!