简单的WIN32屏保开发制作(可播放视频)

本文不同于VC下使用ScrnSave.lib进行屏保制作的方式,

而是在VS下以其内在原理,从无到有进行一个简单的WIN32屏保开发,

只要你拥有一些简单的WIN32程序编写的经验,便可以很轻松的明白并编写出此类屏保。


首先,要实现一个屏保,我们需要实现三件事。

  • 操作系统自动运行程序
  • 全屏幕的窗口
  • 用户输入即退出
只要实现了这三件事,那么便可以称之为简单意义上的屏保了。


操作系统自动运行程序:

       这很幸运,因为只要将用户程序的后缀名改为.scr, 将其放到正确的系统目录下,便可以成为

真正的屏幕保护程序,在空闲时自动得到操作系统的调用,而不用我们花大量时间编写代码。


全屏幕的窗口:

        这个也很简单,只要我们将窗口创建为全屏显示,那么自然也没有太大问题了。

你可以这样做:

    hwnd = CreateWindow(L"BeyondScrnSaver", NULL,                                             //注意这里初始化HWND_DESKTOP,
            WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 0,   //因为在窗口上播放视频,窗口显示太快会看到先显示背景,所以我先将其大小调整为0
            0, HWND_DESKTOP, NULL, hInstance, NULL);

用户输入即退出:

        只要在消息窗口过程中进行鼠标移动,点击,以及键盘输入事件的处理,便可以实现该退出过程。


好了,讲了这么多,现在我们从实现一个屏幕保护程序的窗口框架开始吧....

/*---------------------------------------------------------------------------------
【Cpp文件】:ScreenMain.cpp          Created by Beyond Ray,2014年4月
(描述):使用天下叁CG《墨龙纪》制作成简单的屏保
-----------------------------------------------------------------------------------*/

//------------------------【头文件】--------------------------------
#include 
#include 								//使用swprintf_s函数所需的头文件
#include "resource.h"							//资源文件(只用于图标)

//------------------------【全局函数声明】--------------------------
LRESULT CALLBACK	WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);			//主窗口过程函数

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	HWND hwndFrameWnd = 0;
	HWND hwnd = 0;
	RECT rect;

	//---------------------------【设计一个窗口类】------------------------------
	WNDCLASSEX wndClass = { 0 };					//用WINDCLASSEX定义一个窗口类,并初始化
	wndClass.cbSize = sizeof(WNDCLASSEX);			//设置结构体的字节数大小
	wndClass.style = CS_HREDRAW | CS_VREDRAW;		//设置窗口的样式
	wndClass.lpfnWndProc = WndProc;					//设置指向窗口过程函数的指针
	wndClass.cbClsExtra = 0;						//窗口类的附加内存,取0就可以了
	wndClass.cbWndExtra = 0;						//窗口的附加内存,依然取0就行了
	wndClass.hInstance = hInstance;					//指定包含窗口过程的程序的实例句柄。
	wndClass.hIcon = (HICON)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));    //本地加载自定义ico图标
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); //指定窗口类的光标句柄。
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  //指定一个白色画刷句柄	
	wndClass.lpszMenuName = NULL;					//用一个以空终止的字符串,指定菜单资源的名字。
	wndClass.lpszClassName = L"BeyondScrnSaver";	//用一个以空终止的字符串,指定窗口类的名字。
	
	//----------------------------【注册一个窗口类】------------------------------
	if (!RegisterClassEx(&wndClass))
		return -1;

	//-----------------------------【创建一个窗口】-------------------------------
	hwnd = CreateWindow(L"BeyondScrnSaver", NULL,					//注意这里初始化HWND_DESKTOP,并且在最初大小为0,
			WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 0, //以防止视频还没播放前看到白屏
			0, HWND_DESKTOP, NULL, hInstance, NULL);
			
	//窗口更新显示
	MoveWindow(hwnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), true);
	ShowWindow(hwnd, nShowCmd);				//调用ShowWindow函数来显示窗口
	UpdateWindow(hwnd);						//对窗口进行更新

	//------------------------------【消息循环过程】-------------------------------
	MSG msg = { 0 };							//定义并初始化msg
	while (GetMessage(&msg, NULL, 0, 0))		//使用while循环,如果消息不是WM_QUIT消息,就继续循环
	{
		TranslateMessage(&msg);			//将虚拟键消息转换为字符消息
		DispatchMessage(&msg);			//分发一个消息给窗口程序。
	}


	//-------------------------------【将窗口类注销】-------------------------------
	UnregisterClass(L"BeyondScrnSaver", wndClass.hInstance);  //程序准备结束,注销窗口类
	return 0;
}

