我目前正在開發一個需要在特定視窗截屏的專案。這就是我到目前為止得到的:
主功能
int main() {
LPCSTR windowname = "Calculator";
HWND handle = FindWindowA(NULL, windowname);
while (!handle) {
std::cout << "Process not found..." << std::endl;
handle = FindWindowA(NULL, windowname);
Sleep(100);
}
Mat img = captureScreenMat(handle);
resetMat();
imwrite("test2.jpg", img);
showInMovedWindow("IMG", img);
waitKey(0);
destroyAllWindows();
return 0;
}
贏捕獲
Mat src;
void showInMovedWindow(string winname, Mat img) {
namedWindow(winname);
moveWindow(winname, 40, 30);
imshow(winname, img);
}
BITMAPINFOHEADER createBitmapHeader(int width, int height)
{
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
bi.biHeight = -height;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
return bi;
}
int getHeight(HWND hwnd) {
RECT rect;
GetWindowRect(hwnd, &rect);
int height = rect.bottom - rect.top;
return height;
}
int getWidth(HWND hwnd) {
RECT rect;
GetWindowRect(hwnd, &rect);
int width = rect.right - rect.left;
return width;
}
Mat captureScreenMat(HWND hwnd)
{
HDC hwindowDC = GetDC(hwnd);
HDC hwindowCompatibleDC = CreateCompatibleDC(hwindowDC);
SetStretchBltMode(hwindowCompatibleDC, COLORONCOLOR);
int screenx = GetSystemMetrics(SM_XVIRTUALSCREEN);
int screeny = GetSystemMetrics(SM_YVIRTUALSCREEN);
int width = getWidth(hwnd);
int height = getHeight(hwnd);
src.create(height, width, CV_8UC4);
HBITMAP hbwindow = CreateCompatibleBitmap(hwindowDC, width, height);
BITMAPINFOHEADER bi = createBitmapHeader(width, height);
//DEBUG
cout << hbwindow << endl;
cout << hwindowCompatibleDC << endl;
cout << hwindowDC << endl;
SelectObject(hwindowCompatibleDC, hbwindow);
StretchBlt(hwindowCompatibleDC, 0, 0, width, height, hwindowDC, screenx, screeny, width, height, SRCCOPY);
GetDIBits(hwindowCompatibleDC, hbwindow, 0, height, src.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
DeleteObject(hbwindow);
DeleteDC(hwindowCompatibleDC);
DeleteDC(hwindowDC);
ReleaseDC(NULL, hwindowDC);
return src;
}
void resetMat() {
src.release();
}
大多數視窗都可以很好地使用這種方法,但是有些視窗是第一次作業的,我嘗試拍攝它們的 img,但每次我嘗試拍攝同一程序的另一個螢屏截圖時,它只是給了我第一個我截取的截圖。它僅在重新啟動該程序后才能再次起作用,即使那樣它也僅適用于一個螢屏截圖,并且之后的所有內容都是相同的。我認為這將是某種記憶體泄漏,但我正在洗掉所有物件并釋放句柄。我認為手柄有問題,但我無法弄清楚是什么。我不熟悉使用 windowsAPI,希望有人比我更了解。
固定:行程阻止創建句柄。
uj5u.com熱心網友回復:
當您呼叫時,SelectObject您必須保存先前選擇的句柄(可從回傳值獲得),并且您必須在洗掉或釋放設備背景關系之前將其選回。
現在你正在打破一堆規則。
- 洗掉選擇到設備背景關系中的位圖。
- 洗掉從
GetDC. - 在同一個句柄上同時
DeleteDC呼叫。ReleaseDC NULL作為 的第一個引數傳遞ReleaseDC,應該與HWND傳遞給的相同GetDC。- 洗掉 DC 而不將原始位圖選擇回其中。
這些錯誤嚴重地弄亂了視窗 DC。如果它是一個瞬態 DC,系統可能會立即清理你的爛攤子。但是,如果視窗類具有CS_OWNDCorCS_CLASSDC標志,則會對視窗造成永久性損壞。這就是為什么您的方法似乎適用于某些視窗而不適用于其他視窗的原因。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/415712.html
標籤:
