mysql 0xc0000005_duilib菜单开发遇见“0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突”…

mysql 0xc0000005_duilib菜单开发遇见“0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突”…我的程序是这样一个逻辑。首先创建用户列表,点击列表项弹出菜单,点击菜单上“设备选项”,弹出设备列表,上面显示这个用户拥有的设备。菜单的创建参考了这为博主的教程:http://www.cnblogs.com/Alberl/category/520438.html如图点击列表项,弹出菜单中点击“设备”,运行新的窗口“设备列表”。接下来问题出现了,上面操作重复两遍,会在第二次关闭设备列表的时候发生…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

我的程序是这样一个逻辑。 首先创建用户列表,点击列表项弹出菜单,点击菜单上“设备选项”,弹出设备列表,上面显示这个用户拥有的设备。

菜单的创建参考了这为博主的教程:http://www.cnblogs.com/Alberl/category/520438.html

2e7d6bc3932ffff73af332e9581b10b4.png

如图点击列表项,弹出菜单中点击“设备”,运行新的窗口 “设备列表”。

接下来问题出现了,上面操作重复两遍,会在第二次关闭设备列表的时候 发生异常,程序崩溃。

3ac9548876e4526393e63a22a4244404.png

这就让我非常头痛了。

我知道这种错误是内存访问问题,一般都是指针操作不当造成的。

调试程序,中断发生位置是notify函数(duilib响应函数)结束位置。总之不是发生错误的位置。

下面贴出菜单程序源代码:

MenuWnd2.h:

#pragma once#include#include”my_duilib.h”#include

class CUserManageMenuWnd: publicCXMLWnd {public:explicit CUserManageMenuWnd(LPCTSTR pszXMLPath,inttag);protected:virtual ~CUserManageMenuWnd(); //私有化析构函数,这样此对象只能通过new来生成,而不能直接定义变量。就保证了delete this不会出错

public:voidInit(HWND hWndParent, POINT ptPos);virtual voidOnFinalMessage(HWND hWnd);virtualLRESULT HandleMessage (UINT uMsg, WPARAM wParam, LPARAM lParam);virtual LRESULT OnKillFocus (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled);virtual void Notify( TNotifyUI&msg );private:inttag;

};

MenuWnd2.cpp:

#include “MenuWnd2.h”#include”my_including.h”#include”page_info.h”#include”mysql_utils.h”#include”user_dev_lst.h”

externc_page_info page_info;extern user_sel_ret*user_arr;

CUserManageMenuWnd::CUserManageMenuWnd( LPCTSTR pszXMLPath,inttag)

: CXMLWnd(pszXMLPath){this->tag =tag;}

CUserManageMenuWnd::~CUserManageMenuWnd(){

}voidCUserManageMenuWnd::Init( HWND hWndParent, POINT ptPos ){

Create(hWndParent, _T(“MenuWnd”), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);

::ClientToScreen(hWndParent,&ptPos);

::SetWindowPos(*this, NULL, ptPos.x, ptPos.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE |SWP_NOACTIVATE);

}void CUserManageMenuWnd::OnFinalMessage( HWND /*hWnd*/) {

deletethis;

}

LRESULT CUserManageMenuWnd::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ) {

LRESULT lRes= 0;

BOOL bHandled=TRUE;switch( uMsg )

{caseWM_KILLFOCUS:

lRes=OnKillFocus(uMsg, wParam, lParam, bHandled);break;default:

bHandled=FALSE;

}if(bHandled ||m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))