//-----------------------------------【WndProc( )函数】-------------------------------------------
// Desc:窗口过程函数WndProc,对窗口消息进行处理
//------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	switch (message)						//switch语句开始
	{
	case WM_CREATE:
		break;

	case WM_DESTROY:			//窗口销毁消息
		PostQuitMessage(0);			
		break;									

	default:										
		return DefWindowProc(hwnd, message, wParam, lParam);		//调用缺省的窗口过程
	}

	return 0;			//正常退出
}

当我们实现了一个基本的窗口框架之后,我们便要处理“第三件事”,也就是说

让操作系统实现人机交互的自动退出,那么可以在窗口过程函数WndProc中这么实现:

1.在鼠标点击,键盘键入事件发生时,窗口自动退出

(mciSendString(L"close movie", g_buf, sizeof(g_buf), NULL);  是关闭墨龙纪视频,这里先忽略它)

	case WM_LBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_RBUTTONDOWN:
	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
		MoveWindow(hwnd, 0, 0, 0, 0, true);		//关闭窗口速度比视频退出慢,先使其不可见,以防止看到白屏
		PostQuitMessage(0);						// 退出窗口程序
		mciSendString(L"close movie", g_buf, sizeof(g_buf), NULL);	//关闭墨龙纪视频
		break; 	


2.在鼠标光标移动时,窗口自动退出。
#1.先添加全局变量

//------------------------【全局变量】------------------------------
INT			g_nOrigin_X = -1, g_nOrigin_Y = -1;	//鼠标指针起始位置


#2.WM_MOUSEMOVE事件
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)	//判断鼠标移动检测
		{
			MoveWindow(hwnd, 0, 0, 0, 0, true);
			mciSendString(L"close movie", g_buf, sizeof(g_buf), NULL);
			PostQuitMessage(0);
		}
	}
	break;


实现了这些之后,一个什么都没有的屏保框架也就完成了,接下来我们给它添加一部可播放的视频,
这里我用了来自天下叁CG的《墨龙纪》。
#1.先添加全局变量:

TCHAR		g_buf[256];							//接收《墨龙纪》返回信息的缓冲区

#2.然后在CreateWindow和MoveWindow后面添加如下代码:
//播放《墨龙纪》视频(我将视频放在了 F:/天下叁CG/墨龙纪.avi路径当中,注意调整)
	wchar_t open1[100];
	swprintf_s(open1, L"open F:/天下叁CG/墨龙纪.avi type MPEGVideo Alias movie parent %u Style %u notify", hwnd, WS_CHILD);
	mciSendString(open1, g_buf, sizeof(g_buf), NULL);
	mciSendString(TEXT("play movie fullscreen repeat"), g_buf, sizeof(g_buf), NULL);


关于mciSendString函数我在这里不再详解了,具体可以参考百度百科
链接:http://baike.baidu.com/link?url=y2TRxk3x-TfofomrPEbmG4AO_GUbJ-KSK3tHOQS3mffKV2xJFOfVHLtnKOKts95kH9AZQRN-os2ToLgM8gZmjK

好了,实现到这里,按下F5我们可以看到墨龙纪视频成功播放出来了,但是移动鼠标和键入键盘
都没有响应,这是怎么回事?那是因为在消息循环当中,操作系统优先将消息派发到窗口上层的视频
消息处理接口当中去了,那么怎么办呢?我们可以使用SendMessage手动将消息传递到窗口过程
当中去,就像这样:

if (msg.message == WM_MOUSEMOVE || WM_SYSKEYDOWN || WM_KEYDOWN ||
			WM_LBUTTONDOWN || WM_RBUTTONDOWN || WM_MBUTTONDOWN)	//由于系统默认将消息传递给窗口上层的视频,
		{							//而窗口接受不到消息,所以我们手动进行传送。
			SendMessage(hwnd, msg.message, msg.wParam, msg.lParam);
		}


嗯,在按F5来编译执行一遍,这时我们就可以看到很精彩的CG动画墨龙纪了,而且按下键盘,移动鼠标,以及
点击鼠标,都会很快的正常退出,一切都进行的很圆满。


