暮鼓集    行走集

1.引言

屏幕保护程序(Screen Saver)的历史几乎与视窗操作系统的历史一样悠久,设计它的目的是为了保护CRT显示器使其的使用寿命更长。但随着技术的进步,新型的CRT显示器及液晶显示器已经无须这样做了,不过屏幕保护程序并未消失,因为其绚丽的画面成了人们彰显个性的方式。

现在,逼真的水族箱,浩瀚的太空以及更吸引眼球的屏幕保护程序不段被开发出来。

如果你有兴趣开发自己的屏幕保护程序,并且具有Windows程序的开发经验,请深入阅读本文,本文将提供使用Win32 Platform SDK开发屏幕保护程序的指引及范例。

2.屏幕保护程序是一种应用程序

屏幕保护程序虽然变化多端,但对开发者而言,它仍然是一种Windows应用程序,虽然屏幕保护程序的扩展文件名是scr,但在文件格式上与exe可执行文件是完全一样的。

那么,是不是只要是Windows应用程序都可以作为屏幕保护程序呢?

我们做个一个实验,将Windows自带的“扫雷”程序文件winmine.exe改成winmine.scr,接着我们打开显示器设定,选择屏幕保护程序选项卡,可以发现winmine.scr已经被当成一个屏幕保护程序出现在列表里。我们选中它,看看发生了甚么--扫雷程序运行起来了!但是,随后无论我们如何摆弄键盘和鼠标,程序不会象其他屏幕保护程序那样自动关闭。

所以,虽然屏幕保护程序一种应用程序,但是它与普通应用程序在人机界面上有所不同,我们可以归纳出以下几点特征:

操作系统自动运行程序 全屏幕的窗口 用户输入即退出 因此,只要我们在一个应用程序中实现这些特征,那么这个应用程序即可做为屏幕保护程序。

3.实现屏幕保护程序的基本特征

3.1 操作系统自动运行程序

这实际上由系统完成,只要用户将程序设定为系统的屏幕保护程序,那么当用户没有输入一段时间后,系统就会自动调用这个程序。因此,这不需要开发者操心。

3.2. 创建全屏幕的窗口

我们在创建Window时设置其坐标及长宽参数即可实现这个目的:

CreateWindow( WNDCLASS_SSFRAME,NULL,WS_POPUP|WS_VISIBLE,0,0,GetSystemMetrics( SM_CXSCREEN ),GetSystemMetrics( SM_CYSCREEN ),HWND_DESKTOP,NULL,hInst,NULL);

注意,在这里函数参数中的父窗口句柄传入的是HWND_DESKTOP。

3.3. 用户输入即退出

用户输入的主要途径是通过键盘或鼠标,在Windows系统中,当键盘或鼠标事件发生时,系统会产生一系列的消息通知应用程序,具体有如下几个:

WM_LBUTTONDOWN   按下鼠标左键
WM_MBUTTONDOWN 按下鼠标中键   
WM_RBUTTONDOWN 按下鼠标右键
WM_MOUSEMOVE 鼠标移动
WM_KEYDOWN 按下键盘键
WM_KEYUP 抬起键盘键
WM_SYSKEYDOWN 按下键盘系统键

  (注: 系统键指Windows系统定义的用来激活菜单的F10键,以及按下Alt与其它键的组合键)。

因此,当屏幕保护程序收到这些消息时,应立刻退出运行,在消息处理函数添加如下的代码:

INT g_nOrigin_X = -1, g_nOrigin_Y = -1;switch( message )
{...
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_KEYDOWN:
case WM_SYSKEYDOWN:PostQuitMessage( 0 ); // 退出程序break;
case WM_MOUSEMOVE:{INT nNew_X = LOWORD(lParam);INT nNew_Y = HIWORD(lParam);if( g_nOrigin_X == -1 && g_nOrigin_Y == -1 ){g_nOrigin_X = nNew_X ;g_nOrigin_Y = nNew_Y ;}else if( g_nOrigin_X != nNew_X  &&  g_nOrigin_Y != nNew_Y )PostQuitMessage( 0 );}
...
}

请注意,程序对WM_MOUSEMOVE的消息的处理有些特殊。

