最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c#基于Win32Api實(shí)現(xiàn)返回Windows桌面功能

 更新時(shí)間:2021年05月31日 15:08:15   作者:louzi  
本文分享下回到桌面功能的實(shí)現(xiàn)方法,效果與快捷鍵(Win+D)相同。有此需求的朋友可以參考下

實(shí)現(xiàn)方法

Windows回到桌面功能的實(shí)現(xiàn)方式有多種,可以模擬快捷鍵,也可以執(zhí)行如下方法。其中方法一需要引用Shell32.dll,方法為添加引用,選擇COM找到"Microsoft Shell Controls and Automation",選中并確認(rèn),還需要將其嵌入互操作類型置為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[] { });

問題

正常情況下,這兩個(gè)方法都可以成功執(zhí)行。

但是,今天碰到一臺(tái)設(shè)備操作未成功。場(chǎng)景是WPF應(yīng)用收到udp消息時(shí),執(zhí)行回到桌面操作失敗。

看到有網(wǎng)友說執(zhí)行上述代碼時(shí),需在STA thread中執(zhí)行,否則會(huì)報(bào)錯(cuò)。方法一是需要在STA thread中執(zhí)行的,但是并不能解決該問題。

再次分析問題時(shí)發(fā)現(xiàn),當(dāng)WPF應(yīng)用為當(dāng)前活動(dòng)窗口時(shí),操作執(zhí)行成功,否則執(zhí)行失敗。因此,先激活窗口,再執(zhí)行上述代碼就可以成功解決該問題了。

在出問題的設(shè)備上,使用簡(jiǎn)單的Show()、Active()方法激活窗口是不行的,只會(huì)在任務(wù)欄閃爍圖標(biāo),使用如下方法可以激活

window.Show();
window.Activate();

在大部分設(shè)備上,通過 Show 和 Activate 組合可以讓窗口作為當(dāng)前用戶活動(dòng)的,即使窗口之前是最小化或隱藏,都可以通過 Show 的方法顯示

但是某些設(shè)備窗口被蓋在其他的窗口的下面,此時(shí)的窗口的 window.IsActive 還是 true 但是調(diào)用 Activate 不會(huì)讓窗口放在上層

我在網(wǎng)上看到好多小伙伴調(diào)用了 SetForegroundWindow 方法,其實(shí)現(xiàn)在 WPF 是開源的,可以看到 Window 的 Activate 方法是這樣寫

        public bool Activate()
        {
            // this call ends up throwing an exception if Activate
            // is not allowed
            VerifyApiSupported();
            VerifyContextAndObjectState();
            VerifyHwndCreateShowState();
 
            // Adding check for IsCompositionTargetInvalid
            if (IsSourceWindowNull || IsCompositionTargetInvalid)
            {
                return false;
            }
 
            return UnsafeNativeMethods.SetForegroundWindow(new HandleRef(null, CriticalHandle));
        }

源代碼請(qǐng)看 github

也就是調(diào)用 SetForegroundWindow 和調(diào)用 Activate 方法是差不多的,如果調(diào)用 Activate 沒有用那么應(yīng)該調(diào)用 SetForegroundWindow 也差不多

需要按照以下步驟

    1.得到窗口句柄FindWindow
    2.切換鍵盤輸入焦點(diǎn)AttachThreadInput
    3.顯示窗口ShowWindow(有些窗口被最小化/隱藏了)
    4.更改窗口的Zorder,SetWindowPos使之最上,為了不影響后續(xù)窗口的Zorder,改完之后,再還原
    5.最后SetForegroundWindow

在 WPF 中對(duì)應(yīng)的更改窗口的順序使用的是 Topmost 屬性,同時(shí)設(shè)置順序需要做一點(diǎn)小的更改

在 WPF 中通過 c# - Bring a window to the front in WPF - Stack Overflow 可以了解到如何用 AttachThreadInput 方法

