我正在尝试习惯WinApi,并决定为我编程的数独发生器制作GUI。 它应该动态调整到用户选择的窗口大小。 到目前为止,所有内容都是有意义的,但如果在短时间内发送WM_PAINT-msg(例如更改窗口大小),程序就会崩溃。
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
stringstream ss; //not used
RECT rect;
int w;
int h;
HBRUSH coluns=CreateSolidBrush(RGB(50,120,180));
HBRUSH colsel=CreateSolidBrush(RGB(80,150,220));
HBRUSH colmso=CreateSolidBrush(RGB(50,70,190));
switch (message)
{
case WM_SIZE: //
{
GetWindowRect(hwnd,&rect);
menu.wndw=rect.right-rect.left; //menu is a class to store important information
menu.wndh=rect.bottom-rect.top;
h=menu.wndh;
w=menu.wndw;
for(int i=1;i<10;i++)
{
for(int j=1;j<10;j++)
{
menu.feld[i][j].SetSpace((w/4)+((i-1)*(w/20))+i+(2*((i-1)/3)),(h/4)+((j-1)*(h/20))+j+(2*((j-1)/3)),(w/4)+((i)*(w/20))+i+(2*((i-1)/3)),(h/4)+((j)*(h/20))+j+(2*((j-1)/3)));
}
} //feld is a class wich exists in a 10x10 array with the 0s not being used
InvalidateRect(hwnd,NULL, TRUE);
}
break;
case WM_PAINT:
{
RECT re;
w=menu.wndw;
h=menu.wndh;
hdc = BeginPaint(hwnd,&ps);
re.left=(w/4)-4;
re.top=(h/4)-4;
re.right=(w/4)+9*(w/20)+18;
re.bottom=(h/4)+9*(h/20)+18;
FillRect(hdc,&re,CreateSolidBrush(RGB(0,0,0)));
for(int i=1;i<10;i++)
{
for(int j=1;j<10;j++)
{
re=menu.feld[i][j].GetSpace();
if(menu.feld[i][j].GetSelect()==uns)
if(FillRect(hdc,&re,coluns)==0)
MessageBox(hwnd, "fail","fail",0);
if(menu.feld[i][j].GetSelect()==mso)
if(FillRect(hdc,&re,colmso)==0)
MessageBox(hwnd, "fail","fail",0);
if(menu.feld[i][j].GetSelect()==sel)
if(FillRect(hdc,&re,colsel)==0)
MessageBox(hwnd, "fail","fail",0);
}
}
EndPaint(hwnd, &ps);
}
break;
http://www.pic-upload.de/view-22113118/Unbenannt.png.html 这是执行程序的样子。
现在如前所述,如果你用很多小步骤改变windowsize,程序就会崩溃。在调用MW_PAINT消息约10次后,窗口将冻结,其中1个是白色而不是所需的颜色(随机的,每次不同)。 我的假设是我需要释放某种资源,因为mby堆栈会溢出或smth,但我真的不知道我的程序在哪里可以泄漏。
如果有人能帮助我,我将非常感激。
答案 0 :(得分:4)
每次执行窗口过程时,都会创建三个画笔句柄。这些手柄永远不会整理。然后在WM_PAINT
处理程序中,创建一个传递给FillRect
的画笔,因此永远不会销毁它。
因此,每次窗口过程执行时都会泄漏三个句柄(这种情况会发生很多),每次处理WM_PAINT
时都会泄漏一个句柄。简而言之,您的程序就像筛子一样泄漏!
您应该考虑在创建窗口时创建这些画笔,并在窗口被销毁时销毁它们。或者也许在WM_PAINT
处理程序中创建它们,并在完成使用后立即销毁它们。但由于它们具有恒定的颜色,因此最好一次性创建4个刷子,一劳永逸。
答案 1 :(得分:1)
您正在泄露GDI
资源 David Heffernan 成员。
Here是如何在应用程序中正确使用画笔的示例 - 请注意该示例中的WM_COMMAND
处理程序。
如果您不使用库存GDI对象,则必须在使用它们后将其删除。
以下是使用WM_PAINT
处理程序中的红色笔刷填充窗口的简单示例:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPain( hdc, &ps );
HBRUSH hbrRedBrush = CreateSolidBrush( RGB( 255, 0, 0 ) );
RECT r;
GetClientRect( hWnd, &r );
FillRect( hdc, &r, hbrRedBrush );
DeleteObject( hbrRedBrush ); //you must delete GDI object!
EndPaint( hWnd, &ps );
}
return 0L;
在你的情况下,我会制作4个static
画笔并稍微修改我的代码,在WM_CLOSE
处理程序中添加适当的清理。以下是建议的更改:
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
// add static before HBRUSH
static HBRUSH coluns=CreateSolidBrush(RGB(50,120,180));
static HBRUSH colsel=CreateSolidBrush(RGB(80,150,220));
static HBRUSH colmso=CreateSolidBrush(RGB(50,70,190));
static HBRUSH BlackBrush = CreateSolidBrush(RGB(0,0,0));
switch (message)
{
// this is the problematic handler
case WM_PAINT:
{
//the changed part
FillRect( hdc, &re, BlackBrush );
}
break;
case WM_CLOSE:
{
DeleteObject( BlackBrush );
DeleteObject( coluns );
DeleteObject( colsel );
DeleteObject( colmso );
// other clean up code
}
break;
这次您使用了FillRect
API,但下次您可能会将需要的位图和其他内容加载到将HDC
恢复到原始状态强>你完成绘画后。
你这样做:
HBITMAP bmpOld = (HBITMAP)SelectObject( hdc, myBitmap );
// bmpOld stores the original state of the device context
// you do something with myBitmap
// then you return device context into original state
// by selecting the original value, bmpOld, back into device context
SelectObject( hdc, oldBmp );
DeleteObject( myBitmap );
再次注意上面WM_COMMAND
示例中的MSDN
处理程序,看看他们是如何做到的。
Here是指向初学者的精彩Win32
API教程的链接 - 随意使用。
最后,我建议您this tool检测GDI
泄漏。
如果您有其他问题,请发表评论,我会尽快回复。
祝你好运!