动态创建按钮销毁出错

bluesky12312388 2011-02-17 06:03:01
重载的CzButton类

zButton.h

#ifndef _CZBUTTON_H_
#define _CZBUTTON_H_
/////////////////////////////////////////////////////////////////////////////
// CzButton window

class CzButton : public CButton
{
// Construction
public:
CzButton();

// Attributes
public:

// Operations
public:

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CzButton)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL

// Implementation
public:
virtual ~CzButton();

// Generated message map functions
protected:
//{{AFX_MSG(CzButton)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
protected:
bool m_button_down;
short m_FocusRectMargin; //dotted margin offset
CBitmap m_bNormal,m_bDown,m_bDisabled,m_bMask,m_bOver,m_bFocus; //skin bitmaps
short m_DrawMode; //0=normal; 1=stretch; 2=tiled;
BOOL m_Border; //0=flat; 1=3D;
bool m_Checked; //radio & check buttons
bool m_tracking;
COLORREF m_TextColor; //button text color
void FillWithBitmap(CDC* dc, HBITMAP hbmp, RECT r);
void DrawBitmap(CDC* dc, HBITMAP hbmp, RECT r, int DrawMode);
int GetBitmapWidth (HBITMAP hBitmap);
int GetBitmapHeight (HBITMAP hBitmap);
HRGN hClipRgn; //clipping region
HRGN CreateRgnFromBitmap(HBITMAP hBmp, COLORREF color);




public:
void SetPosition(CRect RC, int pos);
void SetSkin(UINT normal,UINT down, UINT over=0, UINT disabled=0, UINT focus=0,UINT mask=0,
short drawmode=1,short border=1,short margin=4);
COLORREF SetTextColor(COLORREF new_color);



afx_msg void OnDestroy();
};


#endif //


// zButton.cpp : implementation file
//

#include "stdafx.h"
#include "zButton.h"



CzButton::CzButton()
{
m_DrawMode=1; // normal drawing mode
m_FocusRectMargin=0; // disable focus dotted rect
hClipRgn=NULL; // no clipping region
m_TextColor=GetSysColor(COLOR_BTNTEXT); // default button text color
m_button_down = m_tracking = m_Checked = false;
}

CzButton::~CzButton()
{
if (hClipRgn) DeleteObject(hClipRgn); // free clip region
}


BEGIN_MESSAGE_MAP(CzButton, CButton)
//{{AFX_MSG_MAP(CzButton)
// ON_WM_LBUTTONDOWN()
// ON_WM_LBUTTONUP()
// ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
ON_WM_DESTROY()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CzButton message handlers

void CzButton::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
ModifyStyle( 0, BS_OWNERDRAW );
CButton::PreSubclassWindow();
}

void CzButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your code to draw the specified item
ASSERT (lpDrawItemStruct);
//TRACE("* Captured: %08X\n", ::GetCapture());

//Check if the button state in not in inconsistent mode...
POINT mouse_position;
if ((m_button_down) && (::GetCapture() == m_hWnd) && (::GetCursorPos(&mouse_position))){
if (::WindowFromPoint(mouse_position) == m_hWnd){
if ((GetState() & BST_PUSHED) != BST_PUSHED) {
//TRACE("* Inconsistency up detected! Fixing.\n");
SetState(TRUE);
return;
}
} else {
if ((GetState() & BST_PUSHED) == BST_PUSHED) {
//TRACE("* Inconsistency up detected! Fixing.\n");
SetState(FALSE);
return;
}
}
}

//TRACE("* Drawing: %08x\n", lpDrawItemStruct->itemState);
CString sCaption;
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC); // get device context
RECT r=lpDrawItemStruct->rcItem; // context rectangle
int cx = r.right - r.left ; // get width
int cy = r.bottom - r.top ; // get height
// get text box position
RECT tr={r.left+m_FocusRectMargin+2,r.top,r.right-m_FocusRectMargin-2,r.bottom};