{returnlRes;

}return__super::HandleMessage(uMsg, wParam, lParam);

}void CUserManageMenuWnd::Notify( TNotifyUI&msg ) {intnum;stringuser_id;intdev_num;

dev_sel_ret*devs;if( msg.sType == _T(“itemclick”) ) {string click_menu_option = msg.pSender->GetName().ToString();if( !click_menu_option.compare(_T(“check_devs”)) ) {PostMessage(WM_KILLFOCUS);num= page_info.get_begin_index() + this->tag;

user_id=user_arr[num].id;

devs= MYSQL_INTERFACES::select_devs_of_user(“”, &dev_num, user_id);//显示该用户设备列表

create_usr_dev_lst_win(dev_num, devs);}

__super::Notify(msg);

}

LRESULT CUserManageMenuWnd::OnKillFocus( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled ) {

Close();

bHandled=FALSE;return__super::OnKillFocus(uMsg, wParam, lParam, bHandled);

}

创建菜单的代码,在user列表的notify函数里,POINT用来记录菜单生成的位置坐标:

void CUsrManageWnd::Notify( TNotifyUI&msg ) {if(msg.sType == _T(“itemclick”)) {int i_index = msg.pSender->GetTag();

POINT pt={msg.ptMouse.x, msg.ptMouse.y};

CUserManageMenuWnd*p_menu = new CUserManageMenuWnd(_T(“Menu/menu2.xml”), i_index);

p_menu->Init(g_usr_manage_win_hwnd, pt);

p_menu->ShowWindow(TRUE);

}

__super::Notify(msg);

}

发生中断的位置就是notify函数结束的位置,真是看的我一头雾水啊,中断位置跳到反汇编来看也看不出所以然。

试了一天,最后到了晚上才发现问题所在,那就是delete。

.h文件可知,该程序私有化析构函数,使得只能new来创建,这就需要在合适时机去delete。

程序原本将delete写在OnFinalMessage函数里。但在实际调试过程中,发现在执行了OnFinalMessage函数的delete后,程序竟然又进入到notify函数里,随后报错。

我也不是很明白,为什么点击一次菜单,会进入两次notify函数,对于duilib的消息机制也不是那么精通。

最后我的解决方案,就加入一个计数的变量。进入notify创建一次设备列表,则计数变量+1。如果计数变量大于0,则不再创建设备列表。且只有计数变量大于0的时候,才执行delete。

如下,计数变量为new_win_num。

#pragma once#include#include”my_duilib.h”#include

class CUserManageMenuWnd: publicCXMLWnd {public:explicit CUserManageMenuWnd(LPCTSTR pszXMLPath,inttag);protected:virtual ~CUserManageMenuWnd(); //私有化析构函数,这样此对象只能通过new来生成,而不能直接定义变量。就保证了delete this不会出错

public:voidInit(HWND hWndParent, POINT ptPos);virtual voidOnFinalMessage(HWND hWnd);virtualLRESULT HandleMessage (UINT uMsg, WPARAM wParam, LPARAM lParam);virtual LRESULT OnKillFocus (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled);virtual void Notify( TNotifyUI&msg );private:inttag;intnew_win_num;

};

#include “MenuWnd2.h”#include”my_including.h”#include”page_info.h”#include”mysql_utils.h”#include”user_dev_lst.h”

externc_page_info page_info;extern user_sel_ret*user_arr;

CUserManageMenuWnd::CUserManageMenuWnd( LPCTSTR pszXMLPath,inttag)

: CXMLWnd(pszXMLPath){this->tag =tag;this->new_win_num = 0;

}

CUserManageMenuWnd::~CUserManageMenuWnd(){

}voidCUserManageMenuWnd::Init( HWND hWndParent, POINT ptPos ){

Create(hWndParent, _T(“MenuWnd”), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);

::ClientToScreen(hWndParent,&ptPos);

::SetWindowPos(*this, NULL, ptPos.x, ptPos.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE |SWP_NOACTIVATE);

}void CUserManageMenuWnd::OnFinalMessage( HWND /*hWnd*/) {if (new_win_num >0)delete this;

}

LRESULT CUserManageMenuWnd::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ) {

LRESULT lRes= 0;

BOOL bHandled=TRUE;switch( uMsg )

{caseWM_KILLFOCUS:

lRes=OnKillFocus(uMsg, wParam, lParam, bHandled);break;default:

bHandled=FALSE;

}if(bHandled ||m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))

{returnlRes;

}return__super::HandleMessage(uMsg, wParam, lParam);

}void CUserManageMenuWnd::Notify( TNotifyUI&msg ) {intnum;stringuser_id;intdev_num;

dev_sel_ret*devs;if( msg.sType == _T(“itemclick”) ) {string click_menu_option = msg.pSender->GetName().ToString();if( !click_menu_option.compare(_T(“check_devs”)) ) {if (new_win_num == 0) {

PostMessage(WM_KILLFOCUS);

num= page_info.get_begin_index() + this->tag;

user_id=user_arr[num].id;

devs= MYSQL_INTERFACES::select_devs_of_user(“”, &dev_num, user_id);//显示该用户设备列表

create_usr_dev_lst_win(dev_num, devs);

}

new_win_num++;

}}

__super::Notify(msg);

}

LRESULT CUserManageMenuWnd::OnKillFocus( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&bHandled ) {

Close();

bHandled=FALSE;return__super::OnKillFocus(uMsg, wParam, lParam, bHandled);

}

转载一下原作者对于duilib菜单的理解https://www.cnblogs.com/Alberl/p/3352461.html,觉得讲的挺好的:

【菜单类小知识】

如果不用指针的方式,而直接用变量的方式显示菜单 CDuiMenu menu(_T(“Menu/menu.xml”)),则不能用ShowWindow,否则会崩溃,因为出了作用域后窗口被销毁了,所以此时可以将CDuiMenu 定义为成员变量、全局变量、或者静态变量,但是做为一个局部使用的类,这些方法显然不怎么好;

这时可以用ShowModal代替ShowWindow,于是就能看到窗口啦,但是却产生了一个问题,那就是菜单窗口不会失去焦点,或者说点击主窗口的其他区域,菜单不会消失,当然,小伙伴们可以自己捕获鼠标,来判断是否点击了主窗口的其他区域,但显然这种方法也不太好;