当应用程序开始之行时,系统会将当前的鼠标坐标用WM_MOUSEMOVE消息通知应用程序。如果采用收到这个消息就退出处理方法,就会导致程序刚运行就会退出。因此,通过使用两个全局变量g_nOrigin_X和g_nOrigin_Y来纪录下初始化时的鼠标位置值。当再次收到这一消息时,通过比较当前鼠标位置与纪录的位置值可检测出鼠标有没有被移动过,若检测到则退出运行。

3.4 实现屏幕保护程序的画面

这与普通应用程序是完全一样的,在WM_PAINT里运用GDI API实现你的想法。在本例中,我们什么也不做,这就是简单实现黑屏的效果。

按照上面的方法生成的屏幕保护程序已经有模有样了。

4.成为真正的屏幕保护程序

尽管上述的应用程序已经很像一个屏幕保护程序了,但是,如果我们深入使用它,就会发现一些问题。

当我们把这个应用程序的扩展名改成scr并且设定它为系统的屏幕保护程序后,再次在控制面板中选择显示器设定并进入屏幕保护程序选项卡,发现及时我们没有“测试”,它却已经运行了。

这是因为,Windows系统会通过不同的命令行参数,以三种方式运行屏幕保护程序:

方式 命令行参数
正常(由系统自动执行,全屏幕显示 /s
配置(屏幕保护程序选项卡中的设定) /c
预览(显示在屏幕保护程序选项卡的小窗口中) /p

当我们一进入显示器设定的屏幕保护程序选项卡,系统就会自动在小窗口中预览当前选中的屏幕保护程序,即在命令行中传入/p参数运行了程序。而我们的程序中并未处理命令行参数,所以出现了上述的问题。

4.1 处理命令行参数

程序如下

if( __argc > 1 )
{if( strstr(__argv[1], "/p")){if( __argc == 3 ){hFrameWnd = (HWND)atoi( __argv[2] );GetClientRect( hFrameWnd, &rect );CreateWindow( "ScreenSaverDraw", NULL,WS_CHILD|WS_VISIBLE,rect.left, rect.top,rect.right, rect.bottom,hFrameWnd, NULL,hInst, NULL);return 0;}}else if(strchr(__argv[1], 'c') ){MessageBox( NULL, "This screen saver doesn't have configuration","Blank Screen Saver", MB_OK );// Preview modereturn 0;}
}

我们重点要处理的是/p和/c参数。

当系统传入/p参数时,一定会将预览窗口的句柄通过第二个命令行参数一并传入。因此在程序中,可以通过

hFrameWnd = (HWND)atoi( __argv[2] );

来获知预览窗口句柄,此后可以在此窗口中显示预览界面。

当系统传入/c参数时,通常我们要创建一个对话框,并在其中提供一些设定让用户对屏幕保护程序的外观进行定制而使其更具个性。在本程序中,为了简化,所以只其弹出一个对话框,告知用户"This screen saver doesn’t have configuration”。

4.2 密码验证

如果在设置屏幕保护程序的时候选择了密码保护选项,则当屏幕保护程序退出前,应该显示密码验证窗口。

应用程序如何获知用户有没有选择密码保护? Windows会通过发送消息SCRM_VERIFYPW消息来通知应用程序来进行保护。

我们可以定制一个对话框要求用户输入指定的密码。 也可以通过Windows的Shell API使用共用的密码界面,这会更加简单可靠。

处理SCRM_VERIFYPW的代码:

case SCRM_VERIFYPW:if( VerifyPassword(hWnd) )PostQuitMessage(0);break;

函数VerifyPassword的代码:

BOOL VerifyPassword( HWND hwnd )
{// Under NT, we return TRUE immediately. This lets the saver quit,// and the system manages passwords. Under '95, we call VerifyScreenSavePwd.// This checks the appropriate registry key and, if necessary,// pops up a verify dialogOSVERSIONINFO osv;HINSTANCE hpwdcpl;typedef BOOL (WINAPI *VERIFYSCREENSAVEPWD)(HWND hwnd);VERIFYSCREENSAVEPWD VerifyScreenSavePwd;BOOL bRet;osv.dwOSVersionInfoSize = sizeof(osv);GetVersionEx( &osv );if( osv.dwPlatformId == VER_PLATFORM_WIN32_NT )return TRUE;hpwdcpl = LoadLibrary( "PASSWORD.CPL" );if( hpwdcpl == NULL )return TRUE;VerifyScreenSavePwd=(VERIFYSCREENSAVEPWD)GetProcAddress(hpwdcpl,"VerifyScreenSavePwd");if (VerifyScreenSavePwd==NULL){FreeLibrary( hpwdcpl );return TRUE;}bRet = VerifyScreenSavePwd( hwnd );FreeLibrary(hpwdcpl);return bRet;
}

4.3 处理其它消息

屏幕保护程序还必须处理如下系统消息

WM_ACTIVATE

WM_ACTIVATEAPP

WM_NCACTIVATE   

这是因为我们没有处理WM_SYSCOMMAND消息。当我们选择最大化,最小化按钮,选择系统菜单时等等,或者是应用程序就会收到这个消息,

前三个消息指示当程序窗口被系统或其它应用程序解除活动状态时,应退出。(注,wParam为FALSE表示收到这是一个DEACTIVATE消息。WM_SYSCOMMAND是系统通知消息,wParam标示参数类型,SC_SCREENSAVE和SC_CLOSE表示系统要求执行预定的屏幕保护程序和结束程序,这两种情况下,也应该结束程序的执行。

代码如下:

switch( message )
{...
case WM_ACTIVATE:
case WM_ACTIVATEAPP:
case WM_NCACTIVATE :if( wParam == FALSE )PostQuitMessage( 0 );break;case WM_SYSCOMMAND:if( wParam == SC_SCREENSAVE || wParam == SC_CLOSE )PostQuitMessage( 0 );break;...
}

4.4 隐藏光标

由于屏幕保护程序运行过程中,不需要与用户互动,因此鼠标光标没有必要显示出来。隐藏鼠标的光标可以通过处理WM_SETCURSOR消息来实现。

case WM_SETCURSOR:  SetCursor( NULL );  return FALSE;

5.让开发更简单-Screen Saver程序库

使用上述的方法所开发的应用程序已经具有屏幕保护程序的典型特征了。我们可以了解,任何屏幕保护程序为了实现其共有特征,必须对键盘,鼠标和部分系统消息进行相同的处理。

Microsoft考虑到了这一点,它对这些处理过程进行封装,这就是Screen Saver程序库scrnsave.lib。

在这个程序库中,Mircosoft封装了包括WinMain,注册Window Class(窗口类),建立消息循环等过程。开发者要做的只是完成名为”ScreenSaverProc”的消息处理函数。

下面是用Screen Saver程序库改写的”全屏”程序的完整代码。

#include <windows.h>
#include <scrnsave.h>LRESULT CALLBACK ScreenSaverProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{switch( message ){case WM_PAINT:{PAINTSTRUCT ps;HDC hdc;RECT rect;GetClientRect( hWnd, &rect );hdc = BeginPaint(hWnd, &ps);hBrush = CreateSolidBrush( RGB(0,0,0) );FillRect( hdc, &rect, hBrush );DeleteObject( hBrush );EndPaint( hWnd, &ps );}break;case SCRM_VERIFYPW:ScreenSaverChangePassword( hWnd );break;}defScreenSaverProc(hWnd, message, wParam, lParam);
}BOOL WINAPI RegisterDialogClasses (HANDLE hInst)
{return TRUE;
}BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{switch( message ){case WM_INITDIALOG:return FALSE;}return 0;
}

6.结束语

通过阅读本文,相信读者已经掌握了屏幕保护程序的开发方法。对于开发一般的屏幕保护程序,我建议使用Screen Saver程序库进行开发,这样,开发者可以将精力放在屏幕保护程序的内容的开发上,从而提高开发的效率。

使用Win32 SDK开发屏幕保护程序相关推荐

  1. [译]用C#创建一个屏幕保护程序

    用C#创建一个屏幕保护程序 原文地址: http://www.harding.edu/fmccown/screensaver/screensaver.html 简介 一个Windows屏幕保护程序是根 ...

  2. 如何启动屏幕保护程序

    当前屏幕保护程序在注册表中的位置: HKEY_CURRENT_USER/Control Panel/Desktop As for starting an exe in C#: Process myPr ...

  3. html文件设置成mac屏保,Mac怎么设置屏幕保护?如何设置Mac屏幕保护程序?

    Mac电脑如何设置屏幕保护程序?屏保是我们显示个性的重要途径,也是保护我们的电脑安全的一个重要方法.MAC用户想要修改自己的屏保该怎么办呢?今天PC6小编就教大家如何在Mac系统下设置桌面背景以及屏幕 ...

  4. 询问HTG:白噪声屏幕保护程序,有效的文件命名以及从密码泄露中恢复

    Once a week we share three of the questions we've answered from the Ask HTG inbox with the greater r ...

  5. windows xp 屏幕保护程序_小礼物:3D Windows XP 屏幕保护程序

    航通社旗下公众号"56K小猫"(微信:modem56k),原创文章未经授权禁止转载.航通社微信:lifeissohappy 微博:@航通社 生 / 活 / 小 / 妙 / 招 从昨 ...

  6. 个性屏幕保护程序_Mac高清鸟瞰屏幕保护程序,酷毙了

    最新的Aerial for Mac配备了一个漂亮的屏幕保护程序,由在旧金山,纽约,伦敦,中国和许多其他地方录制的一系列航拍电影组成.如果您想在Mac上使用这些剪辑,现在有一种简单的方法可以实现. Ae ...

  7. html文件设置成mac屏保,如何将视频设置为Mac上的屏幕保护程序 | MOS86

    尽管您可能已经在享受Mac上预装的屏幕保护程序,但现在您可以添加一种新的屏幕保护程序到Mac.您现在可以将视频添加为屏幕保护程序. 输入SaveHollywood,一个Mac应用程序,允许您将视频设置 ...

  8. linux替换屏幕保护进程,有没有一个体面的方式来阻止linux中的屏幕保护程序?...

    我正在寻找一种体面的,不跛脚的方式来禁止xscreensaver,kscreensaver或gnome-screensaver,哪些可能正在运行,最好是以屏幕保护程序的方式,而且它绝对肯定必须执行得很 ...

  9. 液晶显示器不宜使用屏幕保护程序

        在使用台式电脑时,很多人都喜欢使用屏幕保护程序,当他们转为使用笔记本电脑时,这个好习惯也被保留了下来,但他们却不知屏幕保护程序对笔记本电脑非但没有任何好处,反而还会造成一些负面影响. 实际上屏 ...

最新文章

  1. React Native 环境搭建步骤
  2. Mac~终端安装Homebrew packages超时
  3. gateway请求拦截_一种网关对用户请求进行统一拦截判断是否放行的方法与流程...
  4. GWT(Google Web Tookit) Eclipse Plugin的zip下载地址(同时提供GWT Designer下载地址)
  5. java ocr linux_linux系统如何使用tess4j(java)进行ocr图片文字识别
  6. 关键字Restrict
  7. UCloud发布新一代归档存储产品,存储成本直降80%
  8. oracle sga设置 256G,Oracle SGA大小的解决方法的调整
  9. Vitamin-R for Mac(GTD工作效率管理工具)
  10. 重磅预告!企业上云的正确姿势
  11. 计算机专业毕业设计—351个VB管理系统源码打包(计算机专业整理)
  12. 计算机显示无法格式化,U盘无法格式化怎么办?Win7提示Windows 无法完成格式化的解决方法...
  13. ISCC2021—小明的宠物兔、表情包
  14. 用Python做数据分析之数据处理及数据提取
  15. 不可或缺的LTO磁带存储
  16. 16bit的pcm双声道转单声道
  17. 好用的Java工具类
  18. android pak文件_Android资源文件说明
  19. python docker 镜像过大_Docker镜像压缩与优化操作
  20. Cris 的Python日记(五):Python 数据结构之元祖,字典和集合

热门文章

  1. 基于兰彻斯特法则的通信运营商竞争形势研究
  2. stdio.h里的一些函数
  3. 特斯拉放弃私有化!马斯克想一出是一出
  4. 易语言linux静态编译失败,易语言静态编译出现错误求解决
  5. FTP,SFTP,HTTP,HTTPS网络传输协议
  6. 浙江大学发布四足机器人“绝影”,爬坡踏雪稳定性令人惊艳
  7. 解决jsp页面浏览器不兼容,样式变样问题
  8. 我的MSN Space
  9. 用计算机代码选址的优点,计算机机房选址原则
  10. 东方标准讲师谈“JAVA之我注六经”(上)