您的位置:首页 > 其它

画图时 内存不停 增长 的解决 CreateCompatibleDC(NULL) 创建失败

2013-12-31 12:56 661 查看
今天做贪食蛇的时候,当吃了几个食物的时候,系统报错,我是在group上画图,蛇头,蛇尾,蛇身,三张位图。

CreateCompatibleDC(NULL) 创建失败,网上查了原因,应该是内存不足引起的,查看任务管理器,果然发现内存一直增长。

经过排查原因发现是dc没有释放。

HDC memDc=CreateCompatibleDC(NULL);//这种的必须要释放 DeleteDC(memDc);//必须释放,要不占内存

但是 CDC sourceDC, destDC;

sourceDC.CreateCompatibleDC(NULL);

destDC.CreateCompatibleDC(NULL);

这种的就不用释放,内存不会增加,个人推测这种是包装过的类,应该是退出函数时,调用析构函数进行释放了。不需要显式释放。

类似的

CWnd *cw=GetDlgItem(IDC_GROUP_MAIN);

HDC hdc=cw->GetDC()->GetSafeHdc();

这种通过 HDC来接受的就需要 显式的调用释放函数 DeleteDC(hdc); cdc应该就不用

其中误解了很多地方占用内存没释放,事后发现其实没有,误解的地方:

cbitmap不用释放内存 和LoadBitmap 没有关系 和bitmap也没关系,不用手动释放

和还原原始设备也没关系 SelectObject(memDc,bitold);

和CArray<CPoint,CPoint&> arr_points; 没关系,他会自动释放,也不用removeall

另外。

个人觉得,这个是立刻释放内存的做法,这个应该不算内存泄露,因为debug的时候没有内存泄露的提示,而且,最小化后,再最大化,内存减了很多。

总结就是:指针和原始类需要手动释放内存,其他的不需要。

相关源代码如下:

// SnakeView.cpp : implementation of the CSnakeView class
//

#include "stdafx.h"
#include "Snake.h"

#include "SnakeDoc.h"
#include "SnakeView.h"
#include "GAMESET.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define  TimerMain 1
int GetRand(double MAX,double MIN);

HBITMAP GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack);
/////////////////////////////////////////////////////////////////////////////
// CSnakeView

IMPLEMENT_DYNCREATE(CSnakeView, CFormView)

BEGIN_MESSAGE_MAP(CSnakeView, CFormView)
//{{AFX_MSG_MAP(CSnakeView)
ON_WM_KEYDOWN()
ON_WM_TIMER()
ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
ON_WM_SHOWWINDOW()
ON_COMMAND(IDM_GAME_SET, OnGameSet)
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSnakeView construction/destruction

CSnakeView::CSnakeView():CFormView(CSnakeView::IDD),
m_iDircFlag(3),m_changeTail(FALSE),m_iTailDegree(0),
m_pFood(CPoint(0,0)),iRandomSeed(0),i_Speed(0)//默认是向右
{
// TODO: add construction code here

}

CSnakeView::~CSnakeView()
{
}

BOOL CSnakeView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
//  the CREATESTRUCT cs

return CFormView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CSnakeView drawing

void CSnakeView::OnDraw(CDC* pDC)
{

CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here

int size=m_snake.m_points.GetSize();

for (int i=0;i<size;i++)
{
CBitmap bit;
//HBITMAP bitold;
HBITMAP hbitmap;
if (i==0||i==size-1)//表示是头或者尾巴
{
if (i==0)
{
bit.LoadBitmap(IDB_SHead);//头
int degree;
switch (m_iDircFlag)
{
case 0:
degree=90;
break;
case 1:
degree=-90;
break;
case 2:
degree=180;
break;
case 3:
degree=0;
break;
}
hbitmap=(HBITMAP)GetRotatedBitmapNT(bit,degree*3.14159265359/180,pDC->GetBkColor());//旋转图片
bit.Detach();
bit.Attach(hbitmap);
}
else
{
bit.LoadBitmap(IDB_STail);//尾巴
if (m_changeTail)
{
switch (m_iDircFlag)
{
case 0:
m_iTailDegree=90;
break;
case 1:
m_iTailDegree=-90;
break;
case 2:
m_iTailDegree=180;
break;
case 3:
m_iTailDegree=0;
break;
}
m_changeTail=FALSE;
}

hbitmap=(HBITMAP)GetRotatedBitmapNT(bit,m_iTailDegree*3.14159265359/180,pDC->GetBkColor());//旋转图片
bit.Detach();
bit.Attach(hbitmap);

}
}
else
{
bit.LoadBitmap(IDB_SBody);
}

CWnd *cw=GetDlgItem(IDC_GROUP_MAIN);
HDC hdc=cw->GetDC()->GetSafeHdc();

HDC memDc=CreateCompatibleDC(NULL);
(HBITMAP)SelectObject(memDc,bit);

BITMAP bm;
bit.GetBitmap(&bm);
CPoint cp=m_snake.m_points[i];

BitBlt(hdc,cp.x,cp.y+8,bm.bmWidth,bm.bmHeight,memDc,0,0,SRCCOPY);

DeleteDC(memDc);//必须释放,要不占内存
DeleteDC(hdc);//必须释放,要不占内存
}
DrawFoodPoint();//画食物点
}

