[英]Capturing wrong part of the screen
我创建了一个小型演示应用程序,其中 window 如下所示:
当我运行这个演示应用程序并按任意键时,我想捕获屏幕 bitmap 的一部分。
我感兴趣的屏幕部分,是我的 window 占据的那个部分,即我的 window 中顶部矩形的内容,其中包含字母。 捕获的屏幕 bitmap 应如下所示:
我面临的问题是屏幕捕获代码捕获了错误的屏幕部分。
下面是完整的代码(请记住,我尽量保持最小化):
#include <Windows.h>
void foo(HWND hWnd)
{
HDC hdcScreen;
HDC hdcWindow;
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(hWnd);
RECT rcClient;
GetClientRect(hWnd, &rcClient);
// map window's client coordinates to screen coordinates
// HERE IS THE PROBLEM, SOMEHOW COORDINATES ARE NOT TRANSLATED CORRECTLY
// do not know how to fix this, but I am trying :(
RECT rc1 = rcClient;
MapWindowPoints(hWnd, NULL, (LPPOINT)&rc1, 2);
// capture desktop portion of the image
// that corresponds to the window's top rectangle (the one that has letters in it)
// and blit the result in the bottom rectangle
// so result can be visually compared
if (!BitBlt(hdcWindow,
rcClient.left + 50, // coordinates of the bottom rectangle
rcClient.top + 70, // sorry for the "magic numbers"
75, 35, // I am low on time :(
hdcScreen,
rc1.left + 50, // screen coordinates of the top rectangle
rc1.top + 20, // (the one that contains letters)
SRCCOPY))
{
OutputDebugString(L"StretchBlt has failed");
ReleaseDC(NULL, hdcScreen);
ReleaseDC(hWnd, hdcWindow);
return;
}
RECT rcBottomRect; // Frame again the bottom rectangle in the window,
rcBottomRect.left = rcClient.left + 50; // to make visual comparing easier
rcBottomRect.top = rcClient.top + 70; // and to verify that I didn't screw up
rcBottomRect.right = rcClient.left + 125; // the coordinates
rcBottomRect.bottom = rcClient.top + 105;
HBRUSH br = (HBRUSH)GetStockObject(BLACK_BRUSH);
FrameRect(hdcWindow, &rcBottomRect, br);
ReleaseDC(NULL, hdcScreen);
ReleaseDC(hWnd, hdcWindow);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYUP: // easiest handler to add that keeps things minimal
foo(hwnd); // capture screen
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rcClient;
GetClientRect(hwnd, &rcClient);
RECT rcTopRect;
rcTopRect.left = rcClient.left + 50;
rcTopRect.top = rcClient.top + 20;
rcTopRect.right = rcTopRect.left + 75;
rcTopRect.bottom = rcTopRect.top + 35;
HBRUSH br = (HBRUSH)GetStockObject(BLACK_BRUSH);
TextOut(hdc, 20, 30, L"Asdf ghj kkl oioio 4545 676767", ARRAYSIZE(L"Asdf ghj kkl oioio 4545 676767"));
FrameRect(hdc, &rcTopRect, br);
RECT rcBottomRect;
rcBottomRect.left = rcClient.left + 50;
rcBottomRect.top = rcClient.top + 70;
rcBottomRect.right = rcClient.left + 125;
rcBottomRect.bottom = rcClient.top + 105;
FrameRect(hdc, &rcBottomRect, br);
EndPaint(hwnd, &ps);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
// BOILERPLATE CODE...
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"myWindowClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"myWindowClass",
L"MVCE",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 170,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
如何使用 MapWindowPoints 修复计算“错误”(也许它不是错误,也许我误用了MapWindowPoints
?)?
我忘了提到我有 2 台显示器。 在第二台显示器上测试应用程序后,一切正常。
在完成第一台显示器的设置后,我发现它设置为将文本、应用程序和其他项目缩放到 150%。
将其恢复为 100% 使代码工作,但现在我需要为这种情况找到解决方案,因为我可能不会强迫用户更改他们的设置。
任何帮助,将不胜感激。
您不能强制用户更改 DPI,但您可以要求 Windows 停止在您的应用程序中弄乱坐标。 为此,请将清单包含在程序的 main.exe 中。 你可能需要最大。 设置,true/pm 和 PerMonitorV2。
有关更多信息, 请参阅本文。
MapWindowPoints的文档有点含糊,但它似乎确实需要相对于您的window的坐标,而不是您窗口的客户区(这是您给它的)。 这似乎可以解释这种症状,因为您的垂直偏移看起来与窗口标题栏的大小相同。 我一直使用ClientToScreen ,这更清楚。
DPI 缩放也可能是问题的根源,但它们通常不会仅出现在 y 轴上。 确保将您的应用程序标记为高 DPI 多显示器感知,以便系统不会在您背后进行任何缩放。 使用该设置,您可以在大部分时间使用 GDI 完成这项工作,但有一些限制。 (1)如果你的显示器有不同的缩放因子是非常困难的,并且(2)如果缩放因子在你的程序已经运行时动态改变,你可以得到通知,但是许多 API 仍然会告诉你之前的 DPI 设置改变。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.