外行人自学编程的最大坏处是知其然,不知其所以然,所以自己错了也不知道,不理解也没关系,只要代码跑得起来就不问对错了。CV键不停的用,成果都是自己的。还好本人不从事码农工作,不然就坑大发了。
我最早自学编程,是为了给游戏做辅助,自己做了个登陆接奖励的程序,800个小号上一上午登陆自动取名,领奖,截图,还挺有成就感的。后来只要有必要,经常自己动手做点小小程序,代码基本全靠背,毕竟这玩意用几回就记住了,函数后面的原理啥的完全不懂,也不可能懂,毕竟我是外行人。
做游戏辅助程序最重要就是跟图片打交道。我认为最方便的就是用CreateDIBSection。
前些天又做了一个小程序,需要打开很多图片,结果我照以往的代码,直接敲了上去,最后发现一个问题,每打开一个图片,内存开销就会涨10M,我一直搞不懂为什么,一直尝试释放内存,不成功。后来在网上经高人指点才知道自己的代码错了。
这是我用了十年的代码
R = ReadFile(hFile, &fif, sizeof(BITMAPINFOHEADER), &num, NULL);
GetClientRect(hWnd, &rect);
dataSize = bfh.bfSize - bfh.bfOffBits;
data = (BYTE*)malloc(dataSize);
pbmi.bmiHeader = fif;
width = fif.biWidth;
height = fif.biHeight;
winDC = GetDC(hWnd);
memDC = CreateCompatibleDC(winDC);
hBit = CreateDIBSection(memDC, &pbmi, DIB_RGB_COLORS, (void**)&data, NULL, 0);
R = ReadFile(hFile, data, dataSize, &num, NULL);
SelectObject(memDC, hBit);
我也忘了最早是在哪抄的了,反正我一直认为,放像素数据的内存块是需要预先申请的,申请之后再给CreateDIBSection用,只要内存DC,内存位图对象形成后,再把数据写入内存就可以了,最后删除掉对象就可以了。当年甚至都没有想过要释放内存,那会对内存开销也没啥概念,也正因为如此,我这个错误的程序一用就是十年。
昨天我一直尝试释放内存free(data),只要代码运行到这就异常。我一直猜这个位图对象是系统管理的,所以才不能手动释放,于是不停的尝试删除对象,释放DC,然后再释放内存,但最后都以失败告终。没办法,我还问了一下chargpt,他回答得相当全面,说了各种DC的释放方法,内存DC需要先载入另一个对象,再释放。他教的方法是这样
hOldBit = (HBITMAP) SelectObject(memDC, hBit);
我也照着做了,最后还是失败。(其实他教的是对的,只不过我错的不在这里)
后来我去某论坛问了一下,有大神就教了我,他把代码整体改了一下,瞬间就不那么业余了。
GetClientRect(hWnd, &rect);
winDC = GetDC(hWnd);
memDC = CreateCompatibleDC(winDC);
pbmi.bmiHeader = fif;
width = fif.biWidth;
height = fif.biHeight;
hBit = CreateDIBSection(memDC, &pbmi, DIB_RGB_COLORS, (void**)&data, NULL, 0);
if (!hBit) {
data = NULL;
DeleteDC(memDC); memDC = NULL;
ReleaseDC(hWnd, winDC); winDC = NULL;
CloseHandle(hFile);
return NULL;
}
dataSize = bfh.bfSize - bfh.bfOffBits;
R = (ReadFile(hFile, data, dataSize, &num, NULL) && (num == dataSize));
hOldBit = (HBITMAP) SelectObject(memDC, hBit);
原来根本就不需要申请内存,createdibsedction直 接分配了内存,所以只要删除掉位图对象,释放DC就可以了。需要注意的是,释放内存DC需要用DeleteDC,而不是ReleaseDC。