把你的Windows任務欄移到屏幕的上方,你就會發現有多少程序會在啓動的時候,把自己的標題欄移到任務欄的下方,以至於不能用鼠標移動它,甚至有的窗口還沒有系統菜單(Atl + 空格 打開系統菜單,可以移動窗口)。所以,這篇文章我們來討論一下窗口的位置,以避免這樣的事情發生。
如果讓你寫個程序,要把窗口的位置移動到桌面的左上角,我想很多人都會寫出如下的代碼:
MoveWindow(hWnd,0,0,?,?);
後面?的位置如何填寫呢?很多人就會找到GetWindowRect函數來得到當前窗口的寬度。當然,這麼寫也不是不可以。我覺得更好的方式是使用SetWindowPos函數。MoveWindow函數有個很好的名字“移動窗口”,很多人都喜歡使用它,但是它還需要窗口的大小作為參數,來改變窗口的大小。那麼,SetWindowPos使用的人就不那麼多了,它需要更多參數(以至於很多人更傾向於使用MoveWindow),比MoveWindow更底層(MoveWindow內部其實調用的是SetWindowPos),但是功能更加強大。下面代碼,僅僅移動窗口:
SetWindowPos(hWnd,0,0,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
好了,以上説得都不是本文的重點。重點在於移動的座標(0,0),其實是錯的。無論是MoveWindow還是SetWindowPos,使用的座標系都是“桌面座標系”。那麼“桌面”包括哪些區域,任務欄包含在桌面裏面嗎?當然是的,任何窗口都直接或間接的是桌面的子窗口,任務欄是窗口當然是桌面的一部分。所以,在大部分情況下,把窗口移動到(0,0)是不會有問題的,除非你把任務欄移到屏幕的上方或左方(或者在屏幕的左方或上方有其它shell擴展的停靠窗口,比如:google desktop)。這時,桌面的(0,0)位置被任務欄佔據了,窗口移動到此處,必然會與任務欄重疊,而任務欄總在其它窗口的上方,所以你的窗口非常重要的標題欄被覆蓋掉了。
讓我們來看下面這張圖,當任務欄移動到屏幕上方時的桌面情況:
看了,這張圖就應該一目瞭然了。當要把窗口移動到左上角的時候,不應該是(0,0),而是找到WORKAREA的位置。調用SystemParametersInfo(SPI_GETWORKAREA,…)函數就會得到WORKAREA所在位置的RECT。請使用此RECT來決定,窗口的位置和大小,無論是把窗口移動到左上角或者是CenterWindow這樣的操作,這個RECT是非常重要的。
最後要提醒一下的是,並不是所有與窗口位置相關的函數都使用“桌面座標系”,據我所知SetWindowPlacement/GetWindowPlacement以及WM_GETMINMAXINFO消息,使用的就是WORKAREA座標系,也就是(0,0)位置是WORKAREA的左上角。