这时我们将Release文件夹(我配置选项卡设为了Release模式)下的exe执行文件后缀名改为.scr,如果是64
位操作系统,将其放置到C:/Windows/SysWOW64路径下,如果是32位操作系统,将其放置到
C:/Windows/System32路径下,然后再打开“屏幕保护设置”,这时我们会发现存在一个问题,
即使我们没有“预览”,它却已经运行了。


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

       方式                                                            命令行参数 

正常(由系统自动执行,全屏幕显示)                       /s

配置(屏幕保护程序选项卡中的设定)                          /c

预览(显示在屏幕保护程序选项卡的小窗口中)       /p


所以,为了让屏幕保护程序能够在小窗口中自动运行,并且可以设置,以及如我们所愿一般的预览,
我们需要在【设计窗口类】和【注册窗口类】之间加入如下代码:

if (__argc > 1)
	{
		if (strstr(__argv[1], "/p"))	//预览小窗口
		{
			if (__argc == 3)
			{
				hwndFrameWnd = (HWND)atoi(__argv[2]);

				GetClientRect(hwndFrameWnd, &rect);

				wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);  //预览窗口的黑色背景刚好协调
				wndClass.lpfnWndProc = SmallWndProc;						   //为窗口类重新指定窗口函数
				//----------------------------【注册一个窗口类】------------------------------
				if (!RegisterClassEx(&wndClass))
					return -1;

				hwnd = CreateWindow(L"BeyondScrnSaver", NULL,
					WS_CHILD | WS_VISIBLE,
					rect.left, rect.top,
					rect.right, rect.bottom,
					hwndFrameWnd, NULL,
					hInstance, NULL);

				//----------------------------【播放《墨龙纪》视频】--------------------------
				//打开墨龙纪视频
				wchar_t open1[100];
				swprintf_s(open1, L"open F:/天下叁CG/墨龙纪.avi type MPEGVideo Alias movie parent %u Style %u notify", hwnd, WS_CHILD);
				mciSendString(open1, g_buf, sizeof(g_buf), NULL);
				//设置窗口大小并播放
				swprintf_s(open1, L"put movie window at 0 0 %d %d", rect.right - rect.left, rect.bottom - rect.top);
				mciSendString(open1, g_buf, sizeof(g_buf), NULL);
				mciSendString(L"play movie repeat", g_buf, sizeof(g_buf), NULL);

				//------------------------------【消息循环过程】-------------------------------
				MSG msg = { 0 };							//定义并初始化msg
				while (GetMessage(&msg, NULL, 0, 0))		//使用while循环,如果消息不是WM_QUIT消息,就继续循环
				{
					TranslateMessage(&msg);			//将虚拟键消息转换为字符消息
					DispatchMessage(&msg);			//分发一个消息给窗口程序。
				}
				return 0;
			}
		}
		else if (strchr(__argv[1], 'c')) //设置选项卡
		{
			MessageBox(NULL, L"This screen saver doesn't have configuration", L"Blank Screen Saver", MB_OK);
			return 0;
		}
	}


在这里,我主要解释下预览小窗口部分的思想,我们先得到预览窗口的窗口句柄,以及尺寸,
然后在创建一个同样大小的子窗口,紧接着我们在该子窗口上用mciSendString打开了一个基于该窗口的墨龙纪视频,
然后在把该视频大小设置成了窗口的大小(视频打开时默认为其本身的尺寸大小),并进行循环播放,
最后我们用了另外一个消息循环过程来响应事件,以致于不会立刻结束视频播放退出线程。
(注意,这里我们在注册窗口类时用了另外一个SmallWndProc 窗口过程,以得到我们希望的事件响应。

下面这里是有关SmalllWndProc窗口过程部分的代码:
//------------------------【全局函数声明】--------------------------
LRESULT CALLBACK SmallWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);		//预览窗口过程函数

//-----------------------------------【SmallWndProc( )函数】-------------------------------------------
// Desc:预览窗口过程函数,对预览窗口消息进行处理
//-----------------------------------------------------------------------------------------------------
LRESULT CALLBACK SmallWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)						//switch语句开始
	{
	case WM_DESTROY:			//窗口销毁消息
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hwnd, message, wParam, lParam);		//调用缺省的窗口过程
	}

	return 0;			//正常退出
}


到此为止,把代码整合在一起,我们就可以得到一个即能在小窗口上预览《墨龙纪》CG,又能实现
空闲时操作系统自动调用的真正意义上的屏保了,只要我们依旧将exe执行文件后缀改成.scr放置到相应的
系统目录下便能实现了。

下面我将所有代码整合在一起发放一遍:

