<listing id="5x1tx"></listing>
    <track id="5x1tx"></track><pre id="5x1tx"></pre>
    <listing id="5x1tx"><strike id="5x1tx"></strike></listing>

      <del id="5x1tx"></del>

      <noframes id="5x1tx">

      <big id="5x1tx"></big>

      您的位置:首頁 >聚焦 >

      即時焦點:記一次有教益的焦點窗口查找過程—— 一定注意 spy++ 的這個坑

      2022-09-22 22:48:25    來源:程序員客棧
      緣起

      前一陣子,同事遇到了一個詭異的 bug,新版本發出來后之前運行好好的功能不好使了。原來的邏輯是:點擊板上某個埋件的時候,會彈出四個定位編輯框,其中的一個編輯框需要獲得焦點,方便用戶直接修改,按 tab會切換到下一個編輯框。但是新程序的行為發生了變化——點擊埋件的時候,四個編輯框沒有一個獲得焦點。本文記錄了使用 spyxx和 accevent.exe定位此問題的過程。

      初步調查

      同事演示了一下現象,大概現象如下:

      搶焦點

      可以發現,左側的編輯框先是獲得了焦點(獲得焦點的時候會選中全部文字),然后很快被搶走了。


      (相關資料圖)

      因為之前在開發其它功能時也遇到過焦點被命令編輯框(軟件底部中央的編輯框)搶走的情況,所以經過一定的觀察后,斷定跟上次是一樣的問題。由于之前遇到的那個問題是通過其它方式解決的,這次的問題不能用相同的方式解決,于是建議同事跟客戶反饋一下,讓平臺同事幫忙處理一下搶焦點的問題。

      再次調查

      過了一天,客戶那邊反饋可以使用某個命令禁止命令編輯框搶焦點。執行這個命令后,發現命令編輯框確實不搶焦點了,但是焦點還是會被搶走。

      跟同事了解完相關代碼邏輯后,找到了被搶走焦點的編輯框類。該類中包含一個響應函數 OnKillFocus(CWnd* pNewWnd)。從名字可以看出,該函數是處理失去焦點事件的,該函數只有一個參數,從名字看該參數是新獲得焦點的窗口對象指針。于是,果斷在這里設置斷點,并且設置中斷時輸出調試信息后繼續執行代碼。經過幾次觀察,可以發現,焦點總是被某個固定的窗口搶走。

      OnKillFocus

      既然焦點總被固定的窗口搶走,說明這個窗口是固定存在的,不是臨時窗口。既然是固定存在的窗口,就可以通過 spyxx查看到底是哪個窗口。但是當我在 spyxx中輸入這個窗口句柄時,卻怎么也找不到這個句柄對應的窗口!真是怪事!

      can-not-find-this-window 保存調用棧

      雖然沒能通過 spyxx找到對應的窗口,但是卻發現了一條非常有用的信息 —— 每次焦點都會被同一個窗口搶走。那么可以在 OnKillFocus()函數內部設置條件斷點,當 pNewWnd是特定值時才中斷。這樣就可以在目標編輯框失去焦點時中斷下來。中斷下來后,簡單查看調用棧,由于缺少調試符號,沒有發現什么有用信息。保存一份完整轉儲文件,后面可以發給平臺同事,讓他們幫忙查看具體原因。

      提示: 轉儲文件是程序某個時刻的快照。調試時保存轉儲文件個非常好的習慣,尤其是那種不輕易重現的問題。好不容易抓到一次,一定要先拍個照。防止調試器意外退出,追悔莫及。懂的都懂,對吧。

      其實,這個問題調查到這一步已經夠了。因為這個問題已經很明確了(焦點被其它窗口搶走了),而且外網沒有相關代碼,只能等平臺同事處理。但是,我特別好奇到底是哪個窗口把焦點搶走了,為什么在調試輸出中看到焦點每次都被同一個窗口搶走,但是在 spyxx中卻查不到這個窗口。

      繼續折騰

      之前做讀屏軟件開發的時候了解到,除了 spyxx,還有其它工具可以查看窗口信息。比如,可以通過 Inspect, UISpy, accevent等工具以追蹤焦點的方式自動獲取當前獲得焦點的窗口。但是,這次在使用這幾個工具的過程中,發現很大概率會導致主程序發生 StackOverflow異常(在這里浪費了很長時間)。最后發現,使用 accevent32,并且只監聽 OBJ_FOCUS事件的時候,不會發生異常。

      accevent32-setting

      按上圖設置好之后,點擊 OK按鈕,即可監聽焦點變化事件。終于抓到了這個偷搶焦點的窗口。

      accevent-watch-focused-window

      好像搶焦點的是主窗口?趕緊用 spyxx查看主窗口句柄,果然主窗口的句柄是 00541376,與使用 accevent捕獲到的窗口句柄是一樣的。

      這次,終于知道是哪個窗口搶走了焦點,但是為什么主窗口會搶焦點,還是需要平臺同事幫忙調查原因了。

      為什么 spyxx 找不到窗口

      為什么之前在 spyxx里輸入窗口句柄,但是卻找不到對應的窗口呢?在 vs輸出窗口中顯示的窗口句柄是 0x0000000000541376,在 spyxx中輸入的也是 0x0000000000541376,沒道理找不到。但是在 accevent里看到的窗口句柄是 00541376,難道在spyxx中輸入 00541376就可以查找到了?趕緊試試。

      find-window-by-spyxx

      果然,輸入 00541376是可以找到對應的窗口的。但是當我嘗試使用 0x00541376查找窗口時,卻無法找到匹配的窗口??磥?,在 spyxx中通過輸入句柄查找窗口時不能輸入 0x前綴。

      反思

      在整個過程中有一點做的特別不好:本來可以修改 OnKillFocus()函數中的代碼,多打印一些信息,比如獲取窗口范圍,窗口類名等信息。這樣就可以直接在代碼里定位到是哪個窗口搶走了焦點。但是根據之前的經驗,編譯一次比較耗時,所以潛意識里不想修改代碼,只是想著通過為斷點設置輸出信息的方式打印了一些輔助信息。

      總結

      Inspect, UISpy, accevent等工具也是一種可以查看窗口信息的工具,在某些情況下可能非常有用。

      在 spyxx中通過輸入窗口句柄查找窗口時不能輸入 0x前綴,否則會出現找不到窗口的情況。

      關鍵詞: 窗口句柄 獲得焦點 失去焦點

      相關閱讀

      女省委书记被征服
      <listing id="5x1tx"></listing>
        <track id="5x1tx"></track><pre id="5x1tx"></pre>
        <listing id="5x1tx"><strike id="5x1tx"></strike></listing>

          <del id="5x1tx"></del>

          <noframes id="5x1tx">

          <big id="5x1tx"></big>