活动桌面处理和一个例子

问题:
在应用程序中如何激活活动桌面(Active Desktop)?一般情况下用户可以在桌面单击右键,选择“活动桌面”=〉“按Web页查看”来打开/关闭活动桌面特性。有没有什么函数可以程序中调用来实现对活动桌面的操作?另外,如何断定用户激活或取消活动桌面?

解答:
在回答这个问题之前,让我给你一个重要警告。那就是如果你打算开关活动桌面特性,请保证经过了用户的许可!最好使用大字体清晰地显示:“你真的想要激活活动桌面吗?”要是没有这样的提示,对用户不免有些粗鲁。有些用户并不想要什么程序来决定是否启动活动桌面。如果用户真要是喜欢Web特性而不想失去活动桌面。那他们也会容忍由此而带来的性能下降。
好吧,这么多严厉的警告。现在假设你有充足的理由打开或关闭活动桌面。也许你在写一个新的外壳。为了激活或取消活动桌面,你需要使用IActiveDesktop,这是个活动桌面的COM接口。下面列出的是这个接口的方法列表:
//
IActiveDesktop 接口方法表
方法 功能和用途

AddDesktopItem 添加一个桌面项。
AddDesktopItemWithUI 使用某个用户界面添加一个桌面项到活动桌面。
AddUrl 添加与指定的URL关联的桌面项。
ApplyChange 执行对活动桌面的修改。要使修改生效必须调用这个函数。用于激活或取消活动桌面。
GenerateDesktopItemHtml 产生包含给定桌面项的通用HTML页面。
GetDesktopItem 获得指定的桌面项。
GetDesktopItemByID 获得与给定ID匹配的桌面项。
GetDesktopItemBySource 用源URL获得某个桌面项。
GetDesktopItemCount 或的桌面项计数。
GetDesktopItemOptions 检查活动桌面是否打开或关闭。SHGetSettings 性能更佳。用于激活或取消活动桌面。
GetPattern 获取当前使用的式样。
GetWallpaper 获取当前使用的墙纸。仅用于活动桌面。标准模式时(桌面关闭),使用SystemParametersInfo。
GetWallpaperOptions 获得墙纸选项。仅用于活动桌面。标准模式时(桌面关闭),使用SystemParametersInfo。
ModifyDesktopItem 修改桌面项。
RemoveDesktopItem 从桌面删除指定的桌面项。
SetDesktopItemOptions 打开或关闭活动桌面。
SetPattern 设置活动桌面式样。
SetWallpaper 设置活动桌面墙纸。仅用于活动桌面。标准模式时(桌面关闭),使用SystemParametersInfo。
SetWallpaperOptions 设置墙纸选项。仅用于活动桌面。标准模式时(桌面关闭),使用SystemParametersInfo。

//
用IActiveDesktop可以添加和删除桌面项(HTML页面,图像,URLs或者ActiveX 控件),设置和获取墙纸(仅用于活动桌面,在标准模式时要用SystemParametersInfo函数)及其它有用功能。你可以用来打开或关闭活动桌面的函数是SetDesktopItemOptions。但首先要考虑——如何获得IActiveDesktop接口?用通常使用COM的方法创建一个实例:
//
IActiveDesktop* pAD;
HRESULT hr = ::CoCreateInstance(
CLSID_ActiveDesktop,
NULL, // 不支持聚合,也就是说没有外部Unknown
CLSCTX_INPROC_SERVER,
IID_IActiveDesktop,
(void**)&pAD);
//

不要忘了在启动代码中调用CoInitialize,如MFC应用的InitInstance函数。一旦你有了ActiveDesktop指针,便可以调用它的方法。
//
// 激活活动桌面
COMPONENTSOPT opt;
opt.dwSize = sizeof(opt);
opt.fActiveDesktop =
opt.fEnableComponents = TRUE;
HRESULT hr = pAD->SetDesktopItemOptions(&opt,0);
//

现在活动桌面应该被激活,但真是这样吗?当你第一次运行时,什么事情也没发生。怎么回事呢?经过检查,我发现之所以设置没有起作用是因为有个小细节在文档中没有说明——将设置应用到活动桌面:
//
pAD->ApplyChanges(AD_APPLY_REFRESH);
//

用完接口之后不要忘了释放(Release)它!(当然,你不应该使用原始的接口指针,应该用ATL智能指针——希望你正在使用它们)为了检查活动桌面是否打开或关闭,有一个对应的Get函数——GetDesktopItemOptions,它使用相同的COMPONENTSOPT结构。还有一个外壳函数做同样的事情:
//
// 活动桌面打开或关闭了吗?
SHELLFLAGSTATE shfs;
SHGetSettings(&shfs,SSF_DESKTOPHTML);
BOOL bADEnabled = shfs.fDesktopHTML;
//

