Windows屏幕保护程序的制作


                                                              Windows屏幕保护程序的制作


前些日子看了阿卓工作室的一篇关于如何制作屏保程序的文章及其示例,我便想自己做一个玩玩,所以按他说的做,结果不行,所以就在MSDN中搜索了下,得到这么一篇文章,翻译备份如下,以后要用得时候看:

 

                                      屏幕保护程序的制作

Microsoft的WIN32API支持特殊类型程序-屏保程序的制作.当鼠标或键盘空闲一定的时间后屏保程序就会自动启动.之所以屏保的原因是:......

这篇文章包括两个部分:
1:关于屏保程序的使用
2:如何调用屏保函数制作屏保程序

1:关于屏保程序的使用
在WINDOWS的控制面板中有一个程序,可以让用户从一个屏保列表中选择要使用的屏保程序,并指定空闲多长时间启动屏保,以及其它一些相关设置,另外还可以对屏保进行预览.屏保程序的启动一般由WINDOWS根据用户的设定自己启动,也可以由用户手动从控制面板启动.
一旦选定了一个屏保程序,WINDOWS就会启动键盘及鼠标监视,在适当的时候启动屏保.但是在下述情况下WINDOWS不会自动启动屏保:
当前活动的程序不是基于WINDOWS的应用程序.
当前活动的程序是computer-based training (CBT)类型的.
当前活动的程序接受到以SC_SCREENSAVE为wparam值的WM_SYSCOMMAND消息,但不把该消息传回DefWindowProc()函数.
屏保程序包含指定的出口函数,资源定义以及变量声明.屏保链接库包括了主函数MAIN及一个屏保所需要的必要代码.当屏保程序启动时,链接库中的启动代码创建一个全屏的窗口.它的窗口类设置如下:

WNDCLASS cls;
cls.hCursor        = NULL;
cls.hIcon          = LoadIcon(hInst, MAKEINTATOM(ID_APP));
cls.lpszMenuName   = NULL;
cls.lpszClassName  = "WindowsScreenSaverClass";
cls.hbrBackground  = GetStockObject(BLACK_BRUSH);
cls.hInstance      = hInst;
cls.style          = CS_VREDRAW  | CS_HREDRAW | CS_SAVEBITS | CS_DBLCLKS;
cls.lpfnWndProc    = (WNDPROC) ScreenSaverProc;
cls.cbWndExtra     = 0;
cls.cbClsExtra     = 0;
为了创建一个屏保程序,开发者在大多数情况下只需创建一个包含三个必需函数的屏保模块并且将它与屏保库链接起来即可.一个屏保模块只负责设定自己以及提供视觉效果.
三个必需函数中的一个是ScreenSaveProc()(译注:这个就是如上窗口类中指定的窗口处理函数),这个函数处理指定的几个消息并把未处理的消息传递给屏保链接库,下面是由ScreenSaveProc()函数处理的几个典型的消息:

消息           含意
WM_CREATE      从注册表文件Regedit.ini中找到初始化数据,并加以利用.设置一个TIMER.及其它初始化工作.
WM_ERASEBKGND  擦除屏保窗口背景,为后来的窗口绘制做好准备.
WM_TIMER       做绘制操作.
WM_DESTROY     销毁先前创建的TIMER.做必要的清除工作.

ScreenSaverProc()函数(通过屏保链接库)把自身未处理的消息传递给一个叫做DefWcreenSaverProc()的函数.下面描述了这个函数是如何处理各种消息的:
消息                    响应
WM_SETCURSOR            设定光标为NULL,并将之清除出屏幕
WM_PAINT                绘制窗口背景
WM_LBUTTONDOWN          终止屏保
WM_MBUTTONDOWN          终止屏保
WM_RBUTTONDOWN          终止屏保
WM_KEYDOWN              终止屏保
WM_MOUSEMOVE            终止屏保
WM_ACTIVATE             如果消息的wParam参数为FALSE的话终止屏保.


