转载请标明是引用于 http://blog.csdn.net/chenyujing1234

欢迎大家拍砖!

参考英文文章: <<Virtual Desktop: A Simple Desktop Management Tool>>

源代码请到原文链接下载。

一、引言

几个月前,我的一个大学同学正在用一个工具来管理混合桌面。我很好奇有这种的工具。我想它应该仅用来隐藏显示不同桌面的应用程序。作为好奇,我开始研究混合桌面,并得到了这篇文章。我发现之前认为这个工具仅是显示隐藏用的想法是错的。让我们看它如何工作的。

二、Window Station and Window Desktop

其实Windows用Window Station and Desktop  结构来提供可增加的安全。

暂时,我们提到的“Desktop“是指逻辑显示表面,它包含用户接口对象(GDI对象)和用户对象。

一个Window Station 是一个安全的内核对象,它包含剪切板,一个原子表,一个或更多的桌面对象。这些存在默认的窗口站“WinSta0“。

它是一个交互的窗口站,“WinSta0“是仅有的交互窗口站,它能显示用户接口或接收用户输入,而其它的窗口站是非交互的。

默认在交互的容器站中有三个桌面:默认的、WinLogon和ScreenSaver。

()1)通过按ATL+CTL+DEL弹出的窗口是WinLogon桌面。

(2)无论用户在什么时候登陆,默认窗口被创建并可见。这里的“默认”是指对所有登陆用户的默认的活动桌面。当你按了ATL+CTL+DEL,你将会切换回到WinLogon桌面。

