抓蟲記之十:誤殺自己的命令

今天一位同事找我看了一個非常有意思的BUG,在一個彈出的非模態窗體上面,按下【Ctrl + S】,彈出保存文件窗體,點擊取消好,報出0x80808080地址訪問錯誤。但是程序中沒有停下斷點。

先看這個地址很有意思吧?這麼有規律的,絕對很有來頭,不過這個BUG先不講這個。

這個BUG還是很容易跟蹤下來的。不過說是容易,也費了不少勁,因爲消息循環有其特有的特徵,在WndProc裏是不能隨便下斷點的。那如何跟蹤呢?

有人想到ExceptionLog,加入異常機制。這反而麻煩了。其實就是慢慢跟蹤代碼,進行簡單分析。基本就能定位到了。

原來,在彈出的窗體中的消息處理中,響應完消息後,會調用自己定義的消息回調事件,如下:

inherited WnProc(Msg);

If Assigned(FOnMessage) then FOnMessage(Self, Msg);

第一行代碼,在基類中,會自動調用全局消息處理,關鍵是,這位同事的系統中,在保存的時候,釋放掉了一些窗體,包括當前彈出的窗體。

也就是說,第一行代碼執行完成之後,當前對象實例就已經被釋放了。所以第二句話,就會出現地址訪問錯誤了。

那麼,如何解決這個問題呢?這個問題與一般的不太一樣,因爲他涉及到了消息循環。因此我的建議是,將保存事務做完之後,再調用釋放窗體的操作,且該操作作爲一個消息處理,排到消息隊列中。即先聲明一個自定義消息函數:

procedure DoSomeEvent(var Message); message GM_SelfMessage;

並且在保存完成之後通過PostMessage的方式,調用該函數。這樣就能保證WndProc函數處理完成之後,纔會調用到窗體釋放的函數。這個錯誤就應該能夠避免了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章