第二个必需的函数是ScreenSaverConfigureDialog()函数.这个函数显示一个可以让用户设置(译注:如果不知道何谓设置,请先设定一个屏保,在那儿点设置那个按钮就明白啦)关于你的屏保的一些参数的(译注:比如要显示的字,要显示的图片的位置...)对话框(一个应用程序必须提供一个对应的对话框模板).当用户在WINDOWS的控制面板中选择安装该屏保程序时WINDOWS就可以提供这个对话框给用户做相应设置.(译注:当然这个框中并不一定非设置些什么,可以只显示一些关于信息什么的,但这个对话框是必须要有的,因为如果没有的话当用户安装屏保时在那个面板上点设置按钮时,WINDOWS拿什么显示给用户?)
第三个必需的函数是RegisterDialogClasses()函数,这个函数必须由屏保程序所调用.但是,如果你的屏保程序在设置对话框中不需要生成特殊窗口(译注:???)或者自定义的控件的话,这个函数可以简单的只返回一个TRUE就可以了.反之,则需要在这个函数中注册相应的窗口类!
除了要提供如上所述的三个必需函数以外,一个屏保程序还必须有一个图标,这个图标只能在屏保程序以standalone application形态运行时才可见.(译注:什么是standalone application呢???)这个图标资源在屏保源文件中必须以ID_APP为其ID,这个ID是在屏保库文件的Scrnsave.h文件中定义的.
最后一个必需做到的是一个屏保程序description string.屏保的源文件中必须包含一个字符串,(译注:估计这个字符串也是在屏保链接库中定义的)这个串是在屏保选择的那个地方用来显示对这个屏保的标示的.这个description string在资源文件中的字符串表中必须是第一个串(也就是说它的序号为1.)
如何调用屏保函数制作屏保程序
这个部分用从一个屏保程序中的示例代码来说明讲解下述几个任务:
创建一个屏保程序.
安装新屏保.
为屏保设置对话框添加Help功能.
下面先讲解如何创建一个屏保程序:
在从1到10的一个时间范围内,例子中的这个程序用下面四种颜色:白,浅灰,深灰,黑中的一种颜色来重绘屏幕.这个程序当接受到一个WM_TIMER消息时做重绘.用户可以用一个在该屏保设置对话框中的垂直滚动条来调整这个间隔时间.
屏保链接库:
这些静态的屏保函数是包含在一个屏保链接库中的.有两种可以使用的版本:Scrnsave.lib或者Scrnsavw.lib.在你的工程中你必链接其中的一个.Scrnsave.lib是用于使用ANSI字符集的程序,而Scrnsavw.lib用于UNICODE字符集的屏保程序.一个链接了Scrnsavw.lib的屏保程序只能运行在支持UNICODE的WINDOWS平台上.而链接了Scrnsave.lib的屏保程序可以运行在任何WINDOWS平台上.
(译注:下面是示例程序,就不贴了,把我自己的程序贴上来就可以了)
因为我用的是笔记本电脑,我并不想用频繁重绘的屏保来损坏液晶屏,所以我打算写一个只显示一行静态文本的屏保程序,代码如下:
#include <windows.h>
#include <stdio.h>
#include <scrnsave.h>
#include "resource.h"
#define TIMER_ID  1
LRESULT CALLBACK ScreenSaverProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 static HDC hDC;
 static HPEN hPen,hOldPen;
 static CHAR str[100];
 int    iLength;
 switch (message){
 case WM_CREATE:
  SetTimer(hWnd, TIMER_ID, 500, NULL);
  return TRUE;
 case WM_TIMER:
  hDC=GetDC(hWnd);
  SetBkColor(hDC,RGB(0,0,0));
  SetTextColor(hDC,RGB(255,0,0));
  iLength=sprintf(str,"I can also make a ScreenSaver program for you!");
  TextOut(hDC,350,200,str,iLength);
  SelectObject(hDC, hOldPen);
  DeleteObject(hPen);
  ReleaseDC(hWnd, hDC);
  return TRUE;
 case WM_DESTROY:
  KillTimer(hWnd, TIMER_ID);
  return TRUE;
 default:
  return DefScreenSaverProc(hWnd,message,wParam,lParam);
 }
 return FALSE;
}
BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
 switch (message) {
 case WM_INITDIALOG:
  SetWindowPos(hDlg,HWND_NOTOPMOST,400,300,0,0,SWP_NOSIZE);
  return TRUE;
 case WM_COMMAND:
  EndDialog(hDlg, LOWORD(wParam));
  break;
 }
 return FALSE;
}
BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
 return TRUE;
}

