1. 程式人生 > >VC下實現虛擬桌面的兩種方案

VC下實現虛擬桌面的兩種方案

將近年末,《核心程式設計》一書終於要看完了。最近,對Win7的桌面好奇非常!下面總結一下關於,windows虛擬桌面的設計方案,以及程式設計過程中get的一些小知識!

Windows的工作站和桌面:

Windows的工作站包括自己的剪貼簿,全域性原子表(global atoms),和若干個桌面!使用者登入時,系統會為使用者建立一個名為Winsta0的互動式視窗站!簡單,來說Winsta0基本上可是認為是使用者和系統的互動媒介!!

預設的Winsta0包含三塊桌面,即工作介面,登入視窗桌面,螢幕保護桌面!!!

關於這個工作站,我沒有查閱太多資料,貌似對編寫桌面應用來說,這是一個比較冷門(不常用)的內容!

Windows的桌面包含屬於他的一系列視窗以及專屬HOOK連結串列,windows允許我們使用CreateDeskTop建立屬於自己的桌面(HDESK),並且可以讓我們在不同的桌面之間切換!

我們使用Spy++,我們可以看到我們的型別名是"#32769"的視窗,其他所有的視窗都派生自這個匿名視窗!這個匿名視窗下有一個名為Program Manager(Progman)的子視窗,這個視窗有一個派生鏈:Program-----SHELLDLL_DefView-----SysListView32,其中SHELLDLL_DefView相當於桌面的功能層,SysListView32相當於桌面的顯示層。

但我們切換到自定義的桌面時,桌面上什麼都沒有,我們要在當前桌面下執行explorer讓我們的桌面圖示恢復。實際上,explorer程式在新的桌面上建立了一個任務條視窗和一個Program Manager視窗。

基於上面的內容我們很容易建立一個虛擬桌面程式!

#include <windows.h>
#include <tchar.h>


//全域性共享段
#pragma data_seg("Shared")
volatile LONG g_thaAppInstance=0;
#pragma data_seg()
#pragma comment(linker,"/Section::Shared,RWS")



//全域性變數
TCHAR szAppName[]=TEXT("VDeskLQ");
TCHAR szVDesk[]=TEXT("LQVirtualDesk");
HWND hwnd;
HDESK hVirtualDesk,hCurrentDesk,defaultDesk;
HANDLE explorerInfo;

//視窗回撥函式
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
//建立虛擬視窗
VOID CreateVirtualDesk();

//在虛擬桌面建立一個程序
HANDLE ShellCreateInVDesk(PTSTR szName);

