# 用 WinApi 進行視窗控制 - 學習J筆記 這禮拜挺有意思的,小弟我本業是 Android Engineer(我覺得我是啦 但是因為工作的內容是包專案的,還是跟硬體廠配合製作電腦系統、手持系統、網頁 Server,當然也包括 solution 跟整套流程的規畫參與 簡而言之就是新鮮的肝當然要多做點甚麼囉! 而且其實最近剛畢業(昨天畢業證書才寄出)我對自己的期許也是希望能夠在職場上多學一點,畢竟都沒要念研究所了 好了,廢話有點多,直接進到重點吧 ## 任務宗旨 這次要做的事情是在多螢幕之間操控視窗 有一台主控電腦,接 N 台螢幕,因為這次客戶是廠方,他們要求流道作業各自獨立顯示,這就意味著每台螢幕相距很遠,主控者也可能是不熟悉電腦操作的廠務人員,因此我們要幫他們做視窗自動歸位 而我這邊最後是出了兩個 Solution 1. 幫客戶把流程寫死 2. 做出另一個版本可以控制其中的參數(網址、螢幕位置...等 那這篇的內容就是針對我學到的東西、踩到的坑來做紀錄 ## 環境 這次因為是使用 WinApi 來做視窗指令 所以是寫 **C++** IDE 使用大二就卸載的 Dev C++... 至於為甚麼不用 VSCode、VS、VB呢? 前者是因沒辦法編譯出 .exe,後兩者是因為太大了我懶得載 單純寫個額外業務的小程式用 Dev C++ 或是 CodeBlock 都很夠了 ## Func 解說 我接下來要提到的 Func 都是網路上能找到教學的 所以我就簡短說明我用來幹嘛~ ### FindWindow() **FindWindow()** 主要是透過「視窗」的「類別」或是「視窗名稱」來找到視窗控制代碼(HWND) 視窗類別取得比較麻煩,需要透過一些工具,網上有使用VS的解法 視窗名稱取得比較簡單,只要你滑鼠放到工具列的視窗上面,小窗顯示出來的名字就是了,下圖就是 **Google - Google Chrome** ![](https://i.imgur.com/ZgPzwSR.png) 可以都寫,也可以不知道的欄位使用 NULL,如下: ```C++= HWND hwnd = FindWindow(NULL,"Google - Google Chrome"); ``` 這樣就可以使用視窗名稱找到控制代碼 其次,**FindWindow()** 在沒有找到對應視窗的時候會回傳 **NULL**,因此是個很好拿來判斷現在是否有我們需要的視窗,沒有的話我們便可以開一個 ### ShellExcute() **ShellExcute()** 本身是用來開啟外部程式檔的程式碼,在這邊我用它來開啟指定瀏覽器 我就直接上 code,詳細用法可以直接 Google "ShellExcute" ```C++= ShellExecute(0,0,"chrome.exe","www.google.com --new-window",0,SW_SHOW); ``` 參數 1 是針對使用的外部檔案有沒有要指定父視窗(HWND) 參數 2 是要開啟外部檔案的方式,可以不指定 參數 3 就是放你要開的檔案(想用其他瀏覽器就改這個) 參數 4 開啟檔案時的參數內容 參數 5 命令所在目錄 參數 6 執行時視窗型態 這邊比較需要注意的是參數4的部分,我將網址跟google指令都放在一起,因為我需要視窗是個別開啟,如果是想要開啟一個瀏覽器,然後很多分業的話可以這樣寫: ```C++= ShellExecute(0,0,"chrome.exe","www.google.com",0,SW_SHOW); ``` 使用預設瀏覽器的話: ```C++= ShellExecute(0,0,www.google.com",0,0,SW_SHOW); ``` 滿多可以研究的點,我自己踩得坑大概就是 "- -new-window" 這個指令我找很久吧哈哈 (後來是在 FB 發問才找到答案的 > 也有人建議我使用 Google Driver 來開啟瀏覽器,聽說彈性梗大,有興趣的人可以去試試看 ### MoveWindow() 找到視窗控制碼之後,就可以利用控制碼去移動視窗,用法非常簡單 **MoveWindow**(要移動的視窗,要去的位置(X),要去的位置(Y),視窗寬度,視窗高度,是否重繪) ```C++= MoveWindow(hwnd,500,500,800,800,false); ``` 像這樣的操作就是將控制碼 hwnd 的視窗移到 **(500,500)** 的地方;並且設定他的大小為 **800x800**;然後不重繪視窗 所以如果今天我有兩個螢幕,解析度都是 **1366x768** 的話,我想將A視窗從**螢幕1**移到**螢幕2**,就可以將座標設在 **(1380,50)** 那麼就會依據視窗的左上角去將視窗定位在第二個螢幕的 **(14,50)** ### ShowWindow() 其實看完上面好像覺得說我們的視窗不是這樣移動完就沒事了嗎? 但是並沒有那麼簡單,因為電腦的操作滿死的 #### 我的推斷 應該還是微軟在多螢幕之間的控制,視窗位置判讀還沒有做得很好。最近一直說要更新的 Win11 就打算要處理這方面的問題,所以我們再用 WinApi 去控制視窗的時候就要特別注意視窗的「狀態」 #### 我的觀察 一個視窗在「最大化」的狀態下,如果我將其利用 **MoveWindow()** 從**螢幕1**移動到**螢幕2**時,他會變得不可控、無法縮放。後來發現他的「最大化」狀態並沒有被取消,而且他的位置其實還是歸屬於**螢幕1** 會造成這個狀況的原因主要是 Windows 會一直依靠電腦的快取狀態去決定下一次開啟瀏覽器的時候應該是什麼狀態。 換言之,上次是「最大化」狀態時關閉的話,下次開起就很可能是「最大化」的視窗 #### 解決方法 就是使用 **ShowWindow()** 這個函式 (歡呼~~ **ShowWindow()** 可以幫助我們改變視窗的顯示模式,既然沒辦法在視窗最大化的時候移動,就將視窗變回正常模式就好了 ```C++= ShowWindow(hwnd,SW_RESTORE); ShowWindow(hwnd,9); ``` 在這邊使用 **SW_RESTORE/9** 當作參數的原因是這個參數會強制視窗解除「最大化」or「最小化」狀態,回到「還原」狀態 還原狀態之後就可以使用 **MoveWindow()** 移動視窗,然後再一次使用 **ShowWindow()** 將視窗最大化,全部的步驟就都可以自動化了~ 實現視窗最大化: ```C++= ShowWindow(hwnd,SW_MAXIMIZE); ShowWindow(hwnd,SW_SHOWMAXIMIZED); ShowWindow(hwnd,3); ``` ## 暫停 發現我寫到這邊就快下班了,這篇就到這,之後想寫更細節的東西我再補充到這篇。 但是因為還有 Solution & Rundown 的內容,所以我就留到下一篇寫吧~ 2021/07/15 ###### tags: `C++` `上工日誌` `WinApi``MIS`