需要注意的是:
1:在VC6中,要建一个Windows Application,而不是Windows Console Application.
2:要在Project->Settings->link中的Object/library modules中加入:scrnsave.lib (或者scrnsavw.lib).
3:对话框ID一定要设置为DLG_SCRNSAVECONFIGURE,图标的ID一定要设置为ID_APP.然后再找到New String Table这个图标,并在其中加入一个string:ID必须是IDS_DESCRIPTION,Caption可为任意.
4:在resource.h文件中一定要有#include<scrnsave.h>这句.
5:在VC的Project->Settings->Link选项卡中可以设置输出的文件名,你可以将输出的文件名的后缀改为.scr,使它直接输出屏幕保护程序文件,而不必每次都费力地去改名。
6:如果你想在屏保中输出一副图片,可参考下面这段代码:
LRESULT CALLBACK ScreenSaverProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 HINSTANCE      hInstance ;
 static HBITMAP hBitmap ;
 static HDC hDC, hdcMem;
 switch (message){
 case WM_CREATE:
  SetTimer(hWnd, TIMER_ID, 1000, NULL);
  hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
        hBitmap = LoadBitmap (hInstance, MAKEINTRESOURCE(IDB_BITMAP1)) ;
  return TRUE;
 case WM_TIMER:
  hDC=GetDC(hWnd);
  hdcMem = CreateCompatibleDC (hDC);
  SelectObject (hdcMem, hBitmap);
  BitBlt (hDC,0,0,1024,768, hdcMem,0,0,SRCCOPY);
  DeleteDC (hdcMem) ;
  ReleaseDC(hWnd, hDC);
  return TRUE;
 case WM_DESTROY:
  DeleteObject (hBitmap) ;
  KillTimer(hWnd, TIMER_ID);
  return TRUE;
 default:
  return DefScreenSaverProc(hWnd,message,wParam,lParam);
 }
 return FALSE;
}
8:因为我将TIMER设置为1秒钟后才发WM_TIMER消息,所以只有在启动了屏保1秒之后才可以看到效果,那么如果我想在屏保一开始就看到输出的东西,该怎么做呢?应该可以在WM_CREATE中发送一个WM_TIMER消息给程序.我试了一下:
 case WM_CREATE:
  SetTimer(hWnd, TIMER_ID, 1000, NULL);
  hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
            hBitmap = LoadBitmap (hInstance, MAKEINTRESOURCE(IDB_BITMAP1)) ;
  PostMessage(hWnd,WM_TIMER,TIMER_ID,NULL);
    return TRUE;
是可以正确运行的.但这地方的问题是如果我用SendMessage()函数就不能实现目的,不知是为什么?
9:我还是觉得一秒种就重绘一个位图还是不太好,所以我就改成了:
 case WM_TIMER:
  if(0==flag)
  {
   hDC=GetDC(hWnd);
   hdcMem = CreateCompatibleDC (hDC);
   SelectObject (hdcMem, hBitmap);
   BitBlt (hDC,0,0,1024,768, hdcMem,0,0,SRCCOPY);
   DeleteDC (hdcMem) ;
   ReleaseDC(hWnd, hDC);
   flag=1;
  }
  return TRUE;
呵呵,这下好啦.
10:其实在这个程序中有个主要的问题就是没从注册表中读信息,也没往注册表中保存用户设置,其实就压根没设置什么,呵呵,这是因为我还不会注册表的操作.
11:现在我还不知道如何在MFC框架下做一个屏保程序. 

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页