【问题标题】:Show Desktop button in VB.NET Windows Form在 VB.NET Windows 窗体中显示桌面按钮
【发布时间】:2012-04-28 06:04:58
【问题描述】:

在我的 vb.net windows 窗体应用程序中,我想制作一个按钮,当用户单击该按钮时,应显示桌面,(显示桌面按钮)。

考虑一个表单名称为form1,它有一个类似“显示桌面”的按钮,当用户点击时,所有的应用程序都应该被最小化并且应该显示桌面,有没有VB.NET Windows Form应用程序的代码。

【问题讨论】:

    标签: .net vb.net winforms


    【解决方案1】:

    编辑

    虽然我提出的解决方案有效,但我建议使用下面的 Code Gray 的 answer,因为这是正确的方法。


    在 C# 中是这样的:

    using System;
    using System.Runtime.InteropServices;
    
    namespace ConsoleApplication1 {
    class Program {
        [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
        static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);
    
        const int WM_COMMAND = 0x111;
        const int MIN_ALL = 419;
        const int MIN_ALL_UNDO = 416;
    
        static void Main(string[] args) {
            IntPtr lHwnd = FindWindow("Shell_TrayWnd", null);
            SendMessage(lHwnd, WM_COMMAND, (IntPtr)MIN_ALL, IntPtr.Zero); 
            System.Threading.Thread.Sleep(2000);
            SendMessage(lHwnd, WM_COMMAND, (IntPtr)MIN_ALL_UNDO, IntPtr.Zero);
        }
    }
    }
    

    我使用online converter tool转换上述代码,请验证是否有效

    Imports System
    Imports System.Runtime.InteropServices
    
    Namespace ConsoleApplication1
        Class Program
            <DllImport("user32.dll", EntryPoint := "FindWindow", SetLastError := True)> _
            Private Shared Function FindWindow(lpClassName As String, lpWindowName As String) As IntPtr
            End Function
            <DllImport("user32.dll", EntryPoint := "SendMessage", SetLastError := True)> _
            Private Shared Function SendMessage(hWnd As IntPtr, Msg As Int32, wParam As IntPtr, lParam As IntPtr) As IntPtr
            End Function
    
            Const WM_COMMAND As Integer = &H111
            Const MIN_ALL As Integer = 419
            Const MIN_ALL_UNDO As Integer = 416
    
            Private Shared Sub Main(args As String())
                Dim lHwnd As IntPtr = FindWindow("Shell_TrayWnd", Nothing)
                SendMessage(lHwnd, WM_COMMAND, DirectCast(MIN_ALL, IntPtr), IntPtr.Zero)
                System.Threading.Thread.Sleep(2000)
                SendMessage(lHwnd, WM_COMMAND, DirectCast(MIN_ALL_UNDO, IntPtr), IntPtr.Zero)
            End Sub
        End Class
    End Namespace
    

    【讨论】:

      【解决方案2】:

      现有答案中提出的解决方案是依赖于 Windows 未记录方面的黑客攻击。它们现在可以工作,但它们随时可能因 Windows 更新而停止工作。

      Marshal's solution 尝试在任务栏中找到实际的“显示桌面”按钮。一个明显的问题是窗口的名称和 ID 是硬编码的,这意味着如果操作系统本身发生更改,代码就会中断。这些操作系统内部没有记录,不打算由应用程序进行编程操作,并且随时可能更改。我也不知道如果用户修改他们的操作系统设置以不在任务栏中显示此按钮会发生什么。代码是否继续有效?这些消息是否仍受支持?我不知道。你呢?

      Harsh's solution 依赖于合成按下 Win+D 组合键,这是显示桌面的键盘快捷键。这具有合成键盘输入的所有标准问题,另外一个缺点是它使用了旧的、已弃用的keybd_event 函数(SendInput 是它的替代品,它解决了keybd_input 的一些问题,即没有处理错误的方法,但不能解决合成键盘事件的更大问题。)此解决方案不太可能因 Windows 更新而中断,因为此键盘快捷键已记录在案,但可能具有不良副作用和与其他交互的细微问题系统功能和/或应用程序。

      更好的解决方案是委托给 COM 组件 Shell32.dll,调用其记录在案的 ToggleDesktop method,这正是您想要做的。来自 MSDN 文档:

      此方法与任务栏上的显示桌面按钮效果相同。它要么隐藏所有打开的窗口以显示桌面,要么通过显示所有打开的窗口来隐藏桌面。 ToggleDesktop 方法不显示用户界面,它只是调用切换操作。

      由于这已记录在案,因此随着 Windows 的更新,它更有可能继续工作。由于它不依赖黑客或综合事件,因此不太可能导致细微的不兼容。它也很简单更容易使用

      C# 和 VB.NET 都可以轻松访问 COM 库。在 C# 中,调用函数很简单:

      Shell32.Shell shell = new Shell32.Shell();
      shell.ToggleDesktop();
      

      在 VB.NET 中,这变成了(看 ma,没有分号):

      Dim shell As Shell32.Shell = New Shell32.Shell()
      shell.ToggleDesktop()
      

      如果您的项目中尚不存在“Microsoft Shell 控件和自动化”(Shell32.dll 库)的引用,您可能需要添加该引用。这是一个系统 DLL,因此它存在于所有系统上。

      唯一的要求是您从使用单线程单元 (STA) 模型的线程调用此函数。换句话说,它不是线程安全的,也不处理自己的同步。然而,这并不是一个明显的缺点,因为所有 Windows 窗体应用程序都使用 STA 线程:它是主线程,即处理 UI 和泵送消息的线程。 UI 线程几乎总是 STA,并且保证在 WinForms 中也是如此。只是不要尝试从后台/工作线程调用它。并非如此,因为您应该只尝试显示桌面以响应直接的用户交互,这无论如何都会在 UI 线程上处理。

      【讨论】:

      • 非常感谢
      【解决方案3】:

      检查此链接。这包含最小化所有显示桌面的窗口的代码。 http://www.dreamincode.net/code/snippet2109.htm

      Public Sub ShowDesktop()
      keybd_event(VK_LWIN, 0, 0, 0)
      keybd_event(77, 0, 0, 0)
      keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0)
      End Sub
      
      Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, _
      ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
      Private Const KEYEVENTF_KEYUP = &H2
      Private Const VK_LWIN = &H5B
      
      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)         Handles Button1.Click
      Call ShowDesktop()
      End Sub
      

      【讨论】:

        【解决方案4】:

        shell:::{3080F90D-D7AD-11D9-BD98-0000947B0257} 确实是最好的解决方案,因为它是 MSDN 中已知的文档化 CLSID

        【讨论】:

          【解决方案5】:
             Shell("cmd.exe /c %windir%\explorer.exe shell:::{3080F90D-D7AD-11D9-BD98-0000947B0257}", AppWinStyle.MinimizedNoFocus)
          

          最佳解决方案

          【讨论】:

          • 你能解释一下这个解决方案吗?
          • 欢迎来到 Stack Overflow!虽然这段代码可以解决问题,including an explanation 解决问题的方式和原因确实有助于提高帖子的质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案添加解释,并说明适用的限制和假设。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-12-24
          • 1970-01-01
          • 2010-09-15
          • 2018-01-07
          • 1970-01-01
          • 2013-11-04
          • 1970-01-01
          相关资源
          最近更新 更多