許多開發者在實作截圖功能時,直接複製單螢幕版本的代碼,發現在多顯示器環境下失效。其實,支援多顯示器並不需要複雜的 EnumDisplayMonitors 等 API,只需修正兩個核心點:裝置內容(DC)獲取方式 與 虛擬螢幕座標系計算。
| 場景 | API 呼叫 | 說明 |
|---|---|---|
| 單主螢幕 | hScrDC = CreateDC(_T("DISPLAY"), NULL, NULL, NULL); | 建立主顯示裝置的 DC |
| 多顯示器(虛擬螢幕) | hScrDC = ::GetDC(GetDesktopWindow()); | 獲取整個桌面視窗的 DC,涵蓋所有顯示器組成的虛擬螢幕 |
關鍵點: GetDesktopWindow() 返回的視窗跨越所有監視器,其 DC 即為「虛擬螢幕 DC」。
多顯示器環境下,桌面形成一個大的「虛擬螢幕」,原點 (0,0) 固定在主顯示器的左上角。副螢幕若在主螢幕左側或上方,其座標會是負值。
必須使用 GetSystemMetrics 的虛擬螢幕參數:
int cxVirtual = GetSystemMetrics(SM_CXVIRTUALSCREEN); // 虛擬螢幕總寬度
int cyVirtual = GetSystemMetrics(SM_CYVIRTUALSCREEN); // 虛擬螢幕總高度
int xVirtual = GetSystemMetrics(SM_XVIRTUALSCREEN); // 虛擬螢幕左上角 X(可能為負)
int yVirtual = GetSystemMetrics(SM_YVIRTUALSCREEN); // 虛擬螢幕左上角 Y(可能為負)
主螢幕 (0,0) ──────────────────► X
│
│ 副螢幕 (負座標)
▼
Y
錯誤假設: 以為邊界是 (0,0) → (cx, cy)。
正確邊界: (xVirtual, yVirtual) → (xVirtual + cxVirtual, yVirtual + cyVirtual)。
GetDC(GetDesktopWindow()) 取得虛擬螢幕 DC。SM_CXVIRTUALSCREEN 等指標取得完整範圍與原點。BitBlt 時,來源座標從 (xVirtual, yVirtual) 開始。ReleaseDC 對應 GetDC。若你手邊有單螢幕截圖代碼,只需修改以下三處即可支援多顯示器:
CreateDC("DISPLAY") → GetDC(GetDesktopWindow())SM_CXSCREEN → SM_CXVIRTUALSCREEN(0,0) → (SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN)多螢幕截圖其實很簡單,關鍵在於理解「虛擬螢幕」座標系與主螢幕原點的關係。別再被
EnumDisplayMonitors嚇倒了!