随笔-60  评论-262  文章-1  trackbacks-0
用 VC6 和 VC71 装载的 ATL 开发软件的人都知道, 当我们定义了一个自销毁窗口时, 一般在 ATL 窗口类的

virtual void OnFinalMessage(HWND ){...}

函数内加一句

delete this;

然后就返回了. 但是气人的是, 每次当我们返回后, 总有一个地方断言失败,

ATLASSERT(pThis->m_pCurrentMsg == &msg);

Google 了许久, 没有满意的解决方案, 包括微软的方案

http://support.microsoft.com/kb/202110

也不好, 自己想尽办法还是 "山重水复疑无路", 后来突然灵光突现, 彻底解决, 就一个函数调用而已: IsWindow(...). 现在, 终极解决方案是这样的:
搜索 atlwin.h 文件内的 "ATLASSERT(pThis->m_pCurrentMsg == &msg);" 字符串 (在文件内有 3 处), 将其原始内容
    LRESULT lRes;
    BOOL bRet 
= pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
    
// restore saved value for the current message
    ATLASSERT(pThis->m_pCurrentMsg == &msg);
    pThis
->m_pCurrentMsg = pOldMsg;
改成
    LRESULT lRes;
    BOOL bRet 
= pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
    
if(FALSE == ::IsWindow(pThis->m_hWnd)) {
        return
 lRes; // 在 CDialogImplBaseT 类里是 return FALSE;  特此说明
    }
    
// restore saved value for the current message
    ATLASSERT(pThis->m_pCurrentMsg == &msg);
    pThis
->m_pCurrentMsg = pOldMsg;
其中红色的代码为我们的修正代码. 万事大吉. 再也不会出现断言失败了.

道理是这样的: 如果 pThis 对象被删除了的话, 那么 pThis 本身和其成员变量 m_hWnd 都将是一个无效值, 那么后续的操作将毫无意义. 因此直接返回, 不用废话.

真是简单的思路直指问题的核心啊.

posted on 2008-07-02 15:44 free2000fly 阅读(2265) 评论(4)  编辑 收藏 引用

评论:
# re: 将 ATL 的一个顽固 Bug 修正了 2008-09-12 21:40 |
错!

不要更改消息泵, 加一个窗口判断是极其愚蠢的,代价是极其昂贵的。

不能这么干,再说了 如果之前 delete this, pThis 就是一个非法指针  回复  更多评论
  
# re: 将 ATL 的一个顽固 Bug 修正了 2008-09-14 09:17 | free2000fly
@错
提出更合理的解决方案来! 仅仅对非法指针进行读取而不做其他操作是安全的, 我怀疑你有没有真正看明白我在说什么.
总有人自以为是, 好为人师, 虎头蛇尾, 应对乏术, 你呀该干嘛干嘛去.   回复  更多评论
  
# re: 将 ATL 的一个顽固 Bug 修正了 2010-10-13 12:21 | iid
# re: 将 ATL 的一个顽固 Bug 修正了[未登录] 2012-09-12 12:34 | kk
哈哈,这SB文章别误导别人了。。。  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理