整個(gè)代碼請(qǐng)看下面,具體的 win32 方法我就沒有寫出來了,請(qǐng)小伙伴自己添加

        private static void SetWindowToForegroundWithAttachThreadInput(Window window)
        {
            var interopHelper = new WindowInteropHelper(window);
            // 以下 Win32 方法可以在 https://github.com/kkwpsv/lsjutil/tree/master/Src/Lsj.Util.Win32 找到
            var thisWindowThreadId = Win32.User32.GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);
            var currentForegroundWindow = Win32.User32.GetForegroundWindow();
            var currentForegroundWindowThreadId = Win32.User32.GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);
 
            // [c# - Bring a window to the front in WPF - Stack Overflow](https://stackoverflow.com/questions/257587/bring-a-window-to-the-front-in-wpf )
            // [SetForegroundWindow的正確用法 - 子塢 - 博客園](https://www.cnblogs.com/ziwuge/archive/2012/01/06/2315342.html )
            /*
                 1.得到窗口句柄FindWindow 
                2.切換鍵盤輸入焦點(diǎn)AttachThreadInput 
                3.顯示窗口ShowWindow(有些窗口被最小化/隱藏了) 
                4.更改窗口的Zorder,SetWindowPos使之最上,為了不影響后續(xù)窗口的Zorder,改完之后,再還原 
                5.最后SetForegroundWindow 
             */
            Win32.User32.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);
 
            window.Show();
            window.Activate();
            // 去掉和其他線程的輸入鏈接
            Win32.User32.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);
 
            // 用于踢掉其他的在上層的窗口
            window.Topmost = true;
            window.Topmost = false;

到此問題解決完畢。

在 WPF 中,如果想要使用代碼控制,讓某個(gè)窗口作為當(dāng)前用戶的輸入的邏輯焦點(diǎn)的窗口,也就是在當(dāng)前用戶活動(dòng)的窗口的最上層窗口,默認(rèn)使用 Activate 方法,通過這個(gè)方法在大部分設(shè)備都可以做到激活窗口

但是在一些特殊的設(shè)備上,使用下面代碼調(diào)起窗口只是在任務(wù)欄閃爍圖標(biāo),而沒有讓窗口放在最上層

該問題的難點(diǎn)在于并不是所有設(shè)備都存在該問題,我手中有兩臺(tái)設(shè)備,操作系統(tǒng)是一樣的,但一臺(tái)是好的,一臺(tái)是不行的。出問題的設(shè)備代碼是執(zhí)行了的,不知道為什么沒有效果,必須將應(yīng)用置為活動(dòng)窗口才行,有了解該問題的小伙伴歡迎討論。

本文測(cè)試demo的部分代碼如下,詳細(xì)可見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;
}