/*---------------------------------------------------------------------------------
【Cpp文件】:ScreenMain.cpp          Created by Beyond Ray,2014年4月
(描述):使用天下叁CG《墨龙纪》制作成简单的屏保
-----------------------------------------------------------------------------------*/


//------------------------【头文件】--------------------------------
#include 
#include 								//使用swprintf_s函数所需的头文件
#include "resource.h"							//资源文件(只用于图标)

//------------------------【全局变量】------------------------------
INT			g_nOrigin_X = -1, g_nOrigin_Y = -1;	//鼠标指针起始位置
TCHAR		g_buf[256];							//接收《墨龙纪》返回信息的缓冲区

//------------------------【全局函数声明】--------------------------
LRESULT CALLBACK	WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);			//主窗口过程函数
LRESULT CALLBACK SmallWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);		//预览窗口过程函数


//-----------------------------------【WinMain( )函数】-----------------------------------------
//	Desc:Windows应用程序的主入口
//----------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	HWND hwndFrameWnd = 0;
	HWND hwnd = 0;
	RECT rect;

	//---------------------------【设计一个窗口类】------------------------------
	WNDCLASSEX wndClass = { 0 };					//用WINDCLASSEX定义一个窗口类,并初始化
	wndClass.cbSize = sizeof(WNDCLASSEX);			//设置结构体的字节数大小
	wndClass.style = CS_HREDRAW | CS_VREDRAW;		//设置窗口的样式
	wndClass.lpfnWndProc = WndProc;					//设置指向窗口过程函数的指针
	wndClass.cbClsExtra = 0;						//窗口类的附加内存,取0就可以了
	wndClass.cbWndExtra = 0;						//窗口的附加内存,依然取0就行了
	wndClass.hInstance = hInstance;					//指定包含窗口过程的程序的实例句柄。
	wndClass.hIcon = (HICON)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));    //本地加载自定义ico图标
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); //指定窗口类的光标句柄。
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  //指定一个白色画刷句柄	
	wndClass.lpszMenuName = NULL;					//用一个以空终止的字符串,指定菜单资源的名字。
	wndClass.lpszClassName = L"BeyondScrnSaver";	//用一个以空终止的字符串,指定窗口类的名字。

	if (__argc > 1)
	{
		if (strstr(__argv[1], "/p"))	//预览小窗口
		{
			if (__argc == 3)
			{
				hwndFrameWnd = (HWND)atoi(__argv[2]);

				GetClientRect(hwndFrameWnd, &rect);

				wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);  //预览窗口的黑色背景刚好协调
				wndClass.lpfnWndProc = SmallWndProc;						   //为窗口类重新指定窗口函数
				//----------------------------【注册一个窗口类】------------------------------
				if (!RegisterClassEx(&wndClass))
					return -1;

				hwnd = CreateWindow(L"BeyondScrnSaver", NULL,
					WS_CHILD | WS_VISIBLE,
					rect.left, rect.top,
					rect.right, rect.bottom,
					hwndFrameWnd, NULL,
					hInstance, NULL);

				//----------------------------【播放《墨龙纪》视频】--------------------------
				//打开墨龙纪视频
				wchar_t open1[100];
				swprintf_s(open1, L"open F:/天下叁CG/墨龙纪.avi type MPEGVideo Alias movie parent %u Style %u notify", hwnd, WS_CHILD);
				mciSendString(open1, g_buf, sizeof(g_buf), NULL);
				//设置窗口大小并播放
				swprintf_s(open1, L"put movie window at 0 0 %d %d", rect.right - rect.left, rect.bottom - rect.top);
				mciSendString(open1, g_buf, sizeof(g_buf), NULL);
				mciSendString(L"play movie repeat", g_buf, sizeof(g_buf), NULL);

				//------------------------------【消息循环过程】-------------------------------
				MSG msg = { 0 };							//定义并初始化msg
				while (GetMessage(&msg, NULL, 0, 0))		//使用while循环,如果消息不是WM_QUIT消息,就继续循环
				{
					TranslateMessage(&msg);			//将虚拟键消息转换为字符消息
					DispatchMessage(&msg);			//分发一个消息给窗口程序。
				}
				return 0;
			}
		}
		else if (strchr(__argv[1], 'c')) //设置选项卡
		{
			MessageBox(NULL, L"This screen saver doesn't have configuration", L"Blank Screen Saver", MB_OK);
			return 0;
		}
	}

	//----------------------------【注册一个窗口类】------------------------------
	if (!RegisterClassEx(&wndClass))
		return -1;

	//-----------------------------【创建一个窗口】-------------------------------
	hwnd = CreateWindow(L"BeyondScrnSaver", NULL,					//注意这里初始化HWND_DESKTOP,并且在最初大小为0,
			WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 0, //以防止视频还没播放前看到白屏
			0, HWND_DESKTOP, NULL, hInstance, NULL);

	//播放《墨龙纪》视频(我将视频放在了 F:/天下叁CG/墨龙纪.avi路径当中,注意调整)
	wchar_t open1[100];
	swprintf_s(open1, L"open F:/天下叁CG/墨龙纪.avi type MPEGVideo Alias movie parent %u Style %u notify", hwnd, WS_CHILD);
	mciSendString(open1, g_buf, sizeof(g_buf), NULL);
	mciSendString(TEXT("play movie fullscreen repeat"), g_buf, sizeof(g_buf), NULL);
	
	//视频播放出来了,可以把窗口显示出来了
	MoveWindow(hwnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), true);
	ShowWindow(hwnd, nShowCmd);				//调用ShowWindow函数来显示窗口
	UpdateWindow(hwnd);						//对窗口进行更新

	//------------------------------【消息循环过程】-------------------------------
	MSG msg = { 0 };							//定义并初始化msg
	while (GetMessage(&msg, NULL, 0, 0))		//使用while循环,如果消息不是WM_QUIT消息,就继续循环
	{
		TranslateMessage(&msg);			//将虚拟键消息转换为字符消息
		DispatchMessage(&msg);			//分发一个消息给窗口程序。

		if (msg.message == WM_MOUSEMOVE || WM_SYSKEYDOWN || WM_KEYDOWN ||
			WM_LBUTTONDOWN || WM_RBUTTONDOWN || WM_MBUTTONDOWN)	//由于系统默认将消息传递给窗口上层的视频,
		{														//而窗口接受不到消息,所以我们手动进行传送。
			SendMessage(hwnd, msg.message, msg.wParam, msg.lParam);
		}
	}


	//-------------------------------【将窗口类注销】-------------------------------
	UnregisterClass(L"BeyondScrnSaver", wndClass.hInstance);  //程序准备结束,注销窗口类
	return 0;
}

