你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
可配置屏幕保护程序的API编程原理与方法
 

BCVC下可以利用OWL类库或MFC类库编制屏幕保护程序,但在更低一级层次上如完全采用API编程,如何来编制屏幕保护,特别是编制具有参数配置能力的屏幕保护程序呢?虽然利用某些类库编程具有方便性,但通过API编程编制屏幕保护程序,更能弄懂屏幕保护程序的原理,且执行代码不依赖任何类库而只依赖操作系统本身。下面就讲讲利用API编制具有参数配置能力的屏幕保护程序的原理与方法,希望对那些喜欢API编程的朋友或有某种特殊要求的朋友有所帮助。

一、屏幕保护程序原理

屏幕保护程序实际上是比较简单的WINDOWS应用程序,它不象一般应用程序需要创建主窗口,相反,它使用桌面即整个屏幕作为它的窗口。它既不包含WinMain()函数(不管任何编程语言下编制的WINDOWS应用程序都直接或间接包含有此函数),也不需要消息循环,但它一定需要三个函数。这三个函数是:ScreenSaverProcScreenSaverConfigDialogRegisterDialogClasses。下面简单介绍这三个函数。

ScreenSaverProc()是一个窗口过程,原型为:

LRESULT  WINAPI  ScreenSaverProc(HWND hwnd,UINT message,WPARAM wParam, LPARAM lParam) 。它被传递消息,并必须作出反应。如果该函数不作出处理消息,则必须调用DefScreenProc()hwnd中传递的是桌面的句柄,用户的屏幕保护程序要利用这一点。

ScreenSaverConfureDialog()是处理屏幕保护程序配置对话框的对话函数,原型为:

BOOL WINAPI ScreenSaverConfigureDialog(HWND hwnd,UINT message,WPARAM wParam, LPARAM lParam)。如果屏幕保护程序不需要配置,则该函数只要返回零就行了。如果屏幕保护程序支持配置,则必须在资源文件中定义它,并使ID值固定为DLG_SCRNSAVECONFIGURE,该值在必须包含的头文件SCRNSAVE.H中已经定义。

RegisterDialogClasses()用于定制窗口类,如定制控件,原型为:

BOOL WINAPI RegisterDialogClasses(HANDLE hInst)。如果屏幕保护程序不使用定制窗口,则简单地返回1就行了。本程序就没有使用该函数。

另外,屏幕保护程序还必须包含一个图标和一个字符串。图标的ID必须为ID_APP,它用于标志屏幕保护程序;字符串资源的标志符必须是IDS_DESCRIPTION,屏幕保护程序并不使用该字符串,只简单地提供屏幕保护程序的描述而已。这两个ID值都在SCRNSAVE.H中已经定义。

每次激活屏幕保护程序,它就接收到两条消息。第一条是WM_CREATE,屏幕保护程序需要使用此消息执行所需要的初始化操作,并启动定时器,设置好定时器的周期。第二条消息是WM_ERASEBKGND,屏幕保护程序利用此消息来实现清除屏幕。屏幕保护程序的实现是由一个定时器来驱动,每当定时器完成记数时,屏幕保护程序就接收到WM_TIMER消息,并更新屏幕显示。而当用户按一个键或移动鼠标时,屏幕保护程序就接收到一条WM_DESTROY消息,此时,屏幕保护程序需要取消定时器,并执行其它关闭任务。当编译连结生成EXE执行文件文件后,需要将它改为以SCR为扩展名的文件,然后拷贝到WINDOWS目录下的SYSTEM目录中,就可以选用控制面板选取和配置该屏幕保护程序了。

二、注册表使用原理