不需要COM,CoCreateInstance,IActiveDesktop,或任何有关COM接口的东西。只要调用这个函数。你可以用SHGetSettings来检查一系列的外壳设置,下面列出了有关SHGetSettings使用的详细信息。这些设置或多或少与Windows 9x的资源管理器(参见图四)中“查看”=〉“文件夹选项”=〉“查看”标签中的选项对应。(Windows 2000有所不同,它是在“工具”=〉“文件夹选项”=〉“查看”标签中)可惜没用对应的SHSetSettings函数。
//
// 用SHGetSettings获得信息
// SHGetSettings 获得当前外壳设置
//
VOID SHGetSettings(
LPSHELLFLAGSTATE lpsfs, // 下列结构的地址
DWORD dwMask // 获取哪个信息(参见下面内容)
);

// SHGetSettings 填充下面的位域结构. 这些标志与Explorer的“查看”=〉“文件夹选项”=〉“查看”标签中的选项对应
//
typedef struct {
BOOL fShowAllObjects : 1; // 显示所有文件 (隐藏的或系统的)
BOOL fShowExtensions : 1; // 显示文件扩展名 (如 .txt)
BOOL fNoConfirmRecycle : 1; // 删除时不确认
BOOL fShowSysFiles : 1; // 显示文件的系统属性
BOOL fShowCompColor : 1;
BOOL fDoubleClickInWebView : 1; // 顾名思义
BOOL fDesktopHTML : 1; // 已打开活动桌面
BOOL fWin95Classic : 1; // 已打开Windows 95 "传统"视图
BOOL fDontPrettyPath : 1;
BOOL fShowAttribCol : 1;
BOOL fMapNetDrvBtn : 1; // 显示网络驱动器按钮
BOOL fShowInfoTip : 1; // 显示弹出式描述
BOOL fHideIcons : 1; //在活动桌面模式中隐藏图标
UINT fRestFlags : 3;
} SHELLFLAGSTATE;

// 这些标志被用于获取上面的这些域;如调用时使用:
dwMask =
// (SSF_DESKTOPHTML | SSF_WIN95CLASSIC) 来获取 fDesktopHTML 和
// fWin95Classic。
//
#define SSF_SHOWALLOBJECTS 0x00000001
#define SSF_SHOWEXTENSIONS 0x00000002
#define SSF_SHOWCOMPCOLOR 0x00000008
#define SSF_SHOWSYSFILES 0x00000020
#define SSF_DOUBLECLICKINWEBVIEW 0x00000080
#define SSF_SHOWATTRIBCOL 0x00000100
#define SSF_DESKTOPHTML 0x00000200
#define SSF_WIN95CLASSIC 0x00000400
#define SSF_DONTPRETTYPATH 0x00000800
#define SSF_SHOWINFOTIP 0x00002000
#define SSF_MAPNETDRVBUTTON 0x00001000
#define SSF_NOCONFIRMRECYCLE 0x00008000
#define SSF_HIDEICONS 0x00004000

图四 “查看”/“工具” 菜单 =〉“文件夹选项”=〉“查看”
现在我们知道由两种方法来检查是否活动桌面是否激活——SHGetSettings 和 IActiveDesktop::GetDesktopItemOptions,哪个方法好呢?这很重要吗?为了回答这个问题,让我们来探讨问题中的第二部分:如何断定用户激活或取消活动桌面,不论是从桌面菜单或者是从属性对话框(如图五)?

图五 选择活动桌面
当用户打开或关闭活动桌面时,Windows广播WM_SETTINGCHANGE消息给所有最上层窗口,消息值分别为:wParam = 0 和 lParam = "ShellState"。所以为了捕获这个事件,必须处理WM_SETTINGCHANGE消息。
//
// 最上层框架窗口!
void CMainFrame::OnSettingChange(UINT
uFlags, LPCTSTR pszSection)
{
if (lpszSection &&
_tcscmp(pszSection,_T("ShellState"))==0) {
// do what you want
}
CFrameWnd::OnSettingChange(uFlags,
pszSection);
}
//

