如何通过编程隐藏桌面图标?

14

如何使用C#编程来程序化地显示/隐藏桌面图标?

我正在尝试创建一个使用小部件的替代桌面,因此需要隐藏旧的桌面图标。


我已经在类似的问题上发布了一个C++答案,也许有人可以将其翻译成C#。 - zett42
7个回答

26

您可以使用Windows API来完成此操作。以下是C#示例代码,可切换桌面图标。

    [DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
    enum GetWindow_Cmd : uint
    {
        GW_HWNDFIRST = 0,
        GW_HWNDLAST = 1,
        GW_HWNDNEXT = 2,
        GW_HWNDPREV = 3,
        GW_OWNER = 4,
        GW_CHILD = 5,
        GW_ENABLEDPOPUP = 6
    }
    [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    private const int WM_COMMAND = 0x111;

    static void ToggleDesktopIcons()
    {
        var toggleDesktopCommand = new IntPtr(0x7402);
        IntPtr hWnd = GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD);
        SendMessage(hWnd, WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
    }

这将向Progman的SHELLDLL_DefView子窗口发送一条消息,告诉它切换其唯一子项“FolderView”的可见性(通过添加或删除WS_VISIBLE样式)。 “FolderView”是实际包含图标的窗口。

要测试图标是否可见,可以使用以下示例中所示的GetWindowInfo函数查询WS_VISIBLE样式:

    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        private int _Left;
        private int _Top;
        private int _Right;
        private int _Bottom;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct WINDOWINFO
    {
        public uint cbSize;
        public RECT rcWindow;
        public RECT rcClient;
        public uint dwStyle;
        public uint dwExStyle;
        public uint dwWindowStatus;
        public uint cxWindowBorders;
        public uint cyWindowBorders;
        public ushort atomWindowType;
        public ushort wCreatorVersion;

        public WINDOWINFO(Boolean? filler)
            : this()   // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
        {
            cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
        }

    }

这里有一个函数调用上面的代码,并返回true(窗口可见)或false(窗口不可见)。

    static bool IsVisible()
    {
        IntPtr hWnd = GetWindow(GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD), GetWindow_Cmd.GW_CHILD);
        WINDOWINFO info = new WINDOWINFO();
        info.cbSize = (uint)Marshal.SizeOf(info);
        GetWindowInfo(hWnd, ref info);
        return (info.dwStyle & 0x10000000) == 0x10000000;
    }

可以在这里找到Windows API代码以及有关窗口样式的更多信息:http://www.pinvoke.net/default.aspx/user32/GetWindowInfo.html


3
太棒了,我现在会在所有我的应用程序中使用它,并随机切换()它。 :) - Gleno
它似乎在我的电脑上无法工作...我正在使用Windows 7。这是操作系统相关的吗?它应该在所有版本的Windows上都能工作吗?如果是这样,我将寻找另一个可以在多个Windows版本上运行的解决方案... - Tibi
更新:它确实可以工作,显然我必须重新启动explorer.exe,但现在它可以工作了。非常感谢。另一个问题是...我怎么知道它是开还是关? - Tibi
查询图标可见性的代码很多,所以我把它添加到了我的答案中。 - Ondrej Balas
7
这不是“使用Windows API”,而更像是“滥用Windows API”。这些都没有正式记录。 - David Heffernan
非常感谢您的所有帮助。然而,它仍然存在问题:只有在重启explorer.exe之后,才能成功切换桌面图标的可见性,而且只能使用3-4次。 - Tibi

5

虽然这是Ondrej Balas的回答,但我尝试后发现这个解决方案存在一个问题,如果使用ToggleDesktop命令显示桌面(同时启用了壁纸轮换),则该解决方案无法正常工作。

在这两种情况下,“SHELLDLL_DefView”窗口都不是“程序管理器”窗口的子级,而是“WorkerW”窗口的子级(详见WinApi - How to obtain SHELLDLL_DefViewWindows Desktop ListView Handle)。