//-----------------------------------【WndProc( )函数】-------------------------------------------
// Desc:窗口过程函数WndProc,对窗口消息进行处理
//------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	switch (message)						//switch语句开始
	{
	case WM_CREATE:
		ShowCursor(false);
		break;

	case WM_LBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_RBUTTONDOWN:
	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
		MoveWindow(hwnd, 0, 0, 0, 0, true);		//关闭窗口速度比视频退出慢,先使其不可见,以防止看到白屏
		PostQuitMessage(0);						// 退出窗口程序
		mciSendString(L"close movie", g_buf, sizeof(g_buf), NULL);	//关闭墨龙纪视频
		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)	//判断鼠标移动检测
		{
			MoveWindow(hwnd, 0, 0, 0, 0, true);
			mciSendString(L"close movie", g_buf, sizeof(g_buf), NULL);
			PostQuitMessage(0);
		}
	}
		break;

	case WM_DESTROY:			//窗口销毁消息
		PostQuitMessage(0);			
		break;									

	default:										
		return DefWindowProc(hwnd, message, wParam, lParam);		//调用缺省的窗口过程
	}

	return 0;			//正常退出
}

//-----------------------------------【SmallWndProc( )函数】-------------------------------------------
// Desc:预览窗口过程函数,对预览窗口消息进行处理
//-----------------------------------------------------------------------------------------------------
LRESULT CALLBACK SmallWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)						//switch语句开始
	{
	case WM_DESTROY:			//窗口销毁消息
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hwnd, message, wParam, lParam);		//调用缺省的窗口过程
	}

	return 0;			//正常退出
}


最后再来一张《墨龙纪》精彩CG的截图:
简单的WIN32屏保开发制作(可播放视频)_第1张图片

怎么样,CG的动画效果还不错吧!


为了让读者能够更好的理解代码的调用方式,我将资源上传到CSDN上了,有需要的童鞋可以下载。
(项目使用VS2013编写,编译器版本不够就直接复制代码吧...)

BeyondScreenSaver项目传送门:http://download.csdn.net/detail/u013025310/7202247
天下叁《墨龙纪》CG资源传送门:http://pan.baidu.com/s/1kTiaP1P





你可能感兴趣的:(Windows编程)