/////////////////////////////////////////////////////////////////////////////
// CSnakeView printing

BOOL CSnakeView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}

void CSnakeView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}

void CSnakeView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CSnakeView diagnostics

#ifdef _DEBUG
void CSnakeView::AssertValid() const
{
CFormView::AssertValid();
}

void CSnakeView::Dump(CDumpContext& dc) const
{
CFormView::Dump(dc);
}

CSnakeDoc* CSnakeView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSnakeDoc)));
return (CSnakeDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSnakeView message handlers

void CSnakeView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default

CFormView::OnKeyDown(nChar, nRepCnt, nFlags);
}

//蛇移动事件
void CSnakeView::Move()
{
int size=m_snake.m_points.GetSize();
CArray<CPoint,CPoint&> arr_points;//复制一个临时的数组
arr_points.Copy(m_snake.m_points);
//思路:移动时,除了第一个坐标根据上下左右的不同,重新赋值外,其他的坐标复制他们前面一个坐标的值。
CPoint origTail=m_snake.m_points[size-2];

for (int i=1;i<size;i++)
{
m_snake.m_points[i]=arr_points[i-1];
}

//获取group范围 判断蛇的位置是否超出范围,如果是的话,则提示失败,重新开始
CWnd *cGroupWnd=GetDlgItem(IDC_GROUP_MAIN);
RECT groupRect;
cGroupWnd->GetClientRect(&groupRect);
BOOL blIsOut=FALSE;
switch (m_iDircFlag)
{
case 0://上
m_snake.m_points[0].y-=16;
if (m_snake.m_points[0].y<groupRect.top)//超出范围
{
blIsOut=TRUE;
break;
}
if (origTail.y!=m_snake.m_points[size-2].y)//判断倒数第二个的x,y是否变化,来决定尾巴图片是否旋转
{
m_changeTail=TRUE;
}
break;
case 1://下
m_snake.m_points[0].y+=16;
if (m_snake.m_points[0].y+16>groupRect.bottom)//超出范围
{
blIsOut=TRUE;
break;
}
if (origTail.y!=m_snake.m_points[size-2].y)
{
m_changeTail=TRUE;
}
break;
case 2://左
m_snake.m_points[0].x-=16;
if (m_snake.m_points[0].x<groupRect.left)//超出范围
{
blIsOut=TRUE;
break;
}
if (origTail.x!=m_snake.m_points[size-2].x)
{
m_changeTail=TRUE;
}
break;
case 3://右
m_snake.m_points[0].x+=16;
if (m_snake.m_points[0].x+16>groupRect.right)//超出范围
{
blIsOut=TRUE;
break;
}
if (origTail.x!=m_snake.m_points[size-2].x)
{
m_changeTail=TRUE;
}
break;
}

if (blIsOut)
{
m_snake.Initialize();//重新初始化
m_iDircFlag=3;//方向初始化
m_changeTail=FALSE;//尾巴是否改变初始化
m_iTailDegree=0;//尾巴角度初始化
KillTimer(TimerMain);
MessageBox("失败!");
}

//吃东西,如果头坐标和食物坐标相等,追加一个坐标
if (m_snake.m_points[0].x==m_pFood.x&&m_snake.m_points[0].y+8==m_pFood.y)
{
m_snake.m_points.Add(arr_points[size-1]);
CString cs;
cs.Format("%d",m_snake.m_points.GetSize());
SetDlgItemText(IDC_SNAKELEN,cs);
GenerateFoodPoint();//生成食物点
}

//重绘客户区
RECT temprect(groupRect);
temprect.right+=32;
temprect.bottom+=32;
InvalidateRect(&temprect);
}