基于上述问题,并根据Ondrej Balas早期的回答进行改进,修改ToggleDesktopIcons函数如下:

static void ToggleDesktopIcons()
{
    var toggleDesktopCommand = new IntPtr(0x7402);
    SendMessage(GetDesktopSHELLDLL_DefView(), WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
}

并添加一个GetDesktopSHELLDLL_DefView函数:

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
    [DllImport("user32.dll", SetLastError = false)]
    static extern IntPtr GetDesktopWindow();

    static IntPtr GetDesktopSHELLDLL_DefView()
    {
        var hShellViewWin = IntPtr.Zero;
        var hWorkerW = IntPtr.Zero;

        var hProgman = FindWindow("Progman", "Program Manager");
        var hDesktopWnd = GetDesktopWindow();

        // If the main Program Manager window is found
        if (hProgman != IntPtr.Zero)
        {
            // Get and load the main List view window containing the icons.
            hShellViewWin = FindWindowEx(hProgman, IntPtr.Zero, "SHELLDLL_DefView", null);
            if (hShellViewWin == IntPtr.Zero)
            {
                // When this fails (picture rotation is turned ON, toggledesktop shell cmd used ), then look for the WorkerW windows list to get the
                // correct desktop list handle.
                // As there can be multiple WorkerW windows, iterate through all to get the correct one
                do
                {
                    hWorkerW = FindWindowEx(hDesktopWnd, hWorkerW, "WorkerW", null);
                    hShellViewWin = FindWindowEx(hWorkerW, IntPtr.Zero, "SHELLDLL_DefView", null);
                } while (hShellViewWin == IntPtr.Zero && hWorkerW != IntPtr.Zero);
            }
        }
        return hShellViewWin;
    }

现在,无论是桌面切换还是壁纸旋转,ToggleDesktopIcons 都应该始终正常工作。
参考我的桌面切换功能,这导致了原始的 ToggleDesktopIcons 函数出现问题。
static public void ToggleDesktop(object sender, EventArgs e)
        {
            var shellObject = new Shell32.Shell();
            shellObject.ToggleDesktop();
        }

作为对James M的回应,此函数返回当前状态:
bool IconsVisible()
{
    var hWnd = GetDesktopListView();
    var info = new User32.WINDOWINFO(null);
    User32.GetWindowInfo(hWnd, ref info);
    return (info.dwStyle & User32.WindowStyle.WS_VISIBLE) == User32.WindowStyle.WS_VISIBLE;
}

1
你如何扩展这个功能以查看图标是否当前可见?已接受的答案在此解决方案中无法工作。 - user1618054

2

2

您可以在RegEdit中执行此操作 HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced 将HideIcons更改为1

    static void HideIcons()
    {
        RegistryKey myKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced", true);
        if (myKey != null)
        {
            myKey.SetValue("HideIcons", 1);
            myKey.Close();
        }
    }

请按照此处描述使用Registry类。 http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.aspx 是相关文档链接。

执行后桌面图标未隐藏! - bruce

1
你可以创建一个全屏视图应用程序,并将其设置为最顶层的窗口。
然后让你的应用程序随着Windows启动。

3
如果我将其置顶,它将在所有其他应用程序之上... 它需要完全相反,即最底部的窗口,除了任务栏。 - Tibi

0
你的方法不对。你真正想做的是替换shell。Windows已经为此提供了解决方案,所以你应该充分利用它。编写自己的shell来替代资源管理器。

1
我不是想要替换shell,只是想要替换桌面。我将会使用一些漂亮的小部件来代替无聊的图标。 - Tibi

0

不错的话题。如果没有创建不同的桌面,将运行的应用程序最小化到同一个位置会更加美观。


这并没有真正回答问题。如果您有不同的问题,可以通过点击提问来提出。如果您想在此问题获得新的答案时得到通知,您可以关注此问题。一旦您拥有足够的声望,您还可以添加悬赏以吸引更多关注。- 来自审核 - Dan Friedman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接