现在的位置: 首页 > 综合 > 正文

程序打包出错的反思

2018年05月02日 ⁄ 综合 ⁄ 共 2719字 ⁄ 字号 评论关闭

         如果你的程序在运行后输出窗口也出现了一下提示:1.exe 中的 0x642bdd8a (mfc80ud.dll) 处最可能的异常: 0xC0000005: 读取位置 0x00000020 时发生访问冲突

那么请注意了,这不是你打包程序发生的错误,你可以自己在调试中设置成release后调试,然后拿到试验机上看看是否程序会自己出错(一个朋友的提示,很感激),如果不是,那么你只能另寻原因了。。如果是那么继续。。你可以在每次的调用函数中设置断点来查看是什么时候再输出窗口上出现的0xC0000005: 读取位置 0x00000020 时发生访问冲突异常,然后找到出错地方,修改。

         下面是我出错的地方。。

这是我响应的WM_SIZE函数,然后调用了自己写的一个Resize();函数

void CMy1Dlg::OnSize(UINT nType, int cx, int cy)
{   

     CDialog::OnSize(nType, cx, cy); 

     // TODO: 在此处添加消息处理程序代码
      Resize(cx,cy);

}

函数时这样写的:
void CMy1Dlg::Resize(int x,int y)
{
 CRect OldRect;
 GetDlgItem(IDC_LOADZB)->GetClientRect(&OldRect);

}
 然后因为Onsize()是在窗口大小更改时调用的,

Onsize函数是在OnInitDialog之前调用的,但是在Onsize函数中却又未判断地调用了对话框的子控件
GetDlgItem(IDC_LOADZB)->GetClientRect(&OldRect);
于是出现异常....

解决:设置判断变量IsDialog,初始化为FALSE,然后在OnSize()中判断,如果已经调用了OnInitDialog()则执行,(在对子控件有操作的情况下)在调用完OnInitDialog的时候设置IsDialog为TRUE即可。

分析:

跟踪到基类的CDialog::OnInitDialog();  以为是基类中的ExecuteDlgInit()函数起的作用,

ExecuteDlgInit()的函数作用:
启动对话框资源
备注:
ExecuteDlgInit 将使用其他源中的资源绑定到执行模块或资源

然后在CDialog::OnInitDialog()之前调用了子控件

BOOL CMy1Dlg::OnInitDialog()
{
 CRect CPrect;
 GetDlgItem(IDC_LOADZB)->GetClientRect(CPrect);
 CDialog::OnInitDialog();

   ........

}

结果却没有异常,这说明不是CDialog::OnInitDialog()中的函数的作用...

然后在Resize中测试,即Onsize()的调用函数中进行判断是否含有其窗口句柄(至于为什么判断句柄是因为在调用GetClientRect的时候调用的是::GetClientRect(m_hWnd, lpRect);)

然后用IsWindow(HWND hWnd)来判断发现只要有引用到这个句柄的地方就会出错。。如
HWND hwnd=GetDlgItem(IDC_LOADZB)->m_hWnd;就会调用到OnInitDialog(),而(IDC_LOADZB)->m_hWndd只是调用放回值错,但是不调用OnInitDialog()。

WM_INITDIALOG消息响应函数是在程序运行时,当其对话框和子控件全部创建完毕,将要显示内容的时候发送的消息。因此可以在WM_INITDIALOG消息响应函数中添加对编辑框控件的初始化和修改。

CWnd* CWnd::GetDlgItem(int nID) const
{
 ASSERT(::IsWindow(m_hWnd));

 if (m_pCtrlCont == NULL)
  return CWnd::FromHandle(::GetDlgItem(m_hWnd, nID));     //进入了这个函数
 else
  return m_pCtrlCont->GetDlgItem(nID);
}

CWnd* PASCAL CWnd::FromHandle(HWND hWnd)         //如果还未调用OnInitDialog之前这个hWnd是空的,而调用在刚刚调用OnInitDialog函数中调用的hWnd不是空的,那么只能是在OnInitDialog之前但在Onsize之后调用的函数来决定了。
{
 CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist
 ASSERT(pMap != NULL);
 CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);

#ifndef _AFX_NO_OCC_SUPPORT
 pWnd->AttachControlSite(pMap);
#endif

 ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
 return pWnd;
}

其中一个pWnd是为空的,即Cwnd的对象还没有创建,另一个是含有值的。

然后查了WM_INITDIALOG

Specifies additional initialization data. This data is passed to the system as thelParam parameter in a call to the
CreateDialogIndirectParam,CreateDialogParam,
DialogBoxIndirectParam, orDialogBoxParam function used to create the dialog box. For property sheets, this parameter is a pointer to thePROPSHEETPAGE structure used
to create the page. This parameter is zero if any other dialog box creation function is used.

这里对话框模板中有几个子控件,CreateDialogIndirectParam就将调用几次CreateWindowEx函数。
等所有子控件创建完毕后,CreateDialogIndirectParam发出WM_INITDIALOG消息, 调用对话框的OnInitDialog的函数。

所以要等CreateDialogIndirectParam调用完后才能调用子控件的对象。。。这时的对象才和句柄连接了。

 

 

抱歉!评论已关闭.