日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Wallpaper的原理和C#實現(xiàn)(含源文件)

 心有樹 2024-07-24

wallpaper是一款優(yōu)秀的動態(tài)壁紙軟件,除了播放動畫以外,還可以執(zhí)行程序,甚至可以實時響應(yīng)鼠標移動。

原理分析

windows的桌面是由不同的二窗體構(gòu)成,包括圖標層,背景層,背景層顯示桌面壁紙,圖標層放置圖標,且圖標層背景透明,因此可以直接看到后面的背景層,鼠標右鍵彈出菜單也是在圖標層完成。wallpaper在圖標層和背景層之間插入了自己的窗口,因此可以顯示動畫,執(zhí)行代碼。前面已經(jīng)提到圖標層是一個透明的覆蓋全屏的大窗口,因此鼠標事件只會在圖標層響應(yīng),而wallpaper可以實時響應(yīng)鼠標可能是利用了Hook攔截了鼠標事件,并加入自己代碼。

既然知道了原理就可以自己實現(xiàn)。

C#實現(xiàn)

界面繪制

首先創(chuàng)建兩個窗體,一個用來播放視頻,一個用來控制

DearXuan
DearXuan

上圖是控制窗口,也是主窗口。

另一個視頻窗口較為簡單,直接用MediaPlayer覆蓋全屏就行,注意需要設(shè)置WindowState為Maximized,即啟動時立即最大化,同時播放器要隱藏ui,即設(shè)置uiMode為none。

在主窗體的load事件里新建VideoForm。為了讓VideoForm能夠夾在圖標層和背景層中間,需要將VideoForm的父窗體設(shè)置為背景窗體。

查找句柄

現(xiàn)在需要查找背景窗體的句柄,使用窗口查看器發(fā)現(xiàn)背景窗體沒有窗體名稱,因此無法直接定位,但是我們知道它的類名是WorkW,它的父窗體是Program Manager,所以我們可以遍歷所有WorkW窗體,如果其中一個窗體的父窗體是Program Manager,那么這個窗體就是背景窗體。

C#不支持直接這種接近底層的操作,因此需要調(diào)用user32.dll實現(xiàn)