这个时候delete this就派上用场啦(用智能指针也会崩溃,因为出了作用域同样会销毁内存,所以只能用delete this啦~ 用delete this就是将作用域交给duilib了),据说COM里面就是用delete this来销毁内存的。Alberl在duilib的Demo里面见到了大量的delete this,觉得这种自杀的方法很不靠谱,这不,前面教程就提到了ActiveX的一个bug,也是和delete this脱不了干系的~  不过既然COM里面都用了delete this,那就说明如果用好这把双刃剑,还是可以带来很多好处的。

因为duilib提供了一个机制,就是窗口的最后一个函数一定是OnFinalMessage,之后不再调用窗口类的其他函数,这就为自杀提供了两个必要条件;delete this而还有一个必要条件就是这个类必须是通过new来申请内存的(而非 “new[]”,亦非placement的”new” ,一定要是最原始的 “new”,当然malloc也行(需要用free,而不是delete)),所以就将析构函数设置成私有函数,就保证了只有通过new申请内存的方式才能编译通过。 而duilib的Demo中大量使用delete this却没有保证这些必要条件,只要直接用变量的方式来声明类,则关闭窗口时就会崩溃,作为Demo,如此不严谨,有待好好规范。 当然,没有XX党,就没有新中国,没有那些大神的Demo,也就轮不到Alberl唧唧歪歪啦,这里Alberl只是觉得Demo应该严谨和权威,毕竟是官方的,并没有其他意思,请多多谅解~O(∩_∩)O~

最后要吸取教训,如果遇到0xC0000005这种异常,一定要检查对内存的操作。数组啊、指针一类的。

也有可能是,释放了对象的对内存后继续对对象进行操作引发的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/186380.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Activity工作流引擎入门

    Activity工作流引擎入门https://blog.csdn.net/fafa211/article/details/79297305https://www.imooc.com/article/details/id/35590

    2022年7月11日
    21
  • MySQL增删改查_sql where case when

    MySQL增删改查_sql where case whensqlserver数据库中raiserror函数的用法server数据库中raiserror的作用就和asp.NET中的thrownewException一样,用于抛出一个异常或错误。这个错误可以被程序捕捉到。raiserror的常用格式如下:raiserror(‘错误的描述’,错误的严重级别代码,错误的标识,错误的描述中的参数的值(这个可以是多个),一些其它参数),在官方上的格式描述如下:…

    2025年6月17日
    3
  • 逻辑漏洞概述[通俗易懂]

    逻辑漏洞概述[通俗易懂]访问:主体与客体之间的信息流动。主动的是主体,被动的是客体。主体访问客体的四个步骤:身份标识->身份验证(数据库匹配信息,判断身份是否合法)->授权(判断身份是谁,管理员或正常账户)->审计(记录操作)访问控制模型:自主访问控住(DAC大部分使用):由客体的属主自主对客体进行管理,自主决定是否将访问权限授予其他主体。强制访问控制(MAC军方或重要政府部门用):安全…

    2022年4月28日
    47
  • 二进制和十进制的转换机制是什么?_转化成二进制

    二进制和十进制的转换机制是什么?_转化成二进制一、十进制转换成二进制1.1正整数转二进制要点:除二取余,倒序排列,高位补零。方法:将正的十进制数除以二,得到的商再除以二,依次类推直至商为0或1时为止,然后在旁边标出各步的余数,最后倒着写出来,高位补零。注:计算机内部表示数的字节单位是定长的,如8位,16位,或32位。所以,位数不够时,高位补零。1.2负整数转二进制方法:先将对应的正整数转换成二进制后,对二进制取…

    2022年10月18日
    0
  • 桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!

    桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!前言前段时间,写了篇博客关于Python自制一款炫酷音乐播放器。有粉丝问我,音乐播放器为什么要用PyQt5,效果是不是比Tkinter赞?PyQt5真的可以实现这些炫酷的UI画面吗?之前没接触过PyQt5,能不能多分享一些这方面的开发案例?今天就带大家,一起用Python的PyQt5开发一个有趣的自定义桌面动画挂件,看看实现的动画挂件效果!下面,我们开始介绍这个自定义桌面动画挂件的制作过程。一、核心功能设计总体来说,我们需要实现将自己喜欢的动态图gif或者视频转成一个桌面动画挂件,并且可以通过鼠

    2022年4月25日
    58
  • 求二叉树的最长路径_对下列二叉树进行前序遍历的结果为

    求二叉树的最长路径_对下列二叉树进行前序遍历的结果为Ural 大学有 N 名职员,编号为 1∼N。他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司。每个职员有一个快乐指数,用整数 Hi 给出,其中 1≤i≤N。现在要召开一场周年庆宴会,不过,没有职员愿意和直接上司一起参会。在满足这个条件的前提下,主办方希望邀请一部分职员参会,使得所有参会职员的快乐指数总和最大,求这个最大值。输入格式第一行一个整数 N。接下来 N 行,第 i 行表示 i 号职员的快乐指数 Hi。接下来 N−1 行,每行输入一对整数 L,K,表示 K 是 L 的直接

    2022年8月9日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号