(3当屏保被激活时,ScreenSave桌面会被可见并获得激活。

因为这些桌面名字是case-insensitive,这些仅能是一个在容器站指定名字的桌面,但是一个桌面名字能在不同的窗口站中反复出现。

一个桌面也是一个安全的内核对象,当一个新的桌面被创建,它和调用它的进程的当前的窗口站绑定在一起。那里将一直仅有一个桌面是可见并准备接收用户输入,

被提供的桌面和交互窗口站绑定在一起。激活的窗口被调用。

以下的桌面和窗口站的工程是为了提供在不同进程中的顶层解决。

三、关于虚拟桌面(一个简单的应用程序)

虚拟桌面帮助我们创建和在不同的桌面中转换。它甚至给你一个从一个桌面转到另一个桌面的感觉,但它不是真的,因为任何运行的应用程序不能被从一个

桌面移到另一个桌面。如我所说,它只是一个假象,这个应用程序在当前的桌面会被关闭,且在特殊的桌面会被打开。这个可能导致应用程序未保存的数据的丢失,

且可能不能保存状态,因为它可能重启。

这个应用程序用hooks来显示应用程序控制面板中的“Move To"菜单选项。对于hooks更多细节,在文章中我会提到,我将让你大约了解一下工程中用到的APIs和类。

Different APIs Used and Classes Built

1、初始化工作

主要是获得当前桌面的名字、根据名字设置应用程序标题并生成右下角图标、遍历系统中的桌面数量和名字并写注册表、

载入Evnent Hooker.dll,调用接口安装窗口HOOK和消息HOOK。

//Checks whether the specified desktop is current active desktop(deskop of the current thread).
bool CDesktopManager::GetCurrentDesktopName(TCHAR szDesktopName[ARRAY_SIZE])
{bool bReturn = false;try{DWORD iOutCount = 0;HDESK hCurrentDesktop = GetThreadDesktop(GetCurrentThreadId());if(!GetUserObjectInformation(hCurrentDesktop, UOI_NAME, szDesktopName, ARRAY_SIZE - 1, &iOutCount))throw _T("\nCDesktopManager::GetCurrentDesktopName:\t GetUserObjectInformation() failed.");bReturn = true;}catch(TCHAR *pszErrorString){DebugPrintErrorMessage(pszErrorString);}catch(...){DebugPrintErrorMessage(_T("\nCDesktopManager::IsCurrentDesktop\tException caught in CDesktopManager::IsCurrentDesktop."));bReturn = false;}return bReturn;
}
//Windows procedure hook (filter) function.
LRESULT CALLBACK WinProcHookProcedure(int nCode, WPARAM wParam, LPARAM lParam)
{if(0 > nCode)return CallNextHookEx(g_hPreviousWinProcHook ,nCode,wParam,lParam);CWPSTRUCT *pwsStruct = (CWPSTRUCT *) lParam;switch(pwsStruct->message){//Handle the init menu message.case WM_INITMENU:{HMENU hMenu = (HMENU) pwsStruct->wParam;OutputDebugString(_T("\nWinProcHookProcedure:\tMenu WM_INITMENUPOPUP Event Fired."));TCHAR szWindowText[ARRAY_SIZE] = {0};GetWindowText(pwsStruct->hwnd, szWindowText, ARRAY_SIZE);//Hook "Move To" Menu Into System Menu.if(0 != _tcscmp(szWindowText, _T("Virtual Desktop !")))InsertMenu(pwsStruct->hwnd);}}return CallNextHookEx(g_hPreviousWinProcHook ,nCode,wParam,lParam);
}//Set the Windows procedure filter.
bool InstallWinProcHook(void)
{bool bReturn = false;try{//Set the Windows procedure filter.OutputDebugString(_T("\nInstallWinProcHook:\tWinProc Event Hooked."));g_hPreviousWinProcHook = SetWindowsHookEx(WH_CALLWNDPROC,&WinProcHookProcedure,g_hInstance,0);if(NULL == g_hPreviousWinProcHook){TCHAR szError[ARRAY_SIZE] = {0};wsprintf(szError,_T("Last Error : %d"),GetLastError());OutputDebugString(_T("\nInstallWinProcHook:\tFailed to Hook WinProc Event.\n"));OutputDebugString(szError);bReturn = false;}else{OutputDebugString(_T("\nInstallWinProcHook:\tWinProc Event Hooked.\n"));bReturn = true;}}catch(...){OutputDebugString(_T("\nInstallWinProcHook:\tException caught in InstallWinProcHook."));bReturn = false;}return bReturn;
}

在安装窗口HOOK的API函数 SetWindowsHookEx 时360安全卫士报告有异常!(这种情况怎么避免呢?知道的读者能告知我解决方法吗?)

//Set the message hook (Filter).
bool InstallMessageHook(void)
{bool bReturn = false;try{//Set the message hook (Filter).g_hPreviousMsgHook = SetWindowsHookEx(WH_GETMESSAGE,&MessageHookProcedure,g_hInstance,0);if(NULL == g_hPreviousMsgHook){OutputDebugString(_T("\nInstallMessageHook:\tFailed to Hook Messages.\n"));bReturn = false;}else{OutputDebugString(_T("\nInstallMessageHook:\tMessages Hooked.\n"));bReturn = true;}}catch(...){OutputDebugString(_T("\nInstallMessageHook:\tException caught in InstallMessageHook."));bReturn = false;}return bReturn;
}
2、响应窗口切换、启动应用程序、新建窗口动作
//Switch between desktops.
bool CDesktopManager::SwitchDesktop(TCHAR *pszDesktopName)
{bool bReturn = false;try{if (NULL == pszDesktopName){OutputDebugString(_T("\nCDesktopManager::SwitchDesktop:\tNULL DesktopName in CDesktopManager::SwitchToDesktop"));throw false;}/*if( !_tcsicmp(_T("Winlogon"), szDesktopName) || !_tcsicmp(_T("Disconnect"), szDesktopName)){TCHAR szErrorMsg[ARRAY_SIZE] = {_T("You can not switch to ")};_tcscat_s(szErrorMsg, ARRAY_SIZE -1, szDesktopName);_tcscat_s(szErrorMsg, ARRAY_SIZE -1, _T(" Desktop."));MessageBox(NULL, szErrorMsg, TXT_MESSAGEBOX_TITLE, MB_ICONINFORMATION);throw false;}*///Open desktop handle to switch to.HDESK hDesktopToSwitch = OpenDesktop(pszDesktopName, DF_ALLOWOTHERACCOUNTHOOK, TRUE, GENERIC_ALL);if(NULL == hDesktopToSwitch){TCHAR *pszError = NULL;TCHAR szErrorMsg[ARRAY_SIZE] = {0};int iErrorCode = GetLastError();if(5 == iErrorCode){FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, iErrorCode, 0, (LPWSTR) &pszError, 0, NULL);wsprintf(szErrorMsg, _T("Failed to switch to %s desktop.\n\t %s"), pszDesktopName, pszError);MessageBox(NULL, szErrorMsg, TXT_MESSAGEBOX_TITLE, MB_ICONINFORMATION | MB_TOPMOST | MB_TASKMODAL);OutputDebugString(pszError);}wsprintf(szErrorMsg, _T("\nCDesktopManager::SwitchDesktop:\tOpenDesktop Failed in CDesktopManager::SwitchToDesktop. Last Error : %s"), pszError);OutputDebugString(szErrorMsg);throw false;}//Switch the desktop.if(FALSE == ::SwitchDesktop(hDesktopToSwitch)){OutputDebugString(_T("\nCDesktopManager::SwitchDesktop:\tSwitchDesktop Failed in CDesktopManager::SwitchToDesktop"));throw false;}//Close the desktop handle.CloseDesktop(hDesktopToSwitch);bReturn = true;}catch(bool bThrownVal){bReturn = bThrownVal;}catch(...){bReturn = false;DebugPrintErrorMessage(_T("\nCDesktopManager::SwitchDesktop:\tException caught in CDesktopManager::SwitchToDesktop"));}return bReturn;
}
//Creates the new desktop (Adds new desktop)
void CVirtualDesktopDlg::OnBnClickedAddNewDesktop()
{// TODO: Add your control notification handler code hereTCHAR szCaption[ARRAY_SIZE] = {0};m_AddNewDesktop.GetWindowText(szCaption, ARRAY_SIZE - 1);if(_tcsicmp(szCaption, _T("&New"))){m_DesktopNameControl.GetWindowText(szCaption, ARRAY_SIZE -1);//Left trimming the string.while(' ' == szCaption[0])_tcscpy_s(szCaption, ARRAY_SIZE - 1, szCaption + 1);int iLen = (int) _tcslen(szCaption);//Right trimming the string.while(' ' == szCaption[--iLen])szCaption[iLen] = '\0';if(_tcslen(szCaption)){//Check the desktop name in the list.if(-1 != m_DesktopListControl.SelectString(0, szCaption)){MessageBox(_T("Desktop already created !"), TXT_MESSAGEBOX_TITLE, MB_ICONEXCLAMATION | MB_TOPMOST | MB_TASKMODAL);}//Create the desktopif(CDesktopManager::CreateDesktop(szCaption)){if(IDYES == MessageBox(_T("New Desktop is been created.\nWould you like to switch to new desktop ?"), TXT_MESSAGEBOX_TITLE, MB_YESNO | MB_ICONINFORMATION | MB_TOPMOST | MB_TASKMODAL))SwitchDesktopTo(szCaption);m_DesktopListControl.AddString(szCaption);m_DesktopListControl.SelectString(0, szCaption);OnLbnSelchangeDesktopList();UpdateHotKeys();}}else{MessageBox(_T("Please enter Desktop Name"), TXT_MESSAGEBOX_TITLE, MB_ICONEXCLAMATION | MB_TOPMOST | MB_TASKMODAL);m_DesktopNameControl.SetWindowText(_T("")); m_DesktopNameControl.SetFocus();}}else{m_AddNewDesktop.SetWindowText(_T("&Add"));m_DesktopNameControl.SetWindowText(_T(""));m_DesktopNameControl.EnableWindow(TRUE);m_SwitchToDesktop.EnableWindow(FALSE);m_DesktopNameControl.SetFocus();}
}

虚拟桌面:一个简单的桌面管理工具相关推荐

  1. [Winform]一个简单的账户管理工具

    最近一直觉得注册的账户越来越多,帐号密码神马的容易弄混.自己就折腾了一个简单的账户管理工具,其实实现也挺简单,将每个账户的密码及相关密码提示信息,经aes算法加密之后保存到数据库,当前登录用户可以查询 ...

  2. Python开发第一步:如何制作一个简单的桌面应用

    Python开发第一步:如何制作一个简单的桌面应用 前言 大家好,我是baifagg, 一个热爱Python的编程爱好者. 今天我们来学习一下, 如何用Python制作一个简单的桌面应用程序. 虽然桌 ...

  3. SilkierQuartz 1.0.21 发布, 是一个 Quartz.NET 的强大且简单的Web管理工具和承载组件...

    SilkierQuartz 是一个新的合并了 Quartzmin 和 QuartzHostedService的组件! Quartz.NET 是一个完整的开源的任务规划系统,从小应用至大型企业级应用都可 ...

  4. Python简单主机批量管理工具

    Python简单主机批量管理工具 一.程序介绍 需求: 简单主机批量管理工具需求:1.主机分组2.主机信息使用配置文件3.可批量执行命令.发送文件,结果实时返回4.主机用户名密码.端口可以不同5.执行 ...

  5. 一个简单的主机管理模拟程序

    最近写的一个小练习,主要是把前面学的东西整合一下.写了一个简单的主机管理界面,主要是练习以下知识点: Session和Cookie进行登录验证(装饰器) 数据库的基本操作 (单表,1对多,多对多) F ...

  6. 实现一个简单的压测工具

    公司开发了一些服务器程序:上生产前需要进行压力测试,测试点包括:并发数.响应时间.吞吐量等指标.领导说,能不能仿照LoadRunner实现一个简单的压测工具(并发数在10000以上,结果指标以曲线图的 ...

  7. Asp.NetMVC利用LigerUI搭建一个简单的后台管理详解(函登录验证)

    上一篇 Asp.Net 中Grid详解两种方法使用LigerUI加载数据库数据填充数据分页 了解了LigerUI 中Grid的基本用法  现在结合上一篇的内容做一个简单的后台管理,当然也有前台的页面. ...

  8. 笔记本屏幕出现横条纹_笔记本支架+拓展坞+立式无线充:给你的桌面一个简单的品质升级...

    一.写在前面 如果每个女孩都想拥有一个自己的衣帽间的话,每个喜欢科技的男孩,都想拥有一个属于自己的书房或者说游戏间,而这其中书桌是陪伴我们最多的地方,怎么打造一个舒适好用的桌面,让桌面简单而有品质呢, ...

  9. 一个简单的硬盘管理器的实现暨南京邮电大学操作系统——实验四:简单文件系统模拟实验

    文章目录 前言 关于GPT的那点事 硬盘分区和文件系统的关系 GPT规范和MBR规范的历史[^1] GPT规范 开始干活 GPT类 定义GPT分区相关管理结构 创建一个GPT的管理类 GPT类的声明 ...

最新文章

  1. 20140417--Linux课程讲解目录索引
  2. java中避免空指针_在Java中避免空检查
  3. python爬虫脚本ie=utf-8_Python反爬虫伪装浏览器进行爬虫
  4. Git 初学札记(十)—— Reset 回退的三种状态解析
  5. windows2003密码忘记了该如何处理
  6. 数学模型——药物中毒急救模型(基于python)
  7. 下载各种百度文库以及豆丁网文章的简便方法
  8. 华为研发模式演进历程
  9. win10卸载git_提高win10 系统 git 速度的方法
  10. 蜂巢迷宫 c语言,最强大脑的蜂巢迷宫 创意源于此
  11. 初学者应该如何学习法语呢?
  12. 使用牛顿迭代法求根 一元三次方程的根
  13. Python 预测 NBA 比赛结果
  14. koa2入门之使用koa-generator生成koa2项目
  15. DID-双重差分模型
  16. 搜狗输入法简约而美的皮肤推荐
  17. JAVA课程设计——华容道小游戏
  18. 附有限制条件的间接平差类(+抗差估计)
  19. ipad无法充电怎么办_ipad不能充电怎么办 ipad不能充电解决方法【图文】
  20. JSP中的taglib标签如何让JSP页面使用标签

热门文章

  1. 个人注册PowerBI账号申请
  2. MuseScore入门教程(三、添加声部)
  3. 【RGB手持补光棒调光照明方案】 单节双节电池LED升压恒流驱动调光芯片FP7208,PWM内部转模拟调光,无频闪顾虑低亮无抖动
  4. 川土微电子|CA-IS1200G全差分隔离运放ADC简介
  5. isset与empty的区别
  6. 1023day5:class类属性方法、每次执行类属性+1、内建模块、时间装饰器wrapper、面向对象__slots__方法:限制类的属性等基础知识、正则表达式基础知识、多态鸭子类型
  7. sklearn中的特征工程(过滤法、嵌入法和包装法)
  8. Hibernate_9_Person和IdCard实例_一对一关系:基于主键
  9. 如何使用Grafana轻松实现OVL数据可视化
  10. 20200724-Java-抽象类、接口