当屏幕保护程序有配置信息,如本屏幕保护程序中上次显示的字符串、字体大小等信息,这些东西若在下次仍有效,就需要保存下来。那么这些信息保存在什么地方呢?用一个文件当然可以,但配置信息很少,用一个文件太费事,而且如果有很多屏幕保护程序都有配置信息,使用的文件岂不太多了?因此,最好的办法是将这些信息保存在WINDOWS的注册表中。注册表是WINDOWS保持的特殊层次数据库,它保存有用户、机器、和安装的软件三项信息,内置有六个表项,这里我们只使用HKEY_CURRENT_USER就可以了。管理注册表可以使用以下几个API函数来实现。

    1.RegCreateKeyEx()-----该函数打开一个已经存在的注册表表项,当指定的注册表表项不存在时,就自动建立这个表项。如本程序利用该函数在注册表的内置项HKEY_CURRENT_USER下建立或读取一个表项"Software\\Programs\\屏幕保护程序".

    2.RegSetValueEx()-----当打开一个表项时,就可以利用这个函数在其下存储值。本程序就是在前面打开的表项下用delay存储定时器的周期数,用FontSize存储字体的象素大小,用message存储屏幕保存程序要显示的字符串。

    3.RegQueryValueEx()---在注册表中读取已存储的值。在本程序中,当不是首次运行本程序时,就需要利用该函数读取上次存储的三条信息。

   4. RegCloseKey()-----最后利用该函数关闭已打开的表项

   以上四个关于注册表管理的API函数,在程序中有具体应用,这里就不详细介绍其参数了。

本程序在VC6.0中调试通过,生成的程序可在WIN95WIN98中作屏幕保护程序使用。我们首先在File\new下的Project中选择Win32 Application,输入工程名如save,然后选择”An empty project”,单击”OK”后就自动建立一个空的工程。在Source files下添加一个已存在的的C++源程序或重新输入下面的源程序w.cpp,同时将save.hsave.rc资源文件添加入该工程项目中。然后运行生成save.exe文件,将该文件拷贝到WINDOWSSYSTEM目录中,并将该文件改名为save.scr。然后在屏幕上通过单击右键,在弹出菜单中选择属性,再在弹出的属性表中选择屏幕保护程序项,在下拉列表中选中save.scr屏幕保护程序后,可以对该屏幕保护程序进行设置。其弹出的对话框如下:

 

 

 

 

 

 

 

 

 

 

 

 

在延迟时间项中可以输入时间,也可以通过旋转按钮自动增大或减少延迟时间;字号大小这里采用的是一个字所占像素大小,可以输入数字,也可以通过对应旋转按钮改变;在显示信息栏中,可以自由输入一串新的中文或英文字符串,输入什么,屏幕保护程序就显示什么内容。完成配置后,单击确定就可以了。下次启动屏幕保护程序,使用就是上次配置的参数,因为这些参数都已经保存在注册表中了。

注意在VC中编译联结前,需要将屏幕保护程序库SCRNSAVE.LIB和通用控件库COMCTL32.LIB手工添入,具体操作方法是在Project\Settings\Link\Object\library modules编辑框中输入上面两个库名。若联结时找不到这两个库会出现错误。下面是源程序和资源文件。

1.源程序w.cpp

 #include <windows.h>

 #include <scrnsave.h>

 #include <commctrl.h>

 #include <string.h>

 #include "scr.h"

#define DELAYMAX     1000  //定义最大周期数

#define FontSizeMax  400  //定义最大像素

#define MSGSIZE   80     //定义字符串最大长度

 

char str[MSGSIZE]="欢迎来到电脑世界";  //初始字符串

int delay,zhi_hao;

unsigned long datatype,datasize;

unsigned long result;

char str_key[]="Software\\Programs\\屏幕保护程序";

HKEY  hRegKey;

HFONT hfont;

LOGFONT lf;

LRESULT  WINAPI ScreenSaverProc(HWND hwnd,UINT message,

   WPARAM  wParam,LPARAM lParam)

