采用VC++实现的屏幕保护程序(Windows SDK方式)


作者:万立中    时间:2011-04-7                 转载:请注明www.wanlizhong.com

        本文以VC++6.0为开发环境,采用Windows SDK方式实现一个实际可用的小图片更换屏保程序。程序中使用了20张微软Bing背景图片,每张图片的大小为335×179,当然你也可以选择自己更感兴趣的图片。如果需要本程序的图片资源,可以点击这里下载

        由于采用Windows SDK方式进行代码的编写,主窗口的生成、显示及窗口消息处理需要由自己编写代码来完成。作为屏幕保护程序,该主窗口必须全屏幕方式显示,而且窗口需要每隔一段时间自动更换画面,这个工作可以采用定时器来完成(关于主窗口的生成及显示以及定时器的使用,可以参见本站的《VC++定时器的使用(Windows SDK方式)》一文)。另外,屏幕保护程序的退出方式也不同于一般程序,典型的处理方式及时按下键盘上的任意键或移动鼠标。为此,需要专门处理WM_MOUSEMOVE消息以及WM_KEYDOWN消息。


       下面简单阐述一下整个的实现过程:


1. 首先在VC++6.0中创建一个空的Win32 Application,工程名自定义;


2. 然后为工程添加ImgSaver.h、ImgSaver.cpp以及SaverApp.cpp三个文件,其中SaverApp.cpp文件中实现主窗口的生成、显示及窗口消息处理,ImgSaver.h和ImgSaver.cpp文件用来声明和定义一个简单的CImgSaver图像处理类,实现图片资源的加载、绘制;


3. 为了使程序能够独立运行,所有的图片要以资源的形式添加到工程中,并且编译到exe文件中。当图片加入到工程时,需要保持这些图片资源的标识号是连续的,最重要的是要记住第一个图片资源的标识号,加载图片资源是就可以以此类推了;


4. 在SaverApp.cpp文件的主窗口回调函数中,需要处理的消息及说明如下:


1) WM_CREATE消息:初始化CImgSaver对象;
2) WM_TIMER消息:处理定时任务,即画面更新;
3) WM_PAINT消息:处理画面绘制,其中要实现双缓冲绘图,避免屏幕闪烁;
4) WM_MOUSEMOVE消息:判断鼠标位置,处理是否退出程序;
5) WM_KEYDOWN消息:判断是否按下键盘,处理是否退出程序;
6) WM_DESTROY:程序销毁处理。

 

5. 代码完成并通过编译后,将.exe扩展名修改为.scr,拷贝至Windows目录的System32目录中,然后在系统的屏幕保护程序的选项中就可以看到你的程序,选择后就可以正式运行了。

 

以下是本程序的具体实现代码:

 


//===================================================
//ImgSaver.h文件
//===================================================
#pragma once

#include <windows.h>
#include <time.h>
#include <iostream>//srand, rand
using namespace std;

class CImgSaver
{
private:
 int update_speed;
 int total_num;
 
 HBITMAP* hBitmap;
 HWND h_wnd;

public:
 CImgSaver(HWND hwnd, int Speed, int Num);
 ~CImgSaver();
 HBITMAP LoadSrcBmp(WORD srcID);
 PaintImage(HDC hdc);
};


//===================================================
//ImgSaver.cpp文件
//===================================================
#include "ImgSaver.h"
#include "resource.h"

CImgSaver::CImgSaver(HWND hwnd, int Speed, int Num)
{
 h_wnd = hwnd;
 update_speed = Speed;
 total_num = Num;

 hBitmap = new HBITMAP[Num];
 for(int i=0; i<Num; i++)
 {
  int N = rand()%Num;
  N = N + 1;
  hBitmap[i] = LoadSrcBmp((120+N));//(120+N)为资源标号
 }
 //设置定时器
 SetTimer(h_wnd, 1, Speed, (TIMERPROC)NULL);

}

CImgSaver::~CImgSaver()
{
 delete[] hBitmap;

}

HBITMAP CImgSaver::LoadSrcBmp(WORD srcID)
{
 HBITMAP hBmp =
       (HBITMAP)LoadImage(GetModuleHandle(0),
                     MAKEINTRESOURCE(srcID),
         IMAGE_BITMAP, 0, 0,
         LR_CREATEDIBSECTION);
 if (!hBmp) return NULL;
 return hBmp;
}
 
 
CImgSaver::PaintImage(HDC hdc)
{
 HPEN linePen = CreatePen(PS_SOLID, 2, RGB(255, 255, 0));
 SelectObject(hdc, linePen);
 SelectObject(hdc,  GetStockObject(NULL_BRUSH));
 RECT WinRect;
 GetClientRect(h_wnd, &WinRect);
 int Col = WinRect.right/335;
 int Row = WinRect.bottom/179;
 int num;
 for(int i=0; i<Col+1; i++)
 {
  for(int k=0; k<Row+1; k++)
  {
   RECT CellRect;
   CellRect.left = i*335;
   CellRect.top = k*179;
   CellRect.bottom = CellRect.top+179;
   CellRect.right = CellRect.left+335;
   num = rand()%20;

   HDC FrameDC = CreateCompatibleDC(hdc);
   HBITMAP hOldBitmap =
                 (HBITMAP)SelectObject(FrameDC, hBitmap[num]);
   StretchBlt(hdc, i*335, k*179, 335, 179,
                     FrameDC, 0, 0, 335, 179, SRCCOPY);
   Rectangle(hdc, CellRect.left, CellRect.top,
                    CellRect.right, CellRect.bottom);

   SelectObject(FrameDC, hOldBitmap);
   DeleteDC(FrameDC);
  }
 }
 DeleteObject(linePen);
}


