我們的產品中嵌入了im子系統,其中包括類似QQ的截圖功能。之前截圖功能一直都是好好的,無論是在XP還是win7、win8中。但是這兩天,在公司大boss新用的Surface 3 Pro微軟平板上出現了異常,開啟截圖后截圖背景被放大了,導致截圖背景(即發起截圖時的桌面圖片)顯示不全了,這明顯是有問題的,大boss說了,必須要解決。大boss既然都下達指令了,只能將手頭的工作先放放,抓緊研究一下這個問題,盡快找到解決方法。
??????? 正常情況下,截圖背景是當前整個桌面的圖片,但是在win10中被放大后只能顯示一部分桌面,即桌面圖片顯示不全了。這是什么情況?想到QQ,于是拿過來對比了一下,QQ最新版本也有類似的問題,QQ好像對win10做了一些兼容性處理,但是處理的還是有些問題。QQ都有問題,我們也就似乎有理由向boss說明了,這可能是新的win10 UI新特性引起的,QQ都沒有解決,我們可能也不太好解決。但是測試同事就不同意了,大boss關注的問題必須要給個說法,要盡可能的解決掉,誰說QQ沒解決或者目前解決不了的問題,我們就可以不解決!于是乎,就只能靜下心來研究一下了。
??????? 經測試同事提醒,當前Surface平板上顯示比例調整為150%,默認的100%在平臺上顯示太小了,沒法用。顯示比例調整頁面,由于沒能在win10系統中截圖,以win7界面為例(本文中的相關截圖均以win7為例,可能和win10略有差別或者有所出入,關注者可以自行到win10中查看),如下:
在win10中,右鍵點擊桌面,在彈出的右鍵菜單中點擊“顯示比例”就能進入如上的顯示比例設置頁面了。win10以前的系統,都是通知通過改變dpi值來調整顯示比例的(可以通過Process Monitor工具檢測設置頁面設置時改寫的注冊表項來看出來),win10中則有所不同,在win10的注冊表中沒有和win7一樣的注冊表項,用Process Monitor也沒檢測到DPI相關的注冊表項。win10的顯示比例設置和win7還有一處不同,win10設置后立即生效,win7則提示用戶注銷后才能生效。當顯示比例設置為100%時,截圖沒有問題,但是設置到100%以上后,就有被放大的問題了。到底是Win10的什么新特性引起的呢?在網上搜了很久也沒找到相關問題的解決辦法,可能是win10才開始商用吧,這方面的問題報的比較少,但是無意間找到了一篇很有價值的文章,給了我很大的啟發:關于Windows高DPI的一些簡單總結,鏈接為:http://www.cppblog.com/weiym/archive/2014/02/18/205841.aspx。
??????? 其中,下面的這段話非常有用:通過?DWM 虛擬化支持的 高DPI方式,這種方式的高DPI支持是通過DWM的縮放實現的, 具體過程是這樣的, 比如我們當前系統的DPI是200%, 我們程序運行時,系統會告訴你當前DPI仍然是96(100%), 所以我們程序會仍然按照100%的方式進行繪畫, 但是但是系統給我們的坐標是根據DPI縮小過后的(也就是我們對窗口調用GetWindowRect或是通過GetSystemMetrics(SM_CXSCREEN)得到的大小會比實際大小減半) , 當我們畫完之后, DWM再對整個窗口進行200% 放大后畫到屏幕上, 這樣看起來我們的程序就自動支持高DPI了。通過在我們的截圖模塊中添加打印日志,GetWindowRect獲取的桌面窗口的寬度和高度,GetSystemMetrics獲取的屏幕寬度和高度(都是像素值),在顯示比例為200%時獲取的值,比在顯示比例為100%時要縮小一半,和上面的一段話的描述完全一致。
??????? 一般截圖的實現思路是,發起截圖時將此時整個桌面抓取下來,然后啟動一個全屏的對話框,然后將抓取的桌面圖片作為對話框背景貼到對話框上。應該是獲取桌面圖片的代碼出問題了,只獲取到了一部分桌面區域圖片。那么該如何處理才能將整個桌面的圖片都獲取到然后“全景”顯示出來呢?先來看背景圖的相關處理代碼。
獲取桌面尺寸的代碼:
[cpp] view plaincopy print?
RECT?rcDeskTop;??HWND?hWndDeskTop?=?::GetDesktopWindow();??:;GetWindowRect(?hWndDeskTop,?&rcDeskTop?);??
RECT rcDeskTop;HWND hWndDeskTop = ::GetDesktopWindow();:;GetWindowRect( hWndDeskTop, &rcDeskTop );
獲取屏幕寬度和高度的代碼:
[cpp] view plaincopy print?
m_xScreen?=?::GetSystemMetrics(?SM_CXSCREEN?);??m_yScreen?=?::GetSystemMetrics(?SM_CYSCREEN?);??
m_xScreen = ::GetSystemMetrics( SM_CXSCREEN );m_yScreen = ::GetSystemMetrics( SM_CYSCREEN );
拷貝桌面的代碼:
[cpp] view plaincopy print?
??HBITMAP?CCatchScreenDlg::CopyScreenToBitmap(?LPRECT?lpRect?)???{???????????????????????????????????????if?(?IsRectEmpty(?lpRect?)?)??????{??????????return?NULL;??????}????????????CString?strLog;????????HDC?hScrDC?=?::CreateDC(?_T("DISPLAY"),?NULL,?NULL,?NULL?);???????if?(?hScrDC?==?NULL?)??????{??????????strLog.Format(?_T("[CCatchScreenDlg::CopyScreenToBitmap]?創建DISPLAY失敗,?GetLastError:?%d"),???????????????GetLastError()?);??????????WriteScreenCatchLog(?strLog?);????????????return?NULL;??????}????????HDC?hMemDC?=?::CreateCompatibleDC(?hScrDC?);???????if?(?hMemDC?==?NULL?)??????{??????????strLog.Format(?_T("[CCatchScreenDlg::CopyScreenToBitmap]創建與hScrDC兼容的hMemDC失敗,?GetLastError:?%d"),???????????????GetLastError()?);??????????WriteScreenCatchLog(?strLog?);????????????::DeleteDC(?hScrDC?);??????????return?NULL;??????}????????int?nX?=?0;??????int?nY?=?0;??????int?nX2?=?0;??????int?nY2?=?0;?????????int?nWidth?=?0;???????int?nHeight?=?0;??????????????LONG?lTemp?=?0;??????if?(?lpRect->left?>?lpRect->right?)??????{??????????lTemp?=?lpRect->left;??????????lpRect->left?=?lpRect->right;??????????lpRect->right?=?lTemp;??????}??????if?(?lpRect->top?>?lpRect->bottom?)??????{??????????lTemp?=?lpRect->top;??????????lpRect->top?=?lpRect->bottom;??????????lpRect->bottom?=?lTemp;??????}??????????????????nX?=?lpRect->left;??????nY?=?lpRect->top;??????nX2?=?lpRect->right;??????nY2?=?lpRect->bottom;??????????????????if?(?nX?<?0?)??????{??????????nX?=?0;??????}????????if?(?nY?<?0?)??????{??????????nY?=?0;??????}????????if?(?nX2?>?m_xScreen?)??????{??????????nX2?=?m_xScreen;??????}????????if?(?nY2?>?m_yScreen?)??????{??????????nY2?=?m_yScreen;??????}????????nWidth?=?nX2?-?nX;??????nHeight?=?nY2?-?nY;????????????HBITMAP?hBitmap?=?::CreateCompatibleBitmap(?hScrDC,?nWidth,?nHeight?);???????if?(?hBitmap?==?NULL?)??????{??????????strLog.Format(?_T("[CCatchScreenDlg::CopyScreenToBitmap]創建與hScrDC兼容的Bitmap失敗,?GetLastError:?%d"),???????????????GetLastError()?);??????????WriteScreenCatchLog(?strLog?);????????????::DeleteDC(?hScrDC?);??????????::DeleteDC(?hMemDC?);??????????return?NULL;??????}????????::SelectObject(?hMemDC,?hBitmap?);??????????????BOOL?bRet?=?::BitBlt(?hMemDC,?0,?0,?nWidth,?nHeight,?hScrDC,?nX,?nY,?SRCCOPY?|?CAPTUREBLT?);????????if?(?!bRet?)??????{??????????strLog.Format(?_T("[CCatchScreenDlg::CopyScreenToBitmap]將hScrDC拷貝到hMemDC失敗,?GetLastError:?%d"),???????????????GetLastError()?);??????????WriteScreenCatchLog(?strLog?);????????????::DeleteDC(?hScrDC?);??????????::DeleteDC(?hMemDC?);??????????::DeleteObject(?hBitmap?);??????????return?NULL;??????}????????????if?(?hScrDC?!=?NULL?)??????{??????????::DeleteDC(?hScrDC?);??????}????????if?(?hMemDC?!=?NULL?)??????{??????????::DeleteDC(?hMemDC?);??????}????????return?hBitmap;???}??
// 拷貝桌面,lpRect 代表選定區域,bSave 標記是否將圖片內容保存到剪切板中
HBITMAP CCatchScreenDlg::CopyScreenToBitmap( LPRECT lpRect )
{ // 確保選定區域不為空矩形if ( IsRectEmpty( lpRect ) ){return NULL;}CString strLog;HDC hScrDC = ::CreateDC( _T("DISPLAY"), NULL, NULL, NULL ); // 為屏幕創建設備描述表if ( hScrDC == NULL ){strLog.Format( _T("[CCatchScreenDlg::CopyScreenToBitmap] 創建DISPLAY失敗, GetLastError: %d"), GetLastError() );WriteScreenCatchLog( strLog );return NULL;}HDC hMemDC = ::CreateCompatibleDC( hScrDC ); // 為屏幕設備描述表創建兼容的內存設備描述表if ( hMemDC == NULL ){strLog.Format( _T("[CCatchScreenDlg::CopyScreenToBitmap]創建與hScrDC兼容的hMemDC失敗, GetLastError: %d"), GetLastError() );WriteScreenCatchLog( strLog );::DeleteDC( hScrDC );return NULL;}int nX = 0;int nY = 0;int nX2 = 0;int nY2 = 0; int nWidth = 0; int nHeight = 0;// 保證left小于right,top小于bottomLONG lTemp = 0;if ( lpRect->left > lpRect->right ){lTemp = lpRect->left;lpRect->left = lpRect->right;lpRect->right = lTemp;}if ( lpRect->top > lpRect->bottom ){lTemp = lpRect->top;lpRect->top = lpRect->bottom;lpRect->bottom = lTemp;}// 獲得選定區域坐標nX = lpRect->left;nY = lpRect->top;nX2 = lpRect->right;nY2 = lpRect->bottom;// 確保選定區域是可見的if ( nX < 0 ){nX = 0;}if ( nY < 0 ){nY = 0;}if ( nX2 > m_xScreen ){nX2 = m_xScreen;}if ( nY2 > m_yScreen ){nY2 = m_yScreen;}nWidth = nX2 - nX;nHeight = nY2 - nY;HBITMAP hBitmap = ::CreateCompatibleBitmap( hScrDC, nWidth, nHeight ); // 創建一個與屏幕設備描述表兼容的位圖if ( hBitmap == NULL ){strLog.Format( _T("[CCatchScreenDlg::CopyScreenToBitmap]創建與hScrDC兼容的Bitmap失敗, GetLastError: %d"), GetLastError() );WriteScreenCatchLog( strLog );::DeleteDC( hScrDC );::DeleteDC( hMemDC );return NULL;}::SelectObject( hMemDC, hBitmap ); // 把新位圖選到內存設備描述表中BOOL bRet = ::BitBlt( hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY | CAPTUREBLT ); // CAPTUREBLT - 該參數保證能夠截到透明窗口if ( !bRet ){strLog.Format( _T("[CCatchScreenDlg::CopyScreenToBitmap]將hScrDC拷貝到hMemDC失敗, GetLastError: %d"), GetLastError() );WriteScreenCatchLog( strLog );::DeleteDC( hScrDC );::DeleteDC( hMemDC );::DeleteObject( hBitmap );return NULL;}if ( hScrDC != NULL ){::DeleteDC( hScrDC );}if ( hMemDC != NULL ){::DeleteDC( hMemDC );}return hBitmap; // hBitmap資源不能釋放,因為函數外部要使用
}
獲取桌面圖片調用該接口時,傳入的就是桌面區域的像素大小。函數內部的具體做法是,先獲取桌面DC,然后創建一個與桌面DC兼容的、桌面大小的內存位圖(通過位圖句柄來記錄并引用),然后調用BitBlt將桌面圖片拷貝到內存位圖上。win10中將顯示比例調到大于100%時遇到的問題,應該就是該BitBlt左右的代碼引起的。
后來又發現了一個很重要的線索,不管顯示比例比如何改變,當前的系統分辨率是不變的,還是之前設置的分辨率:
當顯示比例設置為100%時屏幕的寬度和高度就是當前系統設置的分辨率,當顯示比例大于100%時,比如為N%,DWM虛擬化會將GetWindowRect等獲取的像素尺寸縮小到分辨率的1/(N%),所以結合獲取的桌面圖片區域的比例情況,是不是可以考慮使用當前系統設置的分辨率寬度和高度來獲取整張桌面圖片,因為分辨率寬度和高度大于當前桌面的像素寬度和高度,所以在向內存中拷貝圖片時,需要選用StretchBlt,將圖片進行縮放,縮放到桌面的像素高度和寬度。經過試驗,這樣做確實是可行的,具體的做法是,先調用EnumDisplaySettings獲取當前系統設置的分辨率,然后判斷屏幕寬度是否小于分辨率,若小于就要換用StretchBlt進行縮放處理:
[cpp] view plaincopy print?
??HBITMAP?CCatchScreenDlg::CopyScreenToBitmap(?LPRECT?lpRect?)???{???????????????????????????????????????if?(?IsRectEmpty(?lpRect?)?)??????{??????????return?NULL;??????}????????CString?strLog;????????HWND?hWndDeskTop?=?::GetDesktopWindow();??????????????HDC?hScrDC?=?::GetDC(?hWndDeskTop?);???????if?(?hScrDC?==?NULL?)??????{??????????strLog.Format(?_T("[CCatchScreenDlg::CopyScreenToBitmap]?創建DISPLAY失敗,?GetLastError:?%d"),???????????????GetLastError()?);??????????WriteScreenCatchLog(?strLog?);????????????return?NULL;??????}????????HDC?hMemDC?=?::CreateCompatibleDC(?hScrDC?);???????if?(?hMemDC?==?NULL?)??????{??????????strLog.Format(?_T("[CCatchScreenDlg::CopyScreenToBitmap]創建與hScrDC兼容的hMemDC失敗,?GetLastError:?%d"),???????????????GetLastError()?);??????????WriteScreenCatchLog(?strLog?);????????????????????????::ReleaseDC(?hWndDeskTop,?hScrDC?);??????????return?NULL;??????}????????int?nX?=?0;??????int?nY?=?0;??????int?nX2?=?0;??????int?nY2?=?0;?????????int?nWidth?=?0;???????int?nHeight?=?0;??????????????CDirectRect?rc?=?*lpRect;??????rc.Normalize();??????????????nX?=?rc.left;??????nY?=?rc.top;??????nX2?=?rc.right;??????nY2?=?rc.bottom;??????????????if?(?nX?<?0?)??????{??????????nX?=?0;??????}????????if?(?nY?<?0?)??????{??????????nY?=?0;??????}????????if?(?nX2?>?m_xScreen?)??????{??????????nX2?=?m_xScreen;??????}????????if?(?nY2?>?m_yScreen?)??????{??????????nY2?=?m_yScreen;??????}????????nWidth?=?nX2?-?nX;??????nHeight?=?nY2?-?nY;????????HBITMAP?hBitmap?=?::CreateCompatibleBitmap(?hScrDC,?nWidth,?nHeight?);???????if?(?hBitmap?==?NULL?)??????{??????????strLog.Format(?_T("[CCatchScreenDlg::CopyScreenToBitmap]創建與hScrDC兼容的Bitmap失敗,?GetLastError:?%d"),???????????????GetLastError()?);??????????WriteScreenCatchLog(?strLog?);??????????????????????::ReleaseDC(?hWndDeskTop,?hScrDC?);??????????::DeleteDC(?hMemDC?);??????????return?NULL;??????}????????::SelectObject(?hMemDC,?hBitmap?);??????????BOOL?bRet?=?FALSE;??????BOOL?bProcessed?=?FALSE;????????????????????if?(?IsOSWin10()?&&?m_bWin10DpiScaleEnabled?)??????{??????????DEVMODE?curDevMode;??????????memset(?&curDevMode,?0,?sizeof(curDevMode)?);??????????curDevMode.dmSize?=?sizeof(DEVMODE);??????????BOOL?bEnumRet?=?::EnumDisplaySettings(?NULL,?ENUM_CURRENT_SETTINGS,?&curDevMode?);??????????if?(?bEnumRet?&&?m_xScreen?<?curDevMode.dmPelsWidth?)??????????{??????????????bProcessed?=?TRUE;??????????????::SetStretchBltMode(?hMemDC,?STRETCH_HALFTONE?);??????????????bRet?=?::StretchBlt(?hMemDC,?0,?0,?nWidth,?nHeight,?hScrDC,?0,?0,?curDevMode.dmPelsWidth,???????????????????curDevMode.dmPelsHeight,?SRCCOPY|CAPTUREBLT?);??????????}??????}????????if?(?!bProcessed?)??????{??????????bRet?=?::BitBlt(?hMemDC,?0,?0,?nWidth,?nHeight,?hScrDC,?nX,?nY,?SRCCOPY?|?CAPTUREBLT?);????????}????????if?(?!bRet?)??????{??????????strLog.Format(?_T("[CCatchScreenDlg::CopyScreenToBitmap]將hScrDC拷貝到hMemDC失敗,?GetLastError:?%d"),???????????????GetLastError()?);??????????WriteScreenCatchLog(?strLog?);??????????????????????::ReleaseDC(?hWndDeskTop,?hScrDC?);??????????::DeleteDC(?hMemDC?);??????????::DeleteObject(?hBitmap?);??????????return?NULL;??????}????????if?(?hScrDC?!=?NULL?)??????{????????????????????::ReleaseDC(?hWndDeskTop,?hScrDC?);??????}????????if?(?hMemDC?!=?NULL?)??????{??????????::DeleteDC(?hMemDC?);??????}????????return?hBitmap;???}??
// 拷貝桌面,lpRect 代表選定區域,bSave 標記是否將圖片內容保存到剪切板中
HBITMAP CCatchScreenDlg::CopyScreenToBitmap( LPRECT lpRect )
{ // 確保選定區域不為空矩形if ( IsRectEmpty( lpRect ) ){return NULL;}CString strLog;HWND hWndDeskTop = ::GetDesktopWindow();//HDC hScrDC = ::CreateDC( _T("DISPLAY"), NULL, NULL, NULL );HDC hScrDC = ::GetDC( hWndDeskTop ); // 為屏幕創建設備描述表if ( hScrDC == NULL ){strLog.Format( _T("[CCatchScreenDlg::CopyScreenToBitmap] 創建DISPLAY失敗, GetLastError: %d"), GetLastError() );WriteScreenCatchLog( strLog );return NULL;}HDC hMemDC = ::CreateCompatibleDC( hScrDC ); // 為屏幕設備描述表創建兼容的內存設備描述表if ( hMemDC == NULL ){strLog.Format( _T("[CCatchScreenDlg::CopyScreenToBitmap]創建與hScrDC兼容的hMemDC失敗, GetLastError: %d"), GetLastError() );WriteScreenCatchLog( strLog );//::DeleteDC( hScrDC );::ReleaseDC( hWndDeskTop, hScrDC );return NULL;}int nX = 0;int nY = 0;int nX2 = 0;int nY2 = 0; int nWidth = 0; int nHeight = 0;// 保證left小于right,top小于bottomCDirectRect rc = *lpRect;rc.Normalize();// 獲得選定區域坐標nX = rc.left;nY = rc.top;nX2 = rc.right;nY2 = rc.bottom;// 確保選定區域是可見的if ( nX < 0 ){nX = 0;}if ( nY < 0 ){nY = 0;}if ( nX2 > m_xScreen ){nX2 = m_xScreen;}if ( nY2 > m_yScreen ){nY2 = m_yScreen;}nWidth = nX2 - nX;nHeight = nY2 - nY;HBITMAP hBitmap = ::CreateCompatibleBitmap( hScrDC, nWidth, nHeight ); // 創建一個與屏幕設備描述表兼容的位圖if ( hBitmap == NULL ){strLog.Format( _T("[CCatchScreenDlg::CopyScreenToBitmap]創建與hScrDC兼容的Bitmap失敗, GetLastError: %d"), GetLastError() );WriteScreenCatchLog( strLog );//::DeleteDC( hScrDC );::ReleaseDC( hWndDeskTop, hScrDC );::DeleteDC( hMemDC );return NULL;}::SelectObject( hMemDC, hBitmap ); // 把新位圖選到內存設備描述表中BOOL bRet = FALSE;BOOL bProcessed = FALSE;// 針對win10 DWM虛擬縮放時的處理if ( IsOSWin10() && m_bWin10DpiScaleEnabled ){DEVMODE curDevMode;memset( &curDevMode, 0, sizeof(curDevMode) );curDevMode.dmSize = sizeof(DEVMODE);BOOL bEnumRet = ::EnumDisplaySettings( NULL, ENUM_CURRENT_SETTINGS, &curDevMode );if ( bEnumRet && m_xScreen < curDevMode.dmPelsWidth ){bProcessed = TRUE;::SetStretchBltMode( hMemDC, STRETCH_HALFTONE );bRet = ::StretchBlt( hMemDC, 0, 0, nWidth, nHeight, hScrDC, 0, 0, curDevMode.dmPelsWidth, curDevMode.dmPelsHeight, SRCCOPY|CAPTUREBLT );}}if ( !bProcessed ){bRet = ::BitBlt( hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY | CAPTUREBLT ); // CAPTUREBLT - 該參數保證能夠截到透明窗口}if ( !bRet ){strLog.Format( _T("[CCatchScreenDlg::CopyScreenToBitmap]將hScrDC拷貝到hMemDC失敗, GetLastError: %d"), GetLastError() );WriteScreenCatchLog( strLog );//::DeleteDC( hScrDC );::ReleaseDC( hWndDeskTop, hScrDC );::DeleteDC( hMemDC );::DeleteObject( hBitmap );return NULL;}if ( hScrDC != NULL ){//::DeleteDC( hScrDC );::ReleaseDC( hWndDeskTop, hScrDC );}if ( hMemDC != NULL ){::DeleteDC( hMemDC );}return hBitmap; // hBitmap資源不能釋放,因為函數外部要使用
}
經測試,可以達到我們預想的效果,桌面的整個區域都顯示出來了。但是有個小問題,在調用StrecthBlt時雖然設置了STRETCH_HALFTONE標記,但是還是有一定的失真,顯示桌面全貌的圖片,相對真實的桌面有點模糊,因為大圖片被縮小了。不過相對之前的放大問題,這個應該是可以忍受的。
?????? 上面的代碼還有一點需要注意,對于獲取系統版本,GetVersionEx API函數在win8和win10上基本上已經被逐步廢棄了,如果調用的話,獲取的將一直是win7的系統版本。要正確獲取系統版本,可以使用RtlGetNtVersionNumbers或者NetWkstaGetInfo函數,具體參見:http://blog.csdn.net/chenlycly/article/details/52881385。
??????? 另外,針對某個進程我們可以將DWM虛擬縮放禁用掉,這樣就不會有縮放引起的問題了。具體做法是,右鍵單擊目標進程exe文件或者其快捷方式,點擊屬性,在彈出的屬性窗口中,在“兼容性”標簽頁中,將“高DPI設置時禁用顯示縮放”勾選上就可以了,如下所示:(圖片是從win7中截圖的,可能和win10中略有不同)
當勾選上該選項后,該程序啟動后,窗口的大小始終固定為100%時的尺寸,不會隨著顯示比例的設置而變化。通過該方法,可以將截圖放大的問題規避掉,但是對于surface平板來說,是行不通的,因為100%時的窗口顯示太小,很難看清,所以需要按上面的辦法對截圖進行改造。
??????? 有人可能會問,我們能否通過代碼去判斷當前進程是否禁用了高DPI設置時的縮放呢?答案是肯定的。按經驗來看,應該將是否勾選對應的標記保存到注冊表中了,可以使用Process Monitor工具監測一下注冊表操作。具體的做法是,打開右鍵屬性,在任務管理器中查看屬于哪個進程,然后到Process Monitor中設置過濾條件,進程屬于資源管理器explorer.exe,注意由于該進程注冊表操作很頻繁,所以要抓的準確,容易看的出來一點,可以先將上面的屬性打開,然后開啟捕獲,然后快速勾選,然后點擊應用,然后到Process Monitor停止捕獲,這樣看到的捕獲結果會少一點,這樣更容易找到到底寫到哪個位置的注冊表中。經檢測,是保存到HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers中了,如下所示:
注意上圖是win7中的截圖,win10中的禁用標記和win7不一樣,因為我當前機器是win7的,之前沒有在win10上截圖,所以以win7系統來說明,一定要注意。那么從代碼角度如何判斷目標進程是否禁用了高DPI時的縮放了呢?其實很簡單,可以先獲取到目標進程的完整路徑,然后到注冊表HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers位置中,查看是否有對應的如上圖的設置選項,如果有,則說明禁了,如果沒有,則沒有禁用。至于Porcess Monitor工具如何獲取及如何使用請關注者自行百度。
??????? 最后,作為windows開發人員,要學會使用Process Explorer、Process Monitor、API Monitor、Process Hacker、Dependency Walker等工具。至于分析軟件異常,需要使用windbg和IDA等反匯編工具。
總結
以上是生活随笔為你收集整理的解决win10系统中截图异常放大的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。