// GetRotatedBitmapNT - Create a new bitmap with rotated image
// Returns - Returns new bitmap with rotated image
// hBitmap - Bitmap to rotate
// radians - Angle of rotation in radians
// clrBack - Color of pixels in the resulting bitmap that do
// not get covered by source pixels
HBITMAP GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack )
{
// Create a memory DC compatible with the display
CDC sourceDC, destDC;
sourceDC.CreateCompatibleDC(NULL);
destDC.CreateCompatibleDC(NULL);
// Get logical coordinates
BITMAP bm;
GetObject( hBitmap, sizeof( bm ), &bm );
float cosine = (float)cos(radians);
float sine = (float)sin(radians);
// Compute dimensions of the resulting bitmap
// First get the coordinates of the 3 corners other than origin
int x1 = (int)(bm.bmHeight * sine);
int y1 = (int)(bm.bmHeight * cosine);
int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
int x3 = (int)(bm.bmWidth * cosine);
int y3 = (int)(-bm.bmWidth * sine);
int minx = min(0,min(x1, min(x2,x3)));
int miny = min(0,min(y1, min(y2,y3)));
int maxx = max(0,max(x1, max(x2,x3)));
int maxy = max(0,max(y1, max(y2,y3)));
int w = maxx - minx;
int h = maxy - miny;
// Create a bitmap to hold the result
HBITMAP hbmResult=::CreateCompatibleBitmap(CClientDC(NULL), w, h);
HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
// Draw the background color before we change mapping mode
HBRUSH hbrBack = CreateSolidBrush( clrBack );
HBRUSH hbrOld = (HBRUSH)::SelectObject(destDC.m_hDC, hbrBack );
destDC.PatBlt( 0, 0, w, h, PATCOPY );
::DeleteObject(::SelectObject(destDC.m_hDC, hbrOld));
// We will use world transform to rotate the bitmap
SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);
XFORM xform;
xform.eM11 = cosine;
xform.eM12 = -sine;
xform.eM21 = sine;
xform.eM22 = cosine;
xform.eDx = (float)-minx;
xform.eDy = (float)-miny;
SetWorldTransform( destDC.m_hDC, &xform );
// Now do the actual rotating - a pixel at a time
destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
// Restore DCs
SelectObject(sourceDC.m_hDC, hbmOldSource );
SelectObject(destDC.m_hDC, hbmOldDest );
return hbmResult;
}

void CSnakeView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
Move();//贪食蛇移动事件
CFormView::OnTimer(nIDEvent);
}

BOOL CSnakeView::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if (pMsg->message==WM_KEYDOWN)
{
switch (pMsg->wParam)
{
case VK_UP:
m_iDircFlag=0;
break;
case VK_DOWN:
m_iDircFlag=1;
break;
case VK_LEFT:
m_iDircFlag=2;
break;
case VK_RIGHT:
m_iDircFlag=3;
break;
}
Move();
}
return CFormView::PreTranslateMessage(pMsg);
}

void CSnakeView::OnBtnStart()
{
// TODO: Add your control notification handler code here
if (i_Speed==0)
{
SetTimer(TimerMain,500,NULL);
}
else if (i_Speed==1)
{
SetTimer(TimerMain,300,NULL);
}
else
{
SetTimer(TimerMain,100,NULL);
}

}

//画食物的点
void CSnakeView::DrawFoodPoint()
{
CWnd *cwnd=GetDlgItem(IDC_GROUP_MAIN);

CBitmap bit;
bit.LoadBitmap(IDB_SBody);
BITMAP bm;
bit.GetBitmap(&bm);

HDC hdc=CreateCompatibleDC(NULL);
(HBITMAP)SelectObject(hdc,bit);
HDC grouphdc=cwnd->GetDC()->GetSafeHdc();

BitBlt(grouphdc,m_pFood.x,m_pFood.y,bm.bmWidth,bm.bmHeight,hdc,0,0,SRCCOPY);
DeleteDC(grouphdc);
DeleteDC(hdc);
}

//重新生成食物点
void CSnakeView::GenerateFoodPoint()
{
if (iRandomSeed==0)
{
srand((unsigned)time(0));//用当前时间
}
else
{
srand(iRandomSeed);
}
iRandomSeed++;
CWnd *cGroupWnd=GetDlgItem(IDC_GROUP_MAIN);
RECT groupRect;
cGroupWnd->GetClientRect(&groupRect);

CBitmap bit;
bit.LoadBitmap(IDB_SBody);
BITMAP bm;
bit.GetBitmap(&bm);

while (TRUE)
{
BOOL blflag=FALSE;//是否需要重新生成food的点
m_pFood.x=(int)(rand()%(groupRect.right/16))*bm.bmWidth;
m_pFood.y=(int)(rand()%(groupRect.bottom/16))*bm.bmHeight+8;
for (int i=0;i<m_snake.m_points.GetSize(); ++i)
{
if ((m_snake.m_points[i].x==m_pFood.x)&&(m_snake.m_points[i].y==m_pFood.y))
{
blflag=TRUE;
break;
}
}
if (!blflag)
{
break;
}
}
}

void CSnakeView::OnShowWindow(BOOL bShow, UINT nStatus)
{
CFormView::OnShowWindow(bShow, nStatus);
GenerateFoodPoint();//生成点
// TODO: Add your message handler code here

}

void CSnakeView::OnGameSet()
{
// TODO: Add your command handler code here
GAMESET gms;

if (IDOK==gms.DoModal())
{
i_Speed=gms.m_iSpeed;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