以上就是c#基于Win32Api實(shí)現(xiàn)返回Windows桌面功能的詳細(xì)內(nèi)容,更多關(guān)于c# 返回Windows桌面的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#生成EMF矢量圖形文件示例詳解

    C#生成EMF矢量圖形文件示例詳解

    這篇文章主要為大家介紹了C#?生成?EMF矢量圖形文件詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • C#調(diào)用C類型dll入?yún)閟truct的問題詳解

    C#調(diào)用C類型dll入?yún)閟truct的問題詳解

    這篇文章主要給大家介紹了關(guān)于C#調(diào)用C類型dll入?yún)閟truct問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • C# Access數(shù)據(jù)庫(kù)增刪查改的簡(jiǎn)單方法

    C# Access數(shù)據(jù)庫(kù)增刪查改的簡(jiǎn)單方法

    這篇文章主要介紹了C# Access數(shù)據(jù)庫(kù)增刪查改的簡(jiǎn)單方法,有需要的朋友可以參考一下
    2014-01-01
  • C#獲取Excel文件所有文本數(shù)據(jù)內(nèi)容的示例代碼

    C#獲取Excel文件所有文本數(shù)據(jù)內(nèi)容的示例代碼

    獲取上傳的?EXCEL?文件的所有文本信息并存儲(chǔ)到數(shù)據(jù)庫(kù)里,可以進(jìn)一步實(shí)現(xiàn)對(duì)文件內(nèi)容資料關(guān)鍵字查詢的全文檢索,有助于我們定位相關(guān)文檔,本文詳細(xì)介紹了C#獲取Excel文件所有文本數(shù)據(jù)內(nèi)容實(shí)現(xiàn)步驟和代碼,需要的朋友可以參考下
    2024-07-07
  • C# 任務(wù)的異常和延續(xù)處理

    C# 任務(wù)的異常和延續(xù)處理

    本文主要介紹了C# 任務(wù)的異常和延續(xù)處理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-12-12
  • 使用C#對(duì)JSON進(jìn)行序列化和反序列化處理的兩種方法

    使用C#對(duì)JSON進(jìn)行序列化和反序列化處理的兩種方法

    本指南探討了如何使用 C# 編程語言進(jìn)行 JSON 序列化和反序列化,我們將介紹 .NET 生態(tài)系統(tǒng)中可用的兩個(gè)本機(jī)選項(xiàng),即命名空間和廣泛使用的 Newtonsoft.Json 庫(kù)(也稱為 Json.NET),需要的朋友可以參考下
    2024-06-06
  • C#?VB.NET?實(shí)現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件

    C#?VB.NET?實(shí)現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件

    Word中可將Office、PDF、txt等文件作為OLE對(duì)象插入到文檔中,雙擊該對(duì)象可直接訪問或編輯該文件,除了以上常見的文件格式對(duì)象,也可以插入多媒體文件,如視頻、音頻等。本篇文章介紹了通過C#實(shí)現(xiàn)在Word中插入多媒體文件。感興趣的可以學(xué)習(xí)一下
    2021-12-12
  • C#使用linq計(jì)算執(zhí)行元素在列表中出現(xiàn)次數(shù)的方法

    C#使用linq計(jì)算執(zhí)行元素在列表中出現(xiàn)次數(shù)的方法

    這篇文章主要介紹了C#使用linq計(jì)算執(zhí)行元素在列表中出現(xiàn)次數(shù)的方法,涉及C#使用linq擴(kuò)展進(jìn)行列表查詢的技巧,需要的朋友可以參考下
    2015-04-04
  • Unity實(shí)現(xiàn)鼠標(biāo)或者手指點(diǎn)擊模型播放動(dòng)畫

    Unity實(shí)現(xiàn)鼠標(biāo)或者手指點(diǎn)擊模型播放動(dòng)畫

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)鼠標(biāo)或者手指點(diǎn)擊模型播放動(dòng)畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • C#使用正則表達(dá)式過濾html標(biāo)簽

    C#使用正則表達(dá)式過濾html標(biāo)簽

    最近在開發(fā)一個(gè)項(xiàng)目,其中有需求要求我們把一段html轉(zhuǎn)換為一般文本返回,使用正則表達(dá)式是明智的選擇,下面小編給介紹下C#使用正則表達(dá)式過濾html標(biāo)簽,需要的朋友參考下
    2016-08-08

最新評(píng)論

南溪县| 孙吴县| 偏关县| 镇安县| 台安县| 丰城市| 景德镇市| 霍林郭勒市| 阳西县| 新乐市| 荥阳市| 旺苍县| 蓝田县| 天祝| 满洲里市| 承德市| 新民市| 抚顺市| 股票| 榆社县| 盘山县| 兴隆县| 湘西| 墨竹工卡县| 科技| 聂荣县| 大冶市| 集贤县| 阿勒泰市| 孟村| 盐边县| 余干县| 龙游县| 河北省| 福贡县| 双桥区| 潍坊市| 五大连池市| 长岭县| 富民县| 新余市|