Win32Api -- 回到Windows桌面


本文分享下回到桌面功能的實現方法,效果與快捷鍵(Win+D)相同。

實現方法

Windows回到桌面功能的實現方式有多種,可以模擬快捷鍵,也可以執行如下方法。其中方法一需要引用Shell32.dll,方法為添加引用,選擇COM找到"Microsoft Shell Controls and Automation",選中並確認,還需要將其嵌入互操作類型置為false。

// 方法一,[參考鏈接](https://stackoverflow.com/questions/41598951/programmatically-show-the-desktop)
Shell32.ShellClass objShel = new Shell32.ShellClass();
objShel.ToggleDesktop();

// 方法二,[參考鏈接](https://social.msdn.microsoft.com/Forums/vstudio/en-US/a27ca1e4-bd02-434b-8d02-06553c35f3d5/show-desktop-program-no-working)
Type shellType = Type.GetTypeFromProgID("shell.application");
object shell = Activator.CreateInstance(shellType);
shellType.InvokeMember("ToggleDesktop", BindingFlags.InvokeMethod, null, shell, new object[] { });

問題

正常情況下,這兩個方法都可以成功執行。

但是,今天碰到一台設備操作未成功。場景是WPF應用收到udp消息時,執行回到桌面操作失敗。

看到有網友說執行上述代碼時,需在STA thread中執行,否則會報錯。方法一是需要在STA thread中執行的,但是並不能解決該問題。

再次分析問題時發現,當WPF應用為當前活動窗口時,操作執行成功,否則執行失敗。因此,先激活窗口,再執行上述代碼就可以成功解決該問題了。

在出問題的設備上,使用簡單的Show()、Active()方法激活窗口是不行的,只會在任務欄閃爍圖標,使用大佬提供的激活窗口的方法可以成功激活。

該問題的難點在於並不是所有設備都存在該問題,我手中有兩台設備,操作系統是一樣的,但一台是好的,一台是不行的。出問題的設備代碼是執行了的,不知道為什么沒有效果,必須將應用置為活動窗口才行,有了解該問題的小伙伴歡迎討論。

本文測試demo的部分代碼如下,詳細可見Github

// Wpf主窗口
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        InitLogger();
        InitUdpThread();
        showDesktop = Method1;
        Logger.LogMessage(Severity.Info, $"start process, Main Thread id: {Thread.CurrentThread.ManagedThreadId}");
    }

    private void InitLogger()
    {
        var file = new FileLogger("log.txt");
        Logger.LogMessage(Severity.Info, "Init logger success");
    }

    private void InitUdpThread()
    {
        Thread udpThread = new Thread(new ThreadStart(GetUdpMessage));
        udpThread.IsBackground = true;
        udpThread.Start();
    }

    private void GetUdpMessage()
    {
        UdpClient udpClient = null;
        try
        {
            udpClient = new UdpClient(10001);
        }
        catch (Exception)
        {
            Logger.LogMessage(Severity.Error, "create udp client failed");
            return;
        }
        Logger.LogMessage(Severity.Info, "create udp client success");

        IPEndPoint remotePoint = null;
        while (true)
        {
            try
            {
                byte[] receiveData = udpClient.Receive(ref remotePoint);
                string receiveString = Encoding.Default.GetString(receiveData);
                Logger.LogMessage(Severity.Info, $"receive udp message: {receiveString}");

                if (receiveString.ToLower().Contains("showdesktop"))
                    showDesktop?.Invoke();
            }
            catch (Exception e)
            {
                Logger.LogMessage(Severity.Error, e.Message);
            }
        }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        if (sender is Button btn)
        {
            switch (btn.Name)
            {
                case "method1":
                    showDesktop = Method1;
                    Logger.LogMessage(Severity.Info, "turn to method1");
                    break;
                case "method2":
                    showDesktop = Method2;
                    Logger.LogMessage(Severity.Info, "turn to method2");
                    break;
                case "activeFirst":
                    showDesktop = ActiveFirst;
                    Logger.LogMessage(Severity.Info, "turn to activeFirst method");
                    break;
                default:
                    break;
            }
        }
    }

    private void Method1()
    {
        Thread newSta = new Thread(()=>
        {
            Shell32.ShellClass objShel = new Shell32.ShellClass();
            objShel.ToggleDesktop();
            Logger.LogMessage(Severity.Info, $"Current Thread id: {Thread.CurrentThread.ManagedThreadId}");
        });
        newSta.TrySetApartmentState(ApartmentState.STA);
        newSta.Start();
    }

    private void Method2()
    {
        Type shellType = Type.GetTypeFromProgID("Shell.Application");
        object shellObject = System.Activator.CreateInstance(shellType);
        shellType.InvokeMember("ToggleDesktop", System.Reflection.BindingFlags.InvokeMethod, null, shellObject, null);
        Logger.LogMessage(Severity.Info, $"Current Thread id: {Thread.CurrentThread.ManagedThreadId}");
    }

    private void ActiveFirst()
    {
        App.Current.Dispatcher.Invoke(new Action(() =>
        {
            Win32Api.SetWindowToForegroundWithAttachThreadInput(this);
            Method2();
        }));
    }

    private Action showDesktop;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM