发现 EasyX 20220901 的新 bug,关于未创建窗口时 SetWorkingImage(0) 的问题

1

问题描述

通常,在对某个 IMAGE 对象绘制时,我们会先保存旧的 WorkingImage,然后在 SetWorkingImage 到待绘制的 IMAGE 对象。

这样,我们就可以在对 IMAGE 对象绘制后,使用 SetWorkingImage 将绘制目标恢复到原先的状态。

这是很常见的做法。但是,如果在没有创建绘图窗口的情况下,上述操作就会出现问题。

触发 bug 的代码

#include <graphics.h>

void DrawOnImage(LPCTSTR lpszFileName)
{
	IMAGE* pOld = GetWorkingImage();
	IMAGE img(40, 40);

	SetWorkingImage(&img);
	circle(20, 20, 10);
	saveimage(lpszFileName, GetWorkingImage());

	SetWorkingImage(pOld);
}

int main()
{
	DrawOnImage(L"1.jpg");		// success
	DrawOnImage(L"2.jpg");		// failure
	DrawOnImage(L"3.jpg");		// failure

	initgraph(640, 480);
	circle(200, 200, 100);		// success
	getmessage(EX_CHAR);
	closegraph();

	return 0;
}

上述代码在创建绘图窗口之前,在三张图片上绘制了相同的圆形,并保存为 1.jpg,2.jpg,3.jpg,然后创建了一个绘图窗口,并画了个圆。

目前,EasyX 的最新版是 20220901。我在 Win10 | VS 2022 | EasyX 20220901 配置下实测,上述代码并不能正常运行。只有第一张图片绘制成功,其余两张绘制失败(什么也没画出来)。

随后,我将 EasyX 替换为 20220610 的版本,上述代码运行成功,三张图片都绘制正常了。

初步推断

可能是由于在创建绘图窗口之前,DrawOnImage 函数首先保存了 WorkingImage 的值(因为没有创建窗口,所以得到的是 nullptr),从而在恢复 WorkingImage 时,错误地调用了 SetWorkingImage(nullptr),但是这个时候其实是没有创建绘图窗口的。

对于这种情况,在 EasyX 20220901 中,可能会导致程序对后续 IMAGE 对象绘制失败。但是如果是在 EasyX 20220610 中,则还是可以正常绘制。

综上,我个人感觉是 EasyX 20220901 中没有处理到未创建绘图窗口时,调用 SetWorkingImage(nullptr) 的特殊情况。

所以,我大胆地推断这是个 bug。如果这不算一个 bug 的话,那么就必须在 DrawOnImage 中判断现在是否已经创建绘图窗口(因为以后也可能在创建绘图窗口后调用这个函数),以此来决定要不要调用 SetWorkingImage(nullptr)。虽然可以通过 GetHWnd() 来判断绘图窗口是否已经创建,但这未免过于繁琐——对于这么一个自定义的绘图函数,判断绘图窗口是否存在似乎不像是它的本职工作。况且,旧版 EasyX 是支持这么写的。

不过,这都是我的一己之见。

ava
huidong

2023-1-15

1

谢谢反馈,的确是个 bug。并且描述信息非常详细,重现代码简洁清晰,必须赞一个。

PS:最新版本 EasyX 已经修复这个问题。

(留意下私信,可以加我领个红包 ^_^)

ava
慢羊羊

2023-1-18

技术讨论社区