int WINAPI WinMain(HINSTANCE hIns,HINSTANCE,PSTR szCmd,int nShow)
{
	if(g_thaAppInstance>0)
	{
		MessageBox(NULL,TEXT("例項已經執行!"),szAppName,MB_OK);
		return 0;
	}
	g_thaAppInstance++;
	
	//建立視窗型別
	WNDCLASS wndclass;
	wndclass.style=CS_HREDRAW|CS_VREDRAW;
	wndclass.lpfnWndProc=WndProc;
	wndclass.cbClsExtra=0;
	wndclass.cbWndExtra=0;
	wndclass.hInstance=hIns;
	wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
	wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
	wndclass.lpszMenuName=NULL;
	wndclass.lpszClassName=szAppName;

	if(!RegisterClass(&wndclass))
	{
		MessageBox(NULL,TEXT("Register Failed!"),szAppName,MB_ICONERROR);
		return 0;
	}

	hwnd =CreateWindow(szAppName,szAppName,//類名
						WS_OVERLAPPEDWINDOW,//風格
						CW_USEDEFAULT,CW_USEDEFAULT,//左上角座標
						CW_USEDEFAULT,CW_USEDEFAULT,//窗體的寬和高
						NULL,NULL,hIns,NULL);

	////由於當前的窗體執行緒需要在不同桌面間切換,
	////必須保證他不能安裝HOOK也不能有窗體顯示在桌面上
	//ShowWindow(hwnd,nShow);
	//UpdateWindow(hwnd);

	//註冊熱鍵
	RegisterHotKey(hwnd,0x0001,0,VK_F8);
	RegisterHotKey(hwnd,0x0002,0,VK_F9);
	//儲存原始桌面控制代碼
	defaultDesk=GetThreadDesktop(GetCurrentThreadId());
	//建立虛擬桌面
	CreateVirtualDesk();
	TCHAR szProcess[]=TEXT("explorer");
	explorerInfo=ShellCreateInVDesk(szProcess);
	MSG msg;
	while(GetMessage(&msg,hwnd,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	g_thaAppInstance--;
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	switch(msg)
	{
	case WM_CREATE:
		hCurrentDesk=defaultDesk;
		return 0;
	case WM_HOTKEY:
		{
			switch(wParam)
			{
			case 0x0001:
				{
					if (hCurrentDesk == hVirtualDesk)
					{
						SetThreadDesktop(defaultDesk); 
						SwitchDesktop(defaultDesk);
						hCurrentDesk =defaultDesk;
					}
					else
					{
						SetThreadDesktop(hVirtualDesk); 
						SwitchDesktop(hVirtualDesk);
						hCurrentDesk =hVirtualDesk;
					}
				}
				break;
			case 0x0002:
				{
					SetThreadDesktop(defaultDesk); 
					SwitchDesktop(defaultDesk);
					TerminateProcess(explorerInfo,1);
					CloseDesktop(hVirtualDesk);
					//關閉虛擬桌面
					SendMessage(hwnd,WM_DESTROY,0,0);
				}
			}
			break;
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd,msg,wParam,lParam);
}

HANDLE ShellCreateInVDesk(PTSTR szName)
{
	STARTUPINFO si={0};
	si.cb=sizeof(si);
	si.lpDesktop=szVDesk;
	PROCESS_INFORMATION pi;
	if ( !CreateProcess(NULL,szName, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) )
	{

		MessageBox(NULL,TEXT("啟動桌面失敗!"),TEXT("Error"),0);
		ExitProcess(1);
	}
	return pi.hProcess;
}

VOID CreateVirtualDesk()
{
	hVirtualDesk  =CreateDesktop(szVDesk,
								NULL,NULL,//保留引數
								DF_ALLOWOTHERACCOUNTHOOK,
								GENERIC_ALL,
								NULL);
}
上面的程式建立了一個程式,並且使用WM_HOTKEY訊息來進行桌面間的切換!程式可以正常執行,但是我還有一個疑問!(有的程式只能執行一個例項,比如某些瀏覽器,因此可能使用虛擬桌面會帶來一些不便!) 

但我在虛擬桌面執行一個程序後,呼叫CloseDesktop關閉桌面後,我發現雖然我當前的桌面看不到這個程序了,但是這個程序仍然是在執行著的!我猜想CloseDesktop只是減少HDESK的引用計數,和CloseHandle一樣他並沒有殺死核心物件!只有當沒有程序使用這個HDESK物件時,這個桌面才會消亡!因此、關閉虛擬桌面之前好先關閉上面的程序!

上面這個程式,在虛擬桌面的情形下Ctrl+Alt+Del無法呼叫工作管理員!!!?不知道,是不是可以新增熱鍵,手動執行taskmgr!!!

在個程式還可以完善,比如修改表實現開機啟動什麼!(新增到HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Run)

相比於上面一種實現,虛擬桌面的方式,我們還可以通過隱藏視窗的方式來實現!

通過為不同桌面維護一個視窗邊表,可以很容易的實現!!!

相關推薦

VC實現虛擬桌面方案

將近年末,《核心程式設計》一書終於要看完了。最近,對Win7的桌面好奇非常!下面總結一下關於,windows虛擬桌面的設計方案,以及程式設計過程中get的一些小知識! Windows的工作站和桌面: Windows的工作站包括自己的剪貼簿,全域性原子表(global ato

Linux實現秒級定時任務的方案(crontab 每秒執行)

第一種方案,當然是寫一個後臺執行的指令碼一直迴圈,然後每次迴圈sleep一段時間。 while true ;do command sleep XX //間隔秒數 done 第二種方案,使用crontab。 我們都知道crontab的粒度最小是到分鐘,但是我們還是可以通過變

Java虛擬機器判斷物件存活的方案:引用計數法與可達性分析演算法

java堆和方法區主要存放各種型別的物件(方法區中也儲存一些靜態變數和全域性常量等資訊),那麼我們在使用GC對其進行回收的時候首先要考慮的就是如何判斷一個物件是否應該被回收。也就是要判斷一個物件是否還有其他的引用或關聯使得這個物件處於存活的狀態。我們需要將不在存活狀態的所有物

AI實現方案,暴力推演與因果率

AI實現的兩種方案,暴力推演與因果率 學習PYTHON兩個月,寫個小遊戲練手。也為以後找工作做儲備。 從最簡單的九格棋入手。 九格棋玩法簡單,橫向,縱向,斜向三子連線則為勝。 基本設計構件有: 一、GUI介面。 介面我選用PYGAME做的。因為PYGAME中沒有提供按鈕等相關控制

分散式鎖實現--基於zookeeper和redis的方案

通過實現Watch介面,實現process(WatchedEvent event)方法來實施監控,使CountDownLatch來完成監控,在等待鎖的時候使用CountDownLatch來計數,等到後進行countDown,停止等待,繼續執行。以下整體流程基本與上述描述流程一致,只是在監聽的時候使用的是Cou

實現緩存最終一致性的方案

日誌 技術分享 頻率 數據庫更新 redis緩存 bsp 不用 客戶端 cdn   一、重客戶端   寫入緩存:      應用同時更新數據庫和緩存   如果數據庫更新成功,則開始更新緩存,否則如果數據庫更新失敗,則整個更新過程失敗。   判斷更新緩存是否成功,如果成

Android熱修復:Andfix和Hotfix,方案的比較與實現

Andfix和hotfix是兩種android熱修復框架。 android的熱修復技術我看的最早的應該是QQ空間團隊的解決方案,後來真正需要了,才仔細調查,現在的方案中,阿里有兩種Dexposed和Andfix框架,由於前一種不支援5.0以上android系統

ReactNative系列之十九表情emoji與文字混排的方案實現

方案一:使用react-native-emoji這個庫優點:文字和圖片混排單行多行,居中顯示都正常缺點:依賴手機的環境,只能根據系統裡的表情進行顯示?不能自定義表情。。。emoji...這種方案基本不可行,使用者體驗差方案二:<Text>    <Text&

vue拉列表的實現方式

第一種採用v-for的方式 <el-select v-model="form.columeType" placeholder="欄位型別"> <el-opt

.Net Core使用RabbitMQ比較完備的方案(雖然程式碼有點慘淡,不過我會完善)

一、前言     上篇說給大家來寫C#和Java的方案,最近工作也比較忙,遲到了一些,我先給大家補上C#的方案。 二、使用的外掛     HangFire     一個開源的.NET任務排程框架,最大特點在於內建提供整合化的控制檯

C#將Word轉換成PDF方法總結(基於Office和WPS方案)

path ebs htm soft off ros exc 標題 總結  有時候,我們需要在線上預覽word文檔,當然我們可以用NPOI抽出Word中的文字和表格,然後顯示到網頁上面,但是這樣會丟失掉Word中原有的格式和圖片。一個比較好的辦法就是將word轉換成pdf,然

C++服務器載文件的方式

roo eric gets sizeof let ont domain write 文件 #include <afxinet.h>#include "wininet.h" #pragma comment( lib, "wininet.lib" )string

CSS3實現動畫的方式

logs del pin 屬性 cnblogs ase http eve 括號 1、設置transition設置過渡,添加transform設置形狀,形成動畫效果,如下: .divadd { transition: All 0.4s ease-in-out;

Android 驗證碼倒計時方案

ans net ive gray remove public handler RM -s 使用 第一種方案:自定義控件 1.在布局中使用 <?xml version="1.0" encoding="utf-8"?> <RelativeLay

Python實現獎金計算方法的比較

position class pla nbsp font fault and dem 100萬 應發獎金計算 簡述:企業發放的獎金根據利潤提成。利潤(profit)低於或等於10萬元時,獎金可提10%; 利潤高於10萬元,低於20萬元時,低於10萬元的部分按1

css實現透明的方式及其區別

白色 class 子節點 new 透明度 區別 方式 ron pre 一、opacity:0~1 值越高,透明度越低,下面為示例 選擇器{ opacity:0.5 } 選擇器匹配到的節點們,包括節點們的孩子節點,都會實現%50透明,另 0.5 可直

Linux實現客戶端連跳ping百度,修改dns和nmcil的用法

1.客戶端跳兩次路由器ping百度 rht vmctl reset 重置虛擬機器 真機和虛擬機器開啟火牆策略 用在配置網路單元學的修改兩機閘道器 設定server為雙網絡卡路由端接觸客戶端Desktop閘道器為1.1.1.100 路由器端設定GATEWAY為真機,記得syste

LeetCode 926. 將字串翻轉到單調遞增 遞迴實現動態規劃 解法

這個題做了一個多小時,考慮複雜了。 開始推動規沒有推出來,然後找到一個遞推關係:從左往右,如果是0,則不需要變動;如果是1,則有兩種選擇(1)將1變為0(2)將1後面的所有數字變為1,這兩種方法中的變動數字最小的方法就是最佳方法,然後依次遞推,很容易寫出遞迴程式。但是這裡面存

java——多線程的實現方式、辦法解決線程賽跑

ble ali ide live nts nds extends sys add 多線程的實現方式:demo1、demo2 demo1:繼承Thread類,重寫run()方法 package thread_test; public class ThreadDemo1 e

狀態與策略——審批操作的方案

    審批操作是ERP或OA系統中必不可少的功能之一。這裡介紹兩種我設計的用於審批操作的方案,並藉此就“狀態模式”與“策略模式”提出一點自己的理解。     別問我為什麼不使用工作流引擎等工具來實現審批功能。做第一版方案時,我孤陋寡聞得並