YangW

无为,无我,无欲,居下,清虚,自然

将 mp3 以资源形式嵌入 exe 中使用

本文讲解怎样将 mp3 等音乐资源以资源形式嵌入 exe 文件中,并通过 mciSendString 调用。嵌入 mp3 和嵌入图片略有不同,将图片嵌入到 exe 中,以及访问嵌入 exe 中的图片,请参考:http://www.easyx.cn/skills/View.aspx?id=6

【一、以资源文件形式嵌入 exe】

关于“资源文件”的介绍和“将 mp3 以资源形式嵌入 exe 文件中”的步骤,请仿照 http://www.easyx.cn/skills/View.aspx?id=6。

【二、播放资源文件中的 mp3】

1. 思路

查看 MSDN 中关于 mciSendString 的使用,发现并不支持直接读取资源文件中的媒体文件,也不支持读取内存中的媒体文件。因此,我们需要提取资源

文件中的 mp3 为成临时文件,然后调用 mciSendString 播放,播放结束后再删掉这个临时文件。

2. 提取资源文件中的为临时文件

...

关于编程中“绝对路径”和“相对路径”的使用

加载图片、音乐等各种文件的时候,都要指定文件路径。通常,可以用绝对路径和相对路径两种方式来指定文件。

先解释一下概念:

  • 绝对路径,就是从盘符开始的路径,例如:“c:\windows\system32\mfc42.dll”。
  • 相对路径,就是从当前路径开始的路径,例如,当前路径是“c:\windows”,那么指定前面范例的文件,可以直接写“system32\mfc42.dll”。
    注意,路径分隔符“\”在 c 语言里面是转义字符,所以表达路径分隔符需要用“\\”。

从功能上讲:

  • 访问每台电脑上路径都固定不变的文件,需要用绝对路径,例如访问 c:\boot.ini。
  • 如果程序所在路径不固定,访问的文件和程序放在一起,就要用相对路径。例如和程序放在一起的图片文件。

在 VC6 的项目中的使用范例:

...

通过程序设置鼠标的样式

在编写程序中(尤其是游戏),有时候需要使用个性的鼠标样式,本文就讲解怎样实现该功能。

实现这个功能需要两步:

  1. 加载鼠标样式,并获取其句柄(HCURSOR);
  2. 设置窗口类的鼠标样式为第一步获取到的句柄。

下面详细解释一下这两步:

一、获取鼠标样式的句柄

使用 API 函数 LoadCursor 实现加载鼠标样式。该函数可以读取系统默认的样式,也可以加载资源形式的 .cur 鼠标样式图片,还可以通过 API 函数 LoadImage 加载文件形式的鼠标样式图片。

涉及到的函数原型如下:

HCURSOR LoadCursor(HINSTANCE hInstance, LPCTSTR lpCursorName);
HMODULE GetModuleHandle(LPCTSTR lpModuleName);
HANDLE LoadImage(HINSTANCE hinst, LPCTSTR l
...

在不创建绘图窗口的前提下,直接生成图片文件

通常我们使用 initgraph 创建绘图窗口,然后在里面绘图。

除此之外,我们还可以直接在 IMAGE 对象中绘图,这样就可以实现在不创建绘图窗口的前提下,直接生成图片文件。

为此,需要使用两条命令:

1. SetWorkingImage
该命令用于设定绘图目标。当设置为 IMAGE 对象时,之后所有的绘图操作都会针对该 IMAGE 对象。

2. saveimage
该命令用于保存图片。

实际上并不复杂,请看下面例子:

#include <graphics.h>
#include <stdio.h>
#include <conio.h>

void main()
{
	// 创建一个 300 x 300 的 IMAGE 对象
	IMAGE img(300, 300);
	// 设定 img 为绘图操作的目标
	SetWorkingImage(&img);

	// 执行若干绘

...

精确延时的实现

大家平时写练习程序,包括网站上的范例程序,很多延时都直接用的 Sleep() 实现。这个延时有个缺点,那就是无法统计代码执行的时间。请看下图:

由图可以看到,使用 API 函数 Sleep() 的问题,就是会忽略掉程序的执行时间。很多时候,程序的执行时间是不固定的,所以这就导致使用 Sleep 的延时并不精确,即便 Sleep 使用相同的延时,也可能造成不同电脑上执行速度不同的结果。

图中,理想的延时函数会将程序的执行时间部分考虑进去,这样就可以实现很均匀的延时。下面讨论实现方法。

本次延时要从上次的延时结束开始计算,就必须要记录每次延时执行的具体时刻,而不仅仅是一个时间长度。所以,可以简单的使用 clock() 函数实现,代码如下:

// 精确延时函数(可以精确到 1ms,精度 ±1ms)
// by yangw80<yw80@qq.com>, 2011-5-4
void HpSleep(int
...

快速画点的原理简述,以及写一个自己的快速画点函数

EasyX 自带的 putpixel 函数源自 Windows GDI 函数 SetPixel,由于要考虑裁剪区、缩放、原点坐标、坐标方向等等诸多因素,所以性能很低,在一些只要求速度的场合很不实用。这篇文章就教你写一个自己的画点函数。

总的思想,是通过直接显存操作来避免系统做不需要的运算。

在 EasyX 绘图窗口的显存中,每个点占用 4 个字节,用 DWORD 指针指向显存就可以像一维数组一样访问了。然后就是将二维坐标 (x, y) 映射到一维数组中,很简单,y * 640 + x 就是。另外需要注意的是,显存中颜色的保存和 COLORREF 相比,蓝色和红色是相反的,需要用 BGR 宏转换一下(BGR 宏执行两次就会还原为原值)。

然后,我们整理出画点和读点的函数:
(记得要获取显存指针并保存为全局变量)

DWORD* g_pBuf;

// 在 main 函数中
g_pBuf = GetImageBuffer();

void fast_putpixe

...

为什么没有 setviewport() 函数?用什么替代?

由于 windows 下的 viewport 概念和过去有了很大的区别,为了避免大家混淆,EasyX 从 2011-2-24 起取消了这个函数。

下面解释一下怎样用其他函数替代 setviewport 的功能。

先说说过去的 setviewport() 的功能:

  • 设置矩形区域
  • 将矩形区域左上角设置为原点坐标
  • 可以选择是否裁剪

对于设置裁剪,可以先定义一个区域,然后将该区域设置为裁剪区。区域的概念不仅局限于矩形,在 Windows GDI 函数中有很多定义区域的语句。下面代码定义一个矩形的区域,并设置为裁剪区:

 HRGN rgn = CreateRectRgn(100, 100, 200, 200);	// 定义矩形区域
 setcliprgn(rgn);			// 设置区域 rgn 为裁剪区
 DeleteObject(rgn);			// 不再使用 rgn,清理 rgn 占用的系统资源
...

通过直接操作显存实现高速绘图和特殊效果(如逐渐变亮)

[开场白]

EasyX 从 2011-2-24 开始,支持了直接操作显存的功能。当然,这个显存并不是通常所说的显卡上的显存,而是用来显示窗口的内存,以及用来保存 IMAGE 对象的内存。为了有别于普通的内存,暂且叫这部分为显存吧。

传统的显存概念这里就不介绍了,这里只说一下在 EasyX 中怎么利用这个“显存”。

比如画点,传统的画点函数要考虑很多因素,比如坐标系、缩放、裁剪区等等,所以性能要差。要实现高速绘图,就需要一些更直接的方法,这就是 EasyX 实现直接操作显存功能的目的。

[理论知识]

在 EasyX 中,每个点用 4 个字节表示。对于 640 x 480 的绘图窗口,显存的大小为 640 x 480 x 4 = 307,200 x 4 = 1,228,800 字节。
一个 DWORD 类型正好四个字节,如果是 DWORD 类型的指针指向显存,那么用数组的形式,数组的下标范围是 0~307,199。

关于颜色有点需要注意的地方。平时我们用 COLORR

...

同时检测多个按键和平滑按键处理

getch() 函数,用于返回用户输入的字符。当连续按键时,该函数返回第一个字符和第二个字符之间,默认有 0.5 秒的延时,并且之后的连续字符,默认是每秒钟 15 次输入。这两个数值可以在控制面板中设置。

如果需要平滑的按键输入,或者同时按下多个按键,就不能用 getch() 了,需要使用另一个 Windows API 函数:GetAsyncKeyState()。该函数原型如下:

SHORT GetAsyncKeyState(
	int vKey		// virtual-key code
);

vKey 是要检测的按键的虚拟键码,常用的如 VK_UP、VK_DOWN 等,分别表示方向键的上、下等。需要注意:对于 26 个字母的键码,可以直接写 'A'、'B'……,而不要写 VK_A、VK_B。数字键也是,请直接写 '0'、'1'……。全部的 256 种虚拟键码,请参考 MSDN 中的 Vi

...