【问题标题】:How to programmatically minimize opened window folders如何以编程方式最小化打开的窗口文件夹
【发布时间】:2012-03-04 11:19:57
【问题描述】:

如何获取打开的文件夹列表、枚举并以编程方式最小化每个文件夹?

有时,当从应用程序中的一个表单跳转到另一个表单时,某些打开的文件夹会从工具中窃取焦点。防止这种情况对我们的客户来说是重中之重。客户是视障人士,因此他们只能通过屏幕阅读器访问机器。最小化其他窗口(文件夹)根本不是问题,实际上是一个要求。

我试过这个:

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

不出所料。

更新

从这里的答案,我尝试了这个:

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

这会创建大量不可见的资源管理器窗口,这些窗口会突然出现在任务栏中。我在处理 Windows API 方面有点菜鸟,所以代码本身实际上会有所帮助。

【问题讨论】:

标签: c# winforms winapi c#-2.0 focus-stealing


【解决方案1】:

请试试这个(代码有点乱,但你应该能够通过它;))

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

最好的问候,

朱布罗夫卡

【讨论】:

  • 让我试试那个!谢谢:)
  • 在我奖励你之前,让我问你,应该怎么做才能最小化其他打开的窗口,比如所有 MS Excel 窗口(使用相同的 shell API?
  • 好吧,如果你具体知道你想最小化什么(例如 Excel),你可以获取 excel.exe 的所有实例,获取主窗口的句柄(如果你有一个 Process 对象,你可以在 MainWindowHandle 属性中找到它),然后向该句柄发送一条消息,请求窗口最小化(如果您喜欢,可以使用 SendMessage(handle, WM_SYSCOMMAND, SC_MINIMIZE, 0); 函数)。
  • 如果你想要的是最小化除了你的程序之外的所有东西,它可能会更棘手,你需要枚举所有没有父/父的窗口是桌面(我在这里可能有点不正确,但我可以确认) 并发送最小化消息,通常它应该可以工作,但可能有一些更棘手的部分,例如 explorer.exe (对于这种特殊情况,您必须过滤无关紧要的句柄(其中一些对最小化消息),我通过过滤类名并仅使用 ExploreWClass 和 CabinetWClass 窗口来做到这一点)
  • GetDaClassName 函数是这里的关键。它提供了要最小化的确切句柄!是的,我可以最小化任何我希望的应用程序。天才的作品,拿走我的100分兄弟(13小时内)! ;)
【解决方案2】:

//通过引用COM库“Microsoft Shell Controls And Automation”-shell32.dll创建Shell类实例

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

编辑:在切换后显示您的应用程序(激活或最大化/恢复)实际上非常困难:

我试过了:

Application.DoEvents();

System.Threading.Thread.Sleep(5000);

即使重写 WndProc 也无法捕获事件:

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

所以我建议不要最小化所有其他窗口,而是在操作过程中将你的窗口放在最上面,然后在你完成后关闭 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);
}

【讨论】:

  • 这会最小化包括我的应用程序在内的所有内容。 this.Activate 不会把它带到前面
  • 对不起应该是this.WindowState = FormWindowState.Maximized;
  • 没办法。它仍然将我的表单保持在底部:(
  • @nawfal - 是的,你的权利,这是一个 PITA。请参阅我编辑的答案。我希望它是一个合适的解决方法。
  • 这仍然行不通。很抱歉延迟回复。它最小化所有窗口以显示桌面,甚至从应用程序中获取焦点。以前我习惯于获得焦点。我不知道幕后发生了什么。
【解决方案3】:

有一个比这里接受的答案更“hacky”的解决方案:Minimize a folder

它基于Shell Objects for Scripting。示例:

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

同样的事情可以使用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);
}

【讨论】:

  • 西蒙,谢谢你,它有效。您也可以在interop.SHDocVw 中调用new ShellWindows() 而不是new Shell().Windows。公认答案的一个优点是它也很容易扩展到其他应用程序的窗口,但这对于给定的任务来说更简单。我对接受哪个答案有两种看法:)
  • 我可以在你的答案中添加一个小代码sn-p来演示吗?这也有一个 small 问题,它将焦点从应用程序中移开。并不是说很难带回来,但这仍然是一个小故障。它发生在你身上吗?知道为什么会这样吗?
  • @nawfal - 如果需要,您可以添加 sn-p。确实,这仅与 Windows 资源管理器文件夹窗口有关——这就是问题 :-),我认为它更具前瞻性。如果您不想最小化,只需使用另一个 ShowWindow 命令,可能是 SW_SHOWMINNOACTIVE。
  • 是的 SW_SHOWMINNOACTIVE 可以解决问题。希望我的编辑没问题。随意进一步编辑。
【解决方案4】:

如果您愿意使用 p-invoke,您可以使用EnumThreadWindows 枚举进程的所有窗口。然后使用ShowWindow 将它们最小化。

【讨论】:

  • 这是枚举所有通用窗口吗?还是只是文件夹窗口?
  • 您可以使用此方法枚举特定进程的所有最顶层窗口。在您的情况下,所有窗口都属于资源管理器。您需要获取进程主线程的句柄。
  • 嘿,ramsus,你能贴一点代码本身吗,我做不到。
  • 关于这个有another question
【解决方案5】:

我知道这是一篇旧帖子,但如果人们仍在寻找解决方案,这里有一个更短、更简单的方法:

使用 Windows API:

声明一个窗口句柄:(最小化调用可执行文件)

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

在任何地方调用以下命令(取决于 wHandle 的范围):

wHandle = GetActiveWindow(); 
ShowWindow(wHandle, SW_SHOWMINNOACTIVE);

【讨论】:

    猜你喜欢
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多