代碼語言:javascript
復制
[DllImport("user32.dll", EntryPoint = "SetParent")]
private static extern int SetParent(int hWndChild,int hWndNewParent);
[DllImport("user32.dll", EntryPoint = "FindWindowA")]
private static extern IntPtr FindWindowA(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindowExA")]
private static extern IntPtr FindWindowExA(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", EntryPoint = "GetClassNameA")]
private static extern IntPtr GetClassNameA(IntPtr hWnd, IntPtr lpClassName, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetParent")]
private static extern IntPtr GetParent(IntPtr hWnd);
 
public static void SetFather(Form form)
{
    SetParent((int)form.Handle, GetBackground());
}
 
private static int GetBackground()
{
    unsafe
    {
        IntPtr background = IntPtr.Zero;
        IntPtr father = FindWindowA("progman", "Program Manager");
        IntPtr workerW = IntPtr.Zero;
        do
        {
            workerW = FindWindowExA(IntPtr.Zero, workerW, "workerW", null);
            if (workerW != IntPtr.Zero)
            {
                char[] buff = new char[200];
                IntPtr b = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
                int ret = (int)GetClassNameA(workerW, b, 400);
                if (ret == 0) throw new Exception("出錯");
            }
            if (GetParent(workerW) == father)
            {
                background = workerW;
            }
        } while (workerW != IntPtr.Zero);
        return (int)background;
    }
}

其中GetBackground函數(shù)負責查找背景層窗體,SetFather負責把一個窗體設(shè)置成另一個窗體的子窗體。為了使用指針功能,需要先開啟不安全的代碼功能 :項目—??屬性(??是你的項目名稱)—允許不安全代碼。

這個方法在Windows 10 21H1 19043.1110上測試有效,但是不保證在其他系統(tǒng)有效,例如,在vista系統(tǒng)上就會返回空指針,這可能是因為vista系統(tǒng)上的背景窗體不滿足上面所講的關(guān)系。一旦返回空指針,會導致設(shè)置父窗體失敗,最后視頻會在圖標層上方播放,此時的動態(tài)壁紙軟件就徹底變成了一個全屏播放器。

如果遇到上面這種情況,可以使用MicrosoftSpy來查找背景窗體,并根據(jù)具體情況改寫上面的代碼。

這里利用了windows窗口的一個特性:如果A窗體在B窗體上面,那么A窗體也會在B窗體的子窗體上面。

按鈕事件

給控制窗體的四個按鈕寫上事件

代碼語言:javascript
復制
private void Form1_Load(object sender, EventArgs e)
{
    main = new VideoForm();
    player = main.player;
    Window.SetFather(main);
    main.Show();
}
private void button1_Click(object sender, EventArgs e)//打開
{
    OpenFileDialog open = new OpenFileDialog();
    open.Filter = "媒體文件(所有類型)|*.mp4;*.mpeg;*.wma;*.wmv;*.wav;*.avi|所有文件|*.*";
    if (open.ShowDialog() == DialogResult.OK)
    {
        player.URL = open.FileName;
    }
}
 
private void button2_Click(object sender, EventArgs e)//播放
{
    player.Ctlcontrols.play();
}
 
private void button3_Click(object sender, EventArgs e)//暫停
{
    player.Ctlcontrols.pause();
}
 
private void button4_Click(object sender, EventArgs e)//退出
{
    main.Dispose();
    System.Environment.Exit(0);
}

其中main是視頻播放窗體,player是播放器

運行

點擊退出

DearXuan
DearXuan

刷新背景

雖然程序退出了,但是桌面變成了一張白紙,極其難看,目前暫不知道為什么會發(fā)生這種情況,個人猜測是windows考慮到背景是一張靜態(tài)圖,所以不會實時刷新,而剛剛被覆蓋掉的地方就會保持最后一次刷新的顏色,剛才點擊“退出”時,由于先dispose了視頻播放窗體,導致背景變成白板,如果不點擊“退出”,直接結(jié)束進程,那么背景就會變成黑板,因為MediaPlayer就是黑色的

DearXuan
DearXuan

既然如此,我們只需要讓背景刷新一下就可以,顯然在切換壁紙的時候,windows不得不刷新背景,所以我們可以先獲取當前壁紙,然后把壁紙切換成當前壁紙,這樣實際效果看起來沒有任何變化,但是讓windows為我們刷新了一次背景。

代碼語言:javascript
復制
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern int SystemParametersInfo(int uAction, int uParam, StringBuilder lpvParam, int fuWinIni);
 
public static bool Refresh()
{
    StringBuilder wallpaper = new StringBuilder(200);
    SystemParametersInfo(0x73, 200, wallpaper, 0);
    int ret = SystemParametersInfo(20, 1, wallpaper, 3);
    if(ret != 0)
    {
        RegistryKey hk = Registry.CurrentUser;
        RegistryKey run = hk.CreateSubKey(@"Control Panel\Desktop\");
        run.SetValue("Wallpaper", wallpaper.ToString());
        return true;
    }
    return false;
}

改寫“退出”按鈕事件

代碼語言:javascript
復制
private void button4_Click(object sender, EventArgs e)//退出
{
    main.Hide();
    this.Hide();
    Window.Refresh();
    main.Dispose();
    System.Environment.Exit(0);
}

之所以先隱藏,是因為在dispose和refresh執(zhí)行的空隙里會有一瞬間的白屏,如果先隱藏就可以避免這種情況。

因為視頻壁紙需要常駐后臺,而控制窗口不可能常駐桌面,所以我們需要改寫它的Formclosing,取消窗體關(guān)閉事件,并隱藏窗體

代碼語言:javascript
復制
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    e.Cancel = true;
    this.Hide();
}

給窗體加上NotifyIcon控件,該控件可以顯示任務(wù)欄角標,改寫雙擊事件,雙擊角標時顯示控制窗體

代碼語言:javascript
復制
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
    this.Show();
}

到現(xiàn)在完整的Wallpaper已經(jīng)制作完成,但是目前僅能播放視頻。當然也包括圖片,但是你需要設(shè)置MediaPlayer的循環(huán)播放,否則圖片顯示幾秒后就會變成純黑壁紙。

資源占用

看看GPU占用情況

DearXuan
DearXuan

以上數(shù)據(jù)是我在播放電影《龍之谷精靈王座》時的資源占用情況,該電影共1.83GB,可以看到內(nèi)存占用不到100MB,GPU0是核顯,核顯占用也才2%,比起wallpaper已經(jīng)非常優(yōu)秀了,但同時功能也非常單一,不過如果僅僅用來播放視頻,完全可以用來替代wallpaper。

如果你想要實現(xiàn)更多好玩的功能,也可以往視頻播放窗體里加別的東西,但是需要注意一點,所有需要交互的事件都不會響應(yīng),比如鼠標點擊,你只能通過控制窗體來修改視頻播放窗體的內(nèi)容。

源代碼

https://dearx./iiP4frxcm4d

EXE文件

https://dearx./iIPmWrxcn6b

EXE文件鏈接打開后是一個壓縮包,里面包含兩個dll和一個exe,這三個文件需要放在同一目錄下才可以運行

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多