{

    static HDC hdc;

    static RECT  scrdim;

    static SIZE  size;

    static int X,Y;

    static HBRUSH  hBlkBrush;

    static TEXTMETRIC tm;

    switch(message)

      {

    case WM_CREATE:

    RegCreateKeyEx(HKEY_CURRENT_USER,str_key,

       0,"Screen Saver",0,KEY_ALL_ACCESS,NULL,&hRegKey,&result);

  if(result==REG_CREATED_NEW_KEY)

  {

  delay=200;

zhi_hao=120;//首次执行时在注册表中建立表项并设置周期数、字号大小和字符串信息

      RegSetValueEx(hRegKey,"delay",0,REG_DWORD,(LPBYTE)&delay,

          sizeof(DWORD));

      RegSetValueEx(hRegKey,"FontSize",0,REG_DWORD,(LPBYTE)&zhi_hao,

          sizeof(DWORD));

      RegSetValueEx(hRegKey,"message",0,REG_SZ,(LPBYTE)str,strlen(str)+1);

  }

  else

  {  datasize=sizeof(DWORD);

     RegQueryValueEx(hRegKey,"delay",NULL,&datatype,(LPBYTE)&delay,&datasize);

     RegQueryValueEx(hRegKey,"FontSize",NULL,&datatype,(LPBYTE)&zhi_hao,&datasize);

     datasize=MSGSIZE;

     RegQueryValueEx(hRegKey,"message",NULL,&datatype,

         (LPBYTE)str,&datasize);

  }//非首次执行就读取上次存储的信息

    RegCloseKey(hRegKey);

    SetTimer(hwnd,1,delay,NULL); //启动定时器

    hBlkBrush=(HBRUSH)GetStockObject(BLACK_BRUSH);

    lf.lfHeight=zhi_hao;    lf.lfWidth=0; 

    lf.lfEscapement=0;  lf.lfOrientation=0;

    lf.lfWeight=FW_HEAVY;

    lf.lfItalic=0;      lf.lfUnderline=0;

    lf.lfStrikeOut=0;   lf.lfCharSet=ANSI_CHARSET;

    lf.lfOutPrecision=OUT_DEFAULT_PRECIS;

    lf.lfClipPrecision=CLIP_DEFAULT_PRECIS;

    lf.lfQuality=PROOF_QUALITY;

    lf.lfPitchAndFamily=VARIABLE_PITCH|FF_DONTCARE;

    strcpy(lf.lfFaceName,"Courier New");

    hfont=CreateFontIndirect(&lf);  //初始化逻辑字体   

    break;

    case WM_ERASEBKGND:

        hdc=GetDC(hwnd);

        GetClientRect(hwnd,&scrdim);

        SelectObject(hdc,hBlkBrush);

        PatBlt(hdc,0,0,scrdim.right,scrdim.bottom,PATCOPY);//将背景刷黑

        SelectObject(hdc,hfont);

        GetTextExtentPoint32(hdc,str,strlen(str),&size);//得到字符串尺寸

        ReleaseDC(hwnd,hdc);

        X=scrdim.right;

        Y=(scrdim.top+scrdim.bottom)*1/3;//确定字符串显示的位置

        break;

    case WM_TIMER:

         hdc=GetDC(hwnd);

         SelectObject(hdc,hBlkBrush);

         PatBlt(hdc,X,Y,size.cx,size.cy,PATCOPY);

         X-=10; 

         if(X<-size.cx) X=scrdim.right;    

         SetBkColor(hdc,RGB(0,0,0));

         SetTextColor(hdc,RGB(0,255,255));//设置字符串显示的颜色

         SelectObject(hdc,hfont);

         TextOut(hdc,X,Y,str,strlen(str));

         ReleaseDC(hwnd,hdc);

         break;

    case WM_DESTROY:

        KillTimer(hwnd,1);//关闭定时器

        DeleteObject(hfont);

        break;

    default:

    return DefScreenSaverProc(hwnd,message,wParam,lParam);

    }

    return 0;

}

  BOOL WINAPI ScreenSaverConfigureDialog(HWND hdwnd,UINT message,

      WPARAM wParam,LPARAM lParam)

  {

      static HWND hEboxWnd1,hEboxWnd2;

      static HWND udWnd1,udWnd2;

      INITCOMMONCONTROLSEX cc;

      switch(message)

      {

      case WM_INITDIALOG:

          cc.dwSize=sizeof(INITCOMMONCONTROLSEX);

          cc.dwICC=ICC_UPDOWN_CLASS;

          InitCommonControlsEx(&cc);//以下建立或读取注册表中有关信息

          RegCreateKeyEx(HKEY_CURRENT_USER,str_key,

          0,"Screen Saver",0,KEY_ALL_ACCESS,NULL,&hRegKey,&result);

        if(result==REG_CREATED_NEW_KEY)

        {

         delay=200;

         zhi_hao=120;

        RegSetValueEx(hRegKey,"delay",0,REG_DWORD,(LPBYTE)&delay,

          sizeof(DWORD));

        RegSetValueEx(hRegKey,"FontSize",0,REG_DWORD,(LPBYTE)&zhi_hao,

          sizeof(DWORD));

        RegSetValueEx(hRegKey,"message",0,REG_SZ,(LPBYTE)str,strlen(str)+1);

  }

  else

  {  datasize=sizeof(DWORD);

     RegQueryValueEx(hRegKey,"delay",NULL,&datatype,(LPBYTE)&delay,&datasize);

     RegQueryValueEx(hRegKey,"FontSize",NULL,&datatype,(LPBYTE)&zhi_hao,&datasize);

     datasize=MSGSIZE;

     RegQueryValueEx(hRegKey,"message",NULL,&datatype,

         (LPBYTE)&str,&datasize);  

  }

  hEboxWnd1=GetDlgItem(hdwnd,IDD_EB1);//得到编辑框IDD_EB1的句柄

  hEboxWnd2=GetDlgItem(hdwnd,IDD_EB2); //得到编辑框IDD_EB2的句柄

  udWnd1=CreateUpDownControl(WS_CHILD|WS_BORDER|WS_VISIBLE|

      UDS_SETBUDDYINT|UDS_ALIGNRIGHT,

      90,5,20,15,hdwnd,IDD_UPDOWN1,hMainInstance,hEboxWnd1,

      DELAYMAX,1,delay);//建立第一个旋转按钮

  udWnd2=CreateUpDownControl(WS_CHILD|WS_BORDER|WS_VISIBLE|

      UDS_SETBUDDYINT|UDS_ALIGNRIGHT,

      90,25,20,15,hdwnd,IDD_UPDOWN2,hMainInstance,hEboxWnd2,

      FontSizeMax,40,zhi_hao); //建立第二个旋转按钮

  SetDlgItemText(hdwnd,IDD_EB3,str);//在编辑框IDD_EB3中显示字符串

   break;

      case WM_COMMAND:

          switch(LOWORD(wParam))

          {

          case IDOK://将设置好的参数写入注册表中

              delay=GetDlgItemInt(hdwnd,IDD_EB1,NULL,1);

              zhi_hao=GetDlgItemInt(hdwnd,IDD_EB2,NULL,1);

              GetDlgItemText(hdwnd,IDD_EB3,str,MSGSIZE);

              RegSetValueEx(hRegKey,"delay",0,REG_DWORD,

              (LPBYTE)&delay,sizeof(DWORD));

              RegSetValueEx(hRegKey,"FontSize",0,REG_DWORD,

              (LPBYTE)&zhi_hao,sizeof(DWORD));

              RegSetValueEx(hRegKey,"message",0,REG_SZ,

              (LPBYTE)str,strlen(str)+1);

          case IDCANCEL:

              RegCloseKey(hRegKey);

              EndDialog(hdwnd,0);

             break;

          }

       break;

      }

      return 0;

  }

  BOOL WINAPI RegisterDialogClasses(HANDLE hInst)

  {

       return 1;

  }

