捕获屏幕的错误部分 [英] Capturing wrong part of the screen

查看:57
本文介绍了捕获屏幕的错误部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个小型演示应用程序,其窗口如下图所示:

I have created a small demo app which window looks as below:

当我运行此演示应用程序并按任意键时,我想捕获屏幕位图的一部分.

When I run this demo app, and press any key, I want to capture the part of the screen bitmap.

我感兴趣的屏幕部分是我的窗口所占据的部分,即窗口中包含字母的顶部矩形的内容.捕获的屏幕位图应如下所示:

The part of the screen I am interested in, is the one my window occupies, namely the content of the top rectangle in my window that holds letters. The captured screen bitmap should look like below:

我面临的问题是屏幕捕获代码捕获了屏幕的错误部分.

The problem I face is that screen capturing code captures wrong part of the screen.

下面是完整的代码(请记住,我试图将内容保持在最低限度):

Below is the full code (bare in mind that I tried to keep things as minimal as possible):

#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;
}

问题:

如何修正计算错误"(可能不是错误,可能是我误用了API?)与 MapWindowPoints ?

我忘了提到我有2台显示器.在第二台显示器上测试该应用程序后,一切正常.

I have forgotten to mention that I have 2 monitors. After testing the app on second monitor everything worked fine.

在对第一台显示器进行了设置之后,我发现它已设置为将文本,应用程序和其他项目缩放到150%.

After going through the settings for the first monitor, I have found out that it is set to scale text, apps and other items to 150%.

将其还原为100%可以使代码正常工作,但是现在我需要找到这种情况的解决方案,因为我可能不会强迫用户更改其设置.

Reverting it to 100% made the code work, but now I need to find a solution for this case, as I may not force users to change their settings.

任何帮助将不胜感激.

推荐答案

您不能强迫用户更改DPI,但可以要求Windows停止弄乱应用程序中的坐标.为此,请将清单文件包含在程序的主.exe中.您可能需要最高设置,true/pm和PerMonitorV2.

You can’t force user to change the DPI, but you can ask Windows to stop messing with the coordinates in your application. To do that, include manifest into the main .exe of your program. You probably need max. settings, true/pm and PerMonitorV2.

请参阅本文以获取更多信息.

这篇关于捕获屏幕的错误部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