WM_SETTINGCHANGE是个Windows的常用消息,当程序修改了SystemParametersInfo设置,则Windows就会广播此消息。但WM_SETTINGCHANGE也比较多地用在其它情形。
一般情况下,wParam/uFlags时0,lParam/pszSection是WIN.INI段名或被修改部分的注册表键(只是最终的键,而不是整个串)。事实上,WM_SETTINGCHANGE常被叫做WM_WININICHANGE,这两个符号在#define中的值也一样!当IActiveDesktop广播设置修改时,它将“ShellState”作为段名来传递,因为活动桌面设置被存储在一个注册表键中:

/HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ShellState

另外,如果你要广播自己修改的全程设置,也可以使用WM_SETTINGCHANGE。广播是应该使用SendMessageTimeout(HWND_BROADCAST, ...)函数。

图六 TestAD
为了整合所讲的内容,我编写了一个小程序:TestAD(如图六)。当TestAD获得 WM_SETTINGCHANGE时,便显示一条消息。利用我创建的一个类(CActiveDesktop)来获得并设置活动桌面的状态。为了使用这个类,你只要编写如下代码:
//
CActiveDesktop ad;
if (!ad.IsEnabled())
ad.Enable(TRUE);
//

CActiveDesktop隐藏了所有与COM有关的琐事。它使用ATL智能指针来保证接口处理的正确性和整体处理的自动化。如果你现在不使用CComQIPtr,那么赶快学会使用它,对于它的正确使用能使你获得健壮的,无错的COM代码,它非常有用。CActiveDesktop并没用封装所有的IActiveDesktop特性,只是封装了我编写TestAD所需要的功能。如果我什么时候想要编写一个Windows外壳时(我当然不会),再添加缺少的方法。但决定权在于你自己。CActiveDesktop非常简单,所以有关细节就请你参考源代码吧。
在实现CActiveDesktop和TestAD时,我遇到了一些意想不到的事情。首先是我在前面已经提到的在修改设置后要将它“应用”到(ApplyChanges)活动桌面的问题。其次是我发现了IActiveDesktop的同步bug问题。当我开始实现TestAD时,IActiveDesktop好像老是报告的错误状态。也就是说活动桌面真正打开的时候,它报告的是关闭,反之亦然。我以为是我的代码有问题,但当我细究后发现IActiveDesktop::GetDesktopItemOptions事实上在报告错误的状态信息!请看下面的分析:
//
TestAD 调用 CActiveDesktop::Enable(TRUE).
//
CActiveDesktop 调用 IActiveDesktop::SetDesktopItemOptions, 然后将修改应
用到活动桌面(ApplyChanges)。
//
ApplyChanges 向最上层窗口广播WM_SETTINGCHANGE 消息。
//
CMainFrame获得WM_SETTINGCHANGE,并调用IActiveDesktop::GetDesktopItemOptions
来获得开/关状态——但IActiveDesktop报告的状态仍然是关闭!
//

显然IActiveDesktop在广播完成之前没有更新其内部的状态。即GetDesktopItemOptions报告的是旧的开/关状态。碰到这种情况怎么办呢?我试图自己通过消息处理来修正这个问题,也就是在主窗口处理完WM_SETTINGCHANGE消息后添加“活动桌面开/关消息”。结果在TestAD程序中开/关活动桌面倒是没什么问题了,但当我用桌面上下文菜单的时候,又发生同样的问题。不用怀疑,肯定是当TestAD处理添加的消息时,Windows仍然在向下一个最上层窗口广播WM_SETTINGCHANGE消息。
怎么办?难道在显示状态信息前等待半秒钟?真臭。这时如果用SHGetSettings就没问题啦。实践证明,SHGetSettings报告的是正确的活动桌面开/关状态,即便GetDesktopItemOptions报告的是相反的状态——真让人高兴!很显然,ApplyChanges更新注册表是在广播WM_SETTINGCHANGE消息之前及在更新其内部状态之前——这是一件让人哭笑不得的事情。
现在我们应该可以明确回答前面提出的问题了:用哪个方法来获得活动桌面得开/关状态
好呢?好像SHGetSettings最接近正确答案。