GetWindowText(sCaption); // get button text
pDC->SetBkMode(TRANSPARENT);

// Select the correct skin
if (lpDrawItemStruct->itemState & ODS_DISABLED){ // DISABLED BUTTON
if(m_bDisabled.m_hObject==NULL)
// no skin selected for disabled state -> standard button
pDC->FillSolidRect(&r,GetSysColor(COLOR_BTNFACE));
else // paint the skin
DrawBitmap(pDC,(HBITMAP)m_bDisabled,r,m_DrawMode);
// if needed, draw the standard 3D rectangular border
if (m_Border) pDC->DrawEdge(&r,EDGE_RAISED,BF_RECT);
// paint the etched button text
pDC->SetTextColor(GetSysColor(COLOR_3DHILIGHT));
pDC->DrawText(sCaption,&tr,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
OffsetRect(&tr,-1,-1);
pDC->DrawText(sCaption,&tr,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
} else { // SELECTED (DOWN) BUTTON
if ((lpDrawItemStruct->itemState & ODS_SELECTED)||m_Checked){
if(m_bDown.m_hObject==NULL)
// no skin selected for selected state -> standard button
pDC->FillSolidRect(&r,GetSysColor(COLOR_BTNFACE));
else { // paint the skin
DrawBitmap(pDC,(HBITMAP)m_bDown,r,m_DrawMode);
}
OffsetRect(&tr,1,1); //shift text
// if needed, draw the standard 3D rectangular border
if (m_Border) pDC->DrawEdge(&r,EDGE_SUNKEN,BF_RECT);
} else { // DEFAULT BUTTON
if(m_bNormal.m_hObject==NULL)
// no skin selected for normal state -> standard button
pDC->FillSolidRect(&r,GetSysColor(COLOR_BTNFACE));
else // paint the skin
if ((m_tracking)&&(m_bOver.m_hObject!=NULL)){
DrawBitmap(pDC,(HBITMAP)m_bOver,r,m_DrawMode);
} else {
if ((lpDrawItemStruct->itemState & ODS_FOCUS)&&(m_bFocus.m_hObject!=NULL)){
DrawBitmap(pDC,(HBITMAP)m_bFocus,r,m_DrawMode);
} else {
DrawBitmap(pDC,(HBITMAP)m_bNormal,r,m_DrawMode);
}
}
// if needed, draw the standard 3D rectangular border
if (m_Border) pDC->DrawEdge(&r,EDGE_RAISED,BF_RECT);
}
// paint the focus rect
if ((lpDrawItemStruct->itemState & ODS_FOCUS)&&(m_FocusRectMargin>0)){
r.left += m_FocusRectMargin ;
r.top += m_FocusRectMargin ;
r.right -= m_FocusRectMargin ;
r.bottom -= m_FocusRectMargin ;
DrawFocusRect (lpDrawItemStruct->hDC, &r) ;
}
// paint the enabled button text
pDC->SetTextColor(m_TextColor);
pDC->DrawText(sCaption,&tr,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
}
}

void CzButton::DrawBitmap(CDC *dc, HBITMAP hbmp, RECT r, int DrawMode)
{
// DrawMode: 0=Normal; 1=stretch; 2=tiled fill
if(DrawMode==2){
FillWithBitmap(dc,hbmp,r);
return;
}
if(!hbmp) return; //safe check

int cx=r.right - r.left;
int cy=r.bottom - r.top;
CDC dcBmp,dcMask;
dcBmp.CreateCompatibleDC(dc);
dcBmp.SelectObject(hbmp);

if (m_bMask.m_hObject!=NULL){
dcMask.CreateCompatibleDC(dc);
dcMask.SelectObject(m_bMask);

CDC hdcMem;
hdcMem.CreateCompatibleDC(dc);
CBitmap hBitmap;
hBitmap.CreateCompatibleBitmap(dc,cx,cy);
hdcMem.SelectObject(hBitmap);

hdcMem.BitBlt(r.left,r.top,cx,cy,dc,0,0,SRCCOPY);
if(!DrawMode){
hdcMem.BitBlt(r.left,r.top,cx,cy,&dcBmp,0,0,SRCINVERT);
hdcMem.BitBlt(r.left,r.top,cx,cy,&dcMask,0,0,SRCAND);
hdcMem.BitBlt(r.left,r.top,cx,cy,&dcBmp,0,0,SRCINVERT);
} else {
int bx=GetBitmapWidth(hbmp);
int by=GetBitmapHeight(hbmp);
hdcMem.StretchBlt(r.left,r.top,cx,cy,&dcBmp,0,0,bx,by,SRCINVERT);
hdcMem.StretchBlt(r.left,r.top,cx,cy,&dcMask,0,0,bx,by,SRCAND);
hdcMem.StretchBlt(r.left,r.top,cx,cy,&dcBmp,0,0,bx,by,SRCINVERT);
}
dc->BitBlt(r.left,r.top,cx,cy,&hdcMem,0,0,SRCCOPY);

hdcMem.DeleteDC();
hBitmap.DeleteObject();

DeleteDC(dcMask);
} else {
if(!DrawMode){
dc->BitBlt(r.left,r.top,cx,cy,&dcBmp,0,0,SRCCOPY);
} else {
int bx=GetBitmapWidth(hbmp);
int by=GetBitmapHeight(hbmp);
dc->StretchBlt(r.left,r.top,cx,cy,&dcBmp,0,0,bx,by,SRCCOPY);
}
}
DeleteDC(dcBmp);

}

void CzButton::FillWithBitmap(CDC *dc, HBITMAP hbmp, RECT r)
{
if(!hbmp) return;
CDC memdc;
memdc.CreateCompatibleDC(dc);
memdc.SelectObject(hbmp);
int w = r.right - r.left;
int h = r.bottom - r.top;
int x,y,z;
int bx=GetBitmapWidth(hbmp);
int by=GetBitmapHeight(hbmp);
for (y = r.top ; y < h ; y += by){
if ((y+by)>h) by=h-y;
z=bx;
for (x = r.left ; x < w ; x += z){
if ((x+z)>w) z=w-x;
dc->BitBlt(x, y, z, by, &memdc, 0, 0, SRCCOPY);
}
}
DeleteDC(memdc);

}

...全文
342 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
zaqizaba2011 2011-02-18
  • 打赏
  • 举报
回复
好长。。。
hslinux 2011-02-18
  • 打赏
  • 举报
回复
mstlq 2011-02-18
  • 打赏
  • 举报
回复
那个直接导致程序debug版抛出异常,分散我注意力了
bluesky12312388 2011-02-18
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 mstlq 的回复:]

楼主这个函数看得我好囧……
C/C++ code

void CTextScreen::OnSysCommand(UINT nID, LPARAM lParam)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if( SC_CLOSE == nID)
{
CWnd *pParentWnd = this->GetParent();
……
[/Quote]
这个没什么用,是我用来模拟的时候有个对话框每次都要ALT + F4去关,麻烦,所以加了这么一句
mstlq 2011-02-18
  • 打赏
  • 举报
回复
楼主这个函数看得我好囧……

void CTextScreen::OnSysCommand(UINT nID, LPARAM lParam)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if( SC_CLOSE == nID)
{
CWnd *pParentWnd = this->GetParent();
this->DestroyWindow();
delete this;
char buf[8] = { 0 };
sprintf(buf,"%d",sizeof(this));
OutputDebugString(buf);
pParentWnd->DestroyWindow();
}
CDialog::OnSysCommand(nID, lParam);
}
healer_kx 2011-02-18
  • 打赏
  • 举报
回复
无功不受分,healer.kx.yu@gmail.com
可以发我一份,
bluesky12312388 2011-02-18
  • 打赏
  • 举报
回复
发个界面图片,大伙看看怎么样,其实是别人美工做得好~~
mstlq 2011-02-18
  • 打赏
  • 举报
回复
debug还有问题就说明真的还有问题,囧……
刚刚看到楼主的email……
今晚试试找找……
bluesky12312388 2011-02-18
  • 打赏
  • 举报
回复
结帖给分了,虽然大家没帮上什么忙,但是来者有份
(MS Debug版本还是会断在::IsWindow(m_hWnd)上)
bluesky12312388 2011-02-18
  • 打赏
  • 举报
回复
经过近两天多的调试问题终于解决,
总结下,
1.动态创建按钮及窗口的时候一定要注意释放顺序,
2.要确保动态创建的窗口及控件不在使用才释放
3.由于窗口之间来回切换导致放在析构函数的释放
资源很有可能造成句柄访问错误,如果你确定你窗口及按钮不在
使用,请立即释放,例如:
p_BtOK->OnDestroy();
delete m_pBtOK;

//这两句最好不要放到析构函数中
4.经过调整释放顺序及改成Release版本,问题得到解决,
也有可能是编译器在Debug版本的时候做了些手脚。
healer_kx 2011-02-18
  • 打赏
  • 举报
回复
150分啊。。。MFC啊。。。就是代码太多了。,。。
管哥的天下 2011-02-18
  • 打赏
  • 举报
回复
太长了,╮(╯_╰)╭!

不过给lz顶顶!
bluesky12312388 2011-02-18
  • 打赏
  • 举报
回复
问题初步找到了,明天到CE下去测试,不对应该是今天

对于new 出来的 m_pBtDown;
销毁的时候函数调用顺序
m_pBtDown->DestoryWindow();
CWnd::DestroyWindow();
在CWnd::DestroyWindow();中有(已经调用过DestoryWindow和delete m_pBtDown)m_hWnd还是不为0
if ((m_hWnd == NULL) && (m_pCtrlSite == NULL))
return FALSE;
::DestoryWindow();

最终通过最简化代码原则,发现我是在
CTextScreen的PreTranslateMessage(MSG* pMsg)中有消息的路由
HWND hWnd = NULL;
if( pMsg->message == WM_LBUTTONDBLCLK)
{
if( pMsg->hwnd == ( hWnd = ::GetDlgItem(m_hWnd,IDB_BT_NEW_SCREEN_OK) ) )
{
MessageBox("NewOK"); //实际上是pCurScreen->HandleMsg(KEY_XX);
}
else if( pMsg->hwnd ==(hWnd = ::GetDlgItem(m_hWnd,IDB_BT_NEW_SCREEN_CANCEL) ) )
{
MessageBox("NewCancel"); //实际上是pCurScreen->HandleMsg(KEY_XX);
}

}

因为最后按下其中一个按钮切换画面的时候也会通过这条消息路由,
并且还有可能使用了GetDlgItem之类的函数,首先这得通过assert(::IsWindow(m_hWnd));
有时候断在这里有时候不是,联想到自己创建与释放代码的顺序不一致有可能会出现问题,
并且加上一个只有是当前屏幕ID的时候才进入相应的按钮消息路由判断,
并且调试的时候编译会自做聪明的将你已经释放的并且赋值为0的m_hWnd 变成0xFEEEFEEE,
这可能也是一个原因。
上班测试过之后在发详细的结果。
wangtk 2011-02-17
  • 打赏
  • 举报
回复
好长啊 现在看别人的东西一张就没心情了

我是不是老了~~
bluesky12312388 2011-02-17
  • 打赏
  • 举报
回复
用Win32的工程来模拟初步没有出现问题,明天还得继续找
artcpp 2011-02-17
  • 打赏
  • 举报
回复
销毁出错的原因往往是因为重复销毁
bluesky12312388 2011-02-17
  • 打赏
  • 举报
回复
工程是基于WinCE的,等等我回去建个Windows平台下的测试工程给你,我自己也在测测。
mstlq 2011-02-17
  • 打赏
  • 举报
回复
暂时没时间看……
可是分数又好诱惑啊……
工程发mstlq@vip.qq.com吧……

今晚吃完宵夜看……
bluesky12312388 2011-02-17
  • 打赏
  • 举报
回复


int CzButton::GetBitmapWidth (HBITMAP hBitmap)
{
BITMAP bm; GetObject(hBitmap,sizeof(BITMAP),(PSTR)&bm);
return bm.bmWidth;
}


int CzButton::GetBitmapHeight (HBITMAP hBitmap)
{
BITMAP bm; GetObject(hBitmap,sizeof(BITMAP),(PSTR)&bm);
return bm.bmHeight;
}
/////////////////////////////////////////////////////////////////////////////
void CzButton::SetSkin(UINT normal,UINT down,UINT over,UINT disabled, UINT focus,UINT mask,
short drawmode, short border, short margin)
{
m_bNormal.DeleteObject(); //free previous allocated bitmap
m_bDown.DeleteObject();
m_bOver.DeleteObject();
m_bDisabled.DeleteObject();
m_bMask.DeleteObject();
m_bFocus.DeleteObject();

if (normal>0) m_bNormal.LoadBitmap(normal);
if (down>0) m_bDown.LoadBitmap(down);
if (over>0) m_bOver.LoadBitmap(over);
if (focus>0) m_bFocus.LoadBitmap(focus);

if (disabled>0) m_bDisabled.LoadBitmap(disabled);
else if (normal>0) m_bDisabled.LoadBitmap(normal);

m_DrawMode=max(0,min(drawmode,2));
m_Border=border;
m_FocusRectMargin=max(0,margin);

if (mask>0){
m_bMask.LoadBitmap(mask);
if (hClipRgn) DeleteObject(hClipRgn);
hClipRgn = CreateRgnFromBitmap(m_bMask,RGB(255,255,255));
if (hClipRgn){
SetWindowRgn(hClipRgn, TRUE);
SelectClipRgn((HDC)GetDC(),hClipRgn);
}
if (m_DrawMode==0){
SetWindowPos(NULL,0,0,GetBitmapWidth(m_bMask),
GetBitmapHeight(m_bMask),SWP_NOZORDER|SWP_NOMOVE);
}
}
}

////////////////////////////////////////////////////////////////////////////
void CzButton::SetPosition(CRect RC, int pos)
{
MoveWindow(RC.left + 50 + 40 * pos, RC.bottom - 30, 30, 20);
}

/////////////////////////////////////////////////////////////////////////////
HRGN CzButton::CreateRgnFromBitmap(HBITMAP hBmp, COLORREF color)
{
if (!hBmp) return NULL;

BITMAP bm;
GetObject( hBmp, sizeof(BITMAP), &bm ); // get bitmap attributes

CDC dcBmp;
dcBmp.CreateCompatibleDC(GetDC()); //Creates a memory device context for the bitmap
dcBmp.SelectObject(hBmp); //selects the bitmap in the device context

const DWORD RDHDR = sizeof(RGNDATAHEADER);
const DWORD MAXBUF = 40; // size of one block in RECTs
// (i.e. MAXBUF*sizeof(RECT) in bytes)
LPRECT pRects;
DWORD cBlocks = 0; // number of allocated blocks

INT i, j; // current position in mask image
INT first = 0; // left position of current scan line
// where mask was found
bool wasfirst = false; // set when if mask was found in current scan line
bool ismask; // set when current color is mask color

// allocate memory for region data
RGNDATAHEADER* pRgnData = (RGNDATAHEADER*)new BYTE[ RDHDR + ++cBlocks * MAXBUF * sizeof(RECT) ];
memset( pRgnData, 0, RDHDR + cBlocks * MAXBUF * sizeof(RECT) );
// fill it by default
pRgnData->dwSize = RDHDR;
pRgnData->iType = RDH_RECTANGLES;
pRgnData->nCount = 0;
for ( i = 0; i < bm.bmHeight; i++ )
for ( j = 0; j < bm.bmWidth; j++ ){
// get color
ismask=(dcBmp.GetPixel(j,bm.bmHeight-i-1)!=color);
// place part of scan line as RECT region if transparent color found after mask color or
// mask color found at the end of mask image
if (wasfirst && ((ismask && (j==(bm.bmWidth-1)))||(ismask ^ (j<bm.bmWidth)))){
// get offset to RECT array if RGNDATA buffer
pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
// save current RECT
pRects[ pRgnData->nCount++ ] = CRect( first, bm.bmHeight - i - 1, j+(j==(bm.bmWidth-1)), bm.bmHeight - i );
// if buffer full reallocate it
if ( pRgnData->nCount >= cBlocks * MAXBUF ){
LPBYTE pRgnDataNew = new BYTE[ RDHDR + ++cBlocks * MAXBUF * sizeof(RECT) ];
memcpy( pRgnDataNew, pRgnData, RDHDR + (cBlocks - 1) * MAXBUF * sizeof(RECT) );
delete pRgnData;
pRgnData = (RGNDATAHEADER*)pRgnDataNew;
}
wasfirst = false;
} else if ( !wasfirst && ismask ){ // set wasfirst when mask is found
first = j;
wasfirst = true;
}
}
dcBmp.DeleteDC(); //release the bitmap
// create region
/* Under WinNT the ExtCreateRegion returns NULL (by Fable@aramszu.net) */
// HRGN hRgn = ExtCreateRegion( NULL, RDHDR + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData );
/* ExtCreateRegion replacement { */
HRGN hRgn=CreateRectRgn(0, 0, 0, 0);
ASSERT( hRgn!=NULL );
pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
for(i=0;i<(int)pRgnData->nCount;i++)
{
HRGN hr=CreateRectRgn(pRects[i].left, pRects[i].top, pRects[i].right, pRects[i].bottom);
VERIFY(CombineRgn(hRgn, hRgn, hr, RGN_OR)!=ERROR);
if (hr) DeleteObject(hr);
}
ASSERT( hRgn!=NULL );
/* } ExtCreateRegion replacement */

delete pRgnData;
return hRgn;
}

/////////////////////////////////////////////////////////////////////////////
COLORREF CzButton::SetTextColor(COLORREF new_color)
{
COLORREF tmp_color=m_TextColor;
m_TextColor=new_color;
return tmp_color; //returns the previous color
}

有关pTextScreen;
extern CTextScreen *pTextScreen; //class CTextScreen:public CDialog()
然后我在一个类如
CScreenTaskManage构造函数中
m_pBtDown = new CzButton();
m_pBtDown->Create(NULL,WS_CHILD |WS_VISIBLE|BS_PUSHBUTTON,rcBt,pTextScreen,IDB_BT_TASK_N_DOWN );
m_pBtDown->SetSkin(PIC_SYS_INFO_CONFIRM_U,PIC_SYS_INFO_CONFIRM_D,0,0,0,0,0,0,0);
m_pBtDown->MoveWindow(xPos,yPos,nWidth,nHeight);
能够正常显示并响应消息

但是我析构函数中调用 delete m_pBtDown;可以返回到另一个画面,但是会断点在
assert(::IsWindow(m_hWnd)); //这里 有时候m_hWnd明明是被delete掉了为0,
在调试的时候又变成开始的值,我猜可能是堆栈被破坏了,但是一直没找出哪里错了,
最有可能出错的地方是 CzButton 中 对hClipRgn的操作,苦于一直没找出错误,现求肋于兄弟们,
先谢过拉!

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