//===================================================
//SaverApp.cpp文件
//===================================================
#include <windows.h>
#include "ImgSaver.h"
 
//声明回调函数
LONG CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM);

CImgSaver* iSaver; //声明CImgSaver类对象的指针
POINT mXY;     //记录鼠标的位置

//========================================================
//WinMain函数
//========================================================
int APIENTRY WinMain(HINSTANCE hInstance,
      HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine,
      int nCmdShow)
{
 MSG msg;
 HWND hWnd;
 WNDCLASSEX wnd;
 wnd.cbSize            = sizeof(WNDCLASSEX);
 wnd.style             = CS_HREDRAW | CS_VREDRAW;
 wnd.lpfnWndProc      = (WNDPROC)MyWndProc;
 wnd.cbClsExtra        = 0;
 wnd.cbWndExtra       = 0;
 wnd.hInstance         = hInstance;
 wnd.hIcon             = NULL;
 wnd.hCursor           = LoadCursor(NULL, IDC_ARROW);
 wnd.hbrBackground     = (HBRUSH)(COLOR_WINDOW+1);
 wnd.lpszMenuName      = NULL;
 wnd.lpszClassName     = "ImageSaver";
 wnd.hIconSm           = NULL;

 RegisterClassEx(&wnd);

 hWnd = CreateWindow( "ImageSaver", "ImageSaver",
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, 800, 600,
      NULL, NULL, hInstance, NULL);

 //==========================================================
 //全屏幕显示
 HWND hDesktop;  
 RECT rc; 
 hDesktop = GetDesktopWindow();
 GetWindowRect(hDesktop, &rc);
 SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_WINDOWEDGE);
 SetWindowLong(hWnd, GWL_STYLE, WS_BORDER);
 SetWindowPos(hWnd, HWND_TOP, 0, 0, rc.right, rc.bottom, SWP_SHOWWINDOW);
 //==========================================================
 
 if (!hWnd) return FALSE;

 ShowWindow(hWnd, nCmdShow);
 UpdateWindow(hWnd);

 while (GetMessage(&msg, NULL, 0, 0))
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 return msg.wParam;
}
 
//========================================================
//回调函数
//========================================================
LONG CALLBACK MyWndProc (HWND hWnd, UINT message,
       WPARAM wParam, LPARAM lParam)
{
 HDC hdc, memDC;
 RECT winRect;
 GetClientRect(hWnd, &winRect);
 HBITMAP memBmp;
 HBRUSH brush;

 switch (message) {
  case WM_CREATE:
   iSaver = new CImgSaver(hWnd, 1000, 20);
   return 0;

  case WM_TIMER:
   //调用WM_PAINT重绘, 不擦除背景 
   InvalidateRect(hWnd, &winRect, FALSE);
   return 0;
   
  case WM_PAINT:
   PAINTSTRUCT ps;
   hdc = BeginPaint(hWnd, &ps);
   
   memDC = CreateCompatibleDC(hdc);
   memBmp = CreateCompatibleBitmap(hdc, winRect.right, winRect.bottom);
   SelectObject(memDC, memBmp);
   brush = CreateSolidBrush(RGB(255, 255, 255));
   FillRect(memDC, &winRect, brush);

   iSaver->PaintImage(memDC);

   BitBlt(hdc, 0, 0, winRect.right, winRect.bottom, memDC, 0, 0, SRCCOPY);
   DeleteDC(memDC);
   DeleteObject(memBmp);
   EndPaint(hWnd,&ps);
   
   return 0;
  
  case WM_MOUSEMOVE:

   if(mXY.x == 0 && mXY.y == 0)
   {
    //记录窗口创建时的鼠标位置
    mXY.x = LOWORD(lParam);
    mXY.y = HIWORD(lParam);
   }

   if(mXY.x != LOWORD(lParam) && mXY.y != HIWORD(lParam))
   {
    KillTimer(hWnd, 1);
    PostQuitMessage(0); 
   }

   return 0;

  case WM_KEYDOWN:
   KillTimer(hWnd, 1);
   PostQuitMessage(0); 
   return 0;

  case WM_DESTROY:
   KillTimer(hWnd, 1);
   PostQuitMessage(0);
   return 0;
 }
 return DefWindowProc(hWnd, message, wParam, lParam);
}


www.pdf24.org    发送文章为PDF   

采用VC++实现的屏幕保护程序(Windows SDK方式)》上有4条评论

  1. 上下翻半天都没找到用来记录鼠标位置坐标的 “mXY” 变量 的初始化代码,
    难道POINT定义实例对象会自动初始化“x”,“y”成员为0值吗?但是翻一下手册,找到定义POINT结构的代码,却也没发现有这样的初始化为0的代码。。
    老师..,这是何故?
    呃..还有一个就是把资源添加到工程中,以图片ID形式调用,好像会造成图片色度的下降,因为工程好像只支持256色的图片,那么还有其它方法,使图片在质量不被损坏的情况,依然能被编译到程序中吗??

    • POINT结构体是两个LONG型值成员, 如果没有赋值, 系统默认赋0; 图片资源的色度不会下降, 引入图片时出现提示的意思是多于256色的图片不能在VC的位图编辑器中直接进行编辑而已, 编译后图片的色深并没有改变, 这个你看屏幕的图片就知道了, 如果是256色的话, 很多像素应该是看不到的, 现在看到的效果显然是真彩的

发表评论