活动桌面处理和一个例子相关推荐

  1. linux运行qt桌面生成pro怎么写,把桌面qt代码编译运行到qpe上的一个例子

    qt-x11版本是2.3.2 qt core版本是2.3.2 qtopia版本是2.2.x qt-x11版本安装目录下的tutorial目录下有一些例子.我把其中的t7目录下的程序(这是一个lcd数值 ...

  2. 打开计算机首先映入眼帘的一整屏称之为桌面,利用“活动桌面” 让桌面也“闪”起来...

    每天打开电脑,首先映入眼帘的就是Windows的系统桌面,时间一长你一定会觉得它们枯燥乏味.如今,各种Flash动画铺天盖地,其中不乏经典之作,你有没有想过让它们在你的桌面上也"闪" ...

  3. [asp.net core]SignalR一个例子

    摘要 在一个后台管理的页面想实时监控一些操作的数据,想到用signalR. 一个例子 asp.net core+signalR 使用Nuget安装包:Microsoft.AspNetCore.Sign ...

  4. R语言使用lm构建线性回归模型、并将目标变量对数化(log10)实战:可视化模型预测输出与实际值对比图、可视化模型的残差、模型预测中系统误差的一个例子 、自定义函数计算R方指标和均方根误差RMSE

    R语言使用lm构建线性回归模型.并将目标变量对数化(log10)实战:可视化模型预测输出与实际值对比图.可视化模型的残差.模型预测中系统误差的一个例子 .自定义函数计算R方指标和均方根误差RMSE 目 ...

  5. 如何使用意图将对象从一个Android活动发送到另一个?

    如何使用Intent类的putExtra()方法将自定义类型的对象从一个Activity传递到另一个Activity ? #1楼 感谢您的包裹帮助,但我发现了另一种可选解决方案 public clas ...

  6. python中self_一个例子带你入门Python装饰器

    ============ 欢迎关注我的公众号:早起python ============ 前言 在还未正式发布的python3.9中,有一个新功能值得关注,那就是任意表达式可以作为装饰器,如果你还不知 ...

  7. 在桌面上创建一个宽带连接服务器,win7宽带连接怎么创建桌面

    win7系统是一款大家用了都说好的系统.最近一直有小伙伴们在问win7宽带连接怎么创建桌面的问题?今天小编就为大家带来了win7宽带连接创建设置一起来看看吧. win7宽带连接创建设置: 1.点开始, ...

  8. ftp服务器文件备份,数据备份是十分重要的,下面是通过ftp将本机数据备份到远程服务器的一个例子...

    数据备份是十分重要的,下面是通过ftp将本机数据备份到远程服务器的一个例子 以备份oracle数据为例 本机IP:192.168.0.1 远程IP:192.168.0.111 备份脚本 ora_bak ...

  9. Bootice1.34版本把grub4dos0.46a写入硬盘MBR失败一个例子

    Bootice1.34版本把grub4dos0.46a写入硬盘MBR失败一个例子         一个同事的台式机,BIOS启动,500GB硬盘,分了四个MBR分区,C盘是激活的主分区,第二个分区50 ...

  10. 用一个例子告诉你gdb调试工具如何使用

                                        用GDB调试程序 GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式 ...

最新文章

  1. Linux无盘教程,如何无盘启动Linux
  2. 天池实验室Python能力测验
  3. mysql数据存储方式_数据存储在mysql的两种方式
  4. .NET开发框架(四)-服务器IIS实践教程
  5. Terrafugia希望在今年夏天带来真正可飞的Airplane
  6. FTP协议、电子邮件系统、Telnet远程控制
  7. 堆排序时间复杂度_图解堆结构、堆排序及堆的应用
  8. 恒大紧急辟谣“资金链断裂”,股价止跌回升
  9. C#学习笔记-ContextMenuStrip
  10. PHP统计订单表,订单售后表金额
  11. UIScrollView, 滚动视图
  12. ISO常见的17大体系介绍
  13. Laravel框架教程 入门篇(一)
  14. 维吉尼亚密码(Vigenere)
  15. 无需输入密码,XP自动登录域
  16. android 调用webservice实现手机号码归属地查询
  17. BZOJ 2243: [SDOI2011]染色
  18. iPhone7可以共享热点给多少设备使用呢?
  19. 2021 Google 游戏开发者峰会回顾: 最新产品和解决方案为您划重点
  20. 论文阅读:Generating Abstractive Summaries with Finetuned Language Models

热门文章

  1. arcgis制作瓦片地图_利用ArcGISDesktop制作【地图瓦片包(TPK切片包)】的技术流程及优化...
  2. 使用 Visio 绘制卷积示意图
  3. Raspberry-Pi-PICO系列--第八篇 高级篇使用SWD接口下载和调试(第一章)
  4. drupal_Drupal在斯隆凯特琳纪念堂的早期采用
  5. 【csdn博客文章】导出备份
  6. 供应链金融(Supply Chain Finance)
  7. 再战港交所的高视医疗,近视小伙伴的福音?
  8. 如果可能,与孤独为友!
  9. 简信CRM:CRM科学服务体系,促进企业销售增长
  10. 番茄todo服务器维护,番茄ToDo:克服“拖延症”必备高效神器!