• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            今天遇到一個(gè)比較有意思的bug, 這里簡單記錄下。

            Bug的癥狀是通過拖拉邊框把我們客戶端主窗口拖小之后,再最大化,會(huì)發(fā)現(xiàn)窗口顯示有問題, 看起來像是刷新問題, 有些地方顯示的不對(duì)了。
            這里要說明的是我這里的主窗口是非常復(fù)雜的窗口, 里面集成了很多組件(cpmponent),有很多層的子窗口。 這個(gè)問題只有在特定條件下才會(huì)發(fā)生, 正常情況下都是好的。

            遇到這種問題,我們?cè)趺刺幚恚?nbsp;

            首先當(dāng)然是觀察癥狀, 究竟是刷新問題, 還是Layout出錯(cuò)了。
            我們可以通過Spy++查看窗口層次是不是正確, 窗口位置是不是對(duì)的。
            查看結(jié)果是窗口的層次和Layout位置都沒有問題。

            既然我們這里遇到的刷新問題,所以我們要從WM_PAINT消息著手, 我們通過Spy++查看相關(guān)窗口的WM_PAINT是不是正確。
            很快我們就會(huì)發(fā)現(xiàn)某個(gè)窗口正在不停地收到WM_PAINT消息, 很可能與我們的bug有關(guān)。

            一個(gè)窗口不停的收到WM_PAINT重畫, 無非大概有幾類原因:
            正常情況是我們正在做動(dòng)畫, 可能是通過定時(shí)器之類的東西讓窗口不停地InvalidateRect重畫某塊區(qū)域, 我們的窗口明顯不屬于這種情況。
            異常情況有時(shí)是WM_PAINT消息里我們的消息處理函數(shù)在某些條件下直接返回了,從而沒有調(diào)用BeginPaint告訴窗口無效區(qū)域已經(jīng)有效, 這樣會(huì)因?yàn)橐驗(yàn)榇翱谝恢庇袩o效區(qū)域存在,導(dǎo)致窗口一直收到WM_PAINT消息。
            還有一種異常情況情況是我們是在WM_PAINT消息里調(diào)用BeginPaint后又調(diào)用了InvalidateRect, 這樣會(huì)導(dǎo)致窗口后面會(huì)再次收到WM_PAINT消息, 最后窗口陷入WM_PAINT的死循環(huán)。 

            那么我們這里的問題窗口屬于哪類? 用什么方法可以判斷出來?

            注意到這里關(guān)鍵的三個(gè)API:BeginPaint, EndPaint, InvalidateRect的第一個(gè)參數(shù)都是窗口句柄, 我們可以通過WinDbg的API斷點(diǎn)來跟蹤執(zhí)行過程, Attach WinDbg到我們的主窗口進(jìn)程,比如我們的窗口句柄是0x209A0, 我們可以這樣設(shè)置API斷點(diǎn):
            bp USER32!NtUserInvalidateRect ".if(dwo(@esp+0x4)==0x209A0) {kv;gc} .else {gc}"
            bp USER32!NtUserBeginPaint ".if(dwo(@esp+0x4)==0x209A0) {kv;gc} .else {gc}"
            bp USER32!NtUserEndPaint ".if(dwo(@esp+0x4)==0x209A0) {kv;gc} .else {gc}"
            上面的條件斷點(diǎn)表示,當(dāng)調(diào)用我們的對(duì)應(yīng)的API,并且第一個(gè)參數(shù)(窗口句柄)是我們的目標(biāo)窗口時(shí),打印堆棧。

            很快我定位出Bug發(fā)生的原因了, 條件斷點(diǎn)顯示了API如下的調(diào)用次序:
            BeginPaint->InvalidateRect->InvalidateRect->EndPaint
            找到Bug的原因后,然后把Bug assign給該模塊的負(fù)責(zé)人。 (看我夠意思吧,不僅找到原因,還把調(diào)用棧都提供了)

            另外 ,后面還發(fā)現(xiàn)這個(gè)bug發(fā)生時(shí)窗口的某些行為會(huì)不對(duì), 測試發(fā)現(xiàn)原因是所有窗口的定時(shí)器都不能正常工作了。
            關(guān)于這個(gè)問題, 你能想到原因嗎? 

            如果想不到, 請(qǐng)把我的這篇博客《從點(diǎn)擊Button到彈出一個(gè)MessageBox, 背后發(fā)生了什么》看一遍。
            如果看了還想不到, 重點(diǎn)看第4條。

            最后, 簡單總結(jié)下:計(jì)算機(jī)的好處是它永遠(yuǎn)不會(huì)欺騙你, 它只會(huì)按部就班的執(zhí)行, 所以很多看似奇怪(甚至看似不可思議的問題), 只要你理解了程序背后的機(jī)制原理,都是可以找出根本原因的。
            posted on 2014-05-30 23:18 Richard Wei 閱讀(2674) 評(píng)論(2)  編輯 收藏 引用 所屬分類: windbg

            FeedBack:
            # re: 記一個(gè)界面刷新相關(guān)的Bug
            2014-06-04 09:59 | friv 3
            我將收藏此頁,并與他的幾個(gè)朋友一起分享,希望他們能有所幫助。感謝分享。
            http://www.friv3go.com  回復(fù)  更多評(píng)論
              
            # re: 記一個(gè)界面刷新相關(guān)的Bug
            2014-06-22 20:52 | 旗袍女裝
            所以很多看似奇怪(甚至看似不可思議的問題), 只要你理解了程序背后的機(jī)制原理,都是可以找出根本原因的。旗袍女裝www.ssnz88.net  回復(fù)  更多評(píng)論
              
            久久精品国产亚洲欧美| 国产69精品久久久久观看软件| 伊人久久大香线蕉影院95| 国产叼嘿久久精品久久| 一本久久a久久精品vr综合| 久久久久久狠狠丁香| 久久久久免费精品国产| 精品午夜久久福利大片| 久久婷婷人人澡人人爽人人爱| 99久久人妻无码精品系列| 亚洲综合久久久| 久久久精品人妻无码专区不卡| 中文字幕无码精品亚洲资源网久久| 久久国产乱子伦精品免费强| 久久成人国产精品免费软件| 精品多毛少妇人妻AV免费久久| 日韩乱码人妻无码中文字幕久久| 久久性生大片免费观看性| 久久99国产精品久久| 久久精品一本到99热免费| 性做久久久久久久久| 国产精品成人精品久久久| 久久99免费视频| 久久久免费精品re6| 亚洲AV日韩AV天堂久久| 色综合久久夜色精品国产| 久久人人爽人人澡人人高潮AV| 久久er热视频在这里精品| 久久国产色AV免费看| 一本色道久久综合亚洲精品| 久久久久亚洲AV片无码下载蜜桃| 久久精品无码av| 色综合久久88色综合天天 | 久久免费99精品国产自在现线 | 亚洲色欲久久久综合网| 国产免费久久精品99re丫y| 久久婷婷午色综合夜啪| 国产精品久久久久蜜芽| 久久99这里只有精品国产| 老男人久久青草av高清| 久久亚洲国产精品成人AV秋霞|