2、资源文件scr.rc

  #include <windows.h>

  #include <scrnsave.h>

  #include "scr.h"

  ID_APP   ICON   SCRICON.ICO

  STRINGTABLE

  {

   IDS_DESCRIPTION "It's a screen saver program!"

   }

   DLG_SCRNSAVECONFIGURE  DIALOG   20,20,160,90

   CAPTION  "屏幕保护程序选项设置"

   STYLE  DS_MODALFRAME |WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU

   {

    DEFPUSHBUTTON  "确定",IDOK,40,70,30,15,WS_CHILD|WS_VISIBLE|WS_TABSTOP

    PUSHBUTTON   "取消",IDCANCEL,80,70,30,15,WS_CHILD|WS_VISIBLE|WS_TABSTOP

    EDITTEXT     IDD_EB1,55,5,25,12,ES_LEFT|WS_CHILD|WS_VISIBLE|WS_BORDER

    EDITTEXT     IDD_EB2,55,25,25,12,ES_LEFT|WS_CHILD|WS_VISIBLE|WS_BORDER

                 |WS_TABSTOP

    EDITTEXT     IDD_EB3,55,45,70,12,ES_LEFT|WS_CHILD|WS_VISIBLE|WS_BORDER

                 |ES_AUTOHSCROLL|WS_TABSTOP

    LTEXT  "延迟时间:",IDD_TEXT1,10,7,40,12

    LTEXT  "字号大小:",IDD_TEXT2,10,25,40,12

    LTEXT  "显示信息:",IDD_TEXT3,10,45,40,12

  }

 

3、头文件scr.h

#define  IDD_EB1     200

#define  IDD_EB2     201

#define  IDD_EB3     202

#define  IDD_UPDOWN1 203

#define  IDD_UPDOWN2 204

#define  IDD_TEXT1   205

#define  IDD_TEXT2   206

#define  IDD_TEXT3   207

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089