windows 设置ROP2(R2_XORPEN)在win11下 Flink

ovfsdjhp  于 2023-01-21  发布在  Windows
关注(0)|答案(1)|浏览(223)

我有一个程序来绘制橡皮筋线,我使用经典XOR,在Win32 GDI,这是SetROP2(R2_XORPEN)方法,它在xp/vista/win7/win8/win10中工作,但最近,在我更新win11后,发现橡皮筋线变得 Flink 。这从来没有发生过,是win11的bug吗?如何修复?
我写了一个简单的demo程序,可以在win11下构建并运行,看到 Flink
注意:我知道处理WM_ERASEBKGND和使用双缓冲区可以避免窗口 Flink ,但这只是橡皮筋线 Flink ,而不是整个窗口。

#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <tchar.h>
    
 LRESULT CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM);
    
 int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                      _In_opt_ HINSTANCE hPrevInstance,
                      _In_ LPWSTR    lpCmdLine,
                      _In_ int       nCmdShow)
 {
     UNREFERENCED_PARAMETER(hPrevInstance);
     UNREFERENCED_PARAMETER(lpCmdLine);
    
     WNDCLASSEX wcex;
     wcex.cbSize = sizeof(WNDCLASSEX);
     wcex.style = CS_HREDRAW | CS_VREDRAW;
     wcex.lpfnWndProc = MyWndProc;
     wcex.cbClsExtra = 0;
     wcex.cbWndExtra = 0;
     wcex.hInstance = hInstance;
     wcex.hIcon = NULL;
     wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
     wcex.lpszMenuName = NULL;
     wcex.lpszClassName = _T("MyRubberBandLine");
     wcex.hIconSm = NULL;
     RegisterClassEx(&wcex);
    
     HWND hWnd = CreateWindow(_T("MyRubberBandLine"), _T("RubberBandLine"), WS_OVERLAPPEDWINDOW,
         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
    
     ShowWindow(hWnd, nCmdShow);
     UpdateWindow(hWnd);
    
     MSG msg;
     while (GetMessage(&msg, nullptr, 0, 0))
     {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }
    
     return (int) msg.wParam;
 }
    
 //
 //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
 //
 //  PURPOSE: Processes messages for the main window.
 //
 //  WM_COMMAND  - process the application menu
 //  WM_PAINT    - Paint the main window
 //  WM_DESTROY  - post a quit message and return
 //
 //
 LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     switch (message)
     {
     case WM_PAINT:
         {
             PAINTSTRUCT ps;
             HDC hdc = BeginPaint(hWnd, &ps);
    
             RECT rect;
             GetClientRect(hWnd, &rect);
             COLORREF clrbak = SetBkColor(hdc, RGB(255, 0, 0));
             ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
    
             int x = (rect.right - rect.left ) / 8;
             int y = (rect.bottom - rect.top) / 8;
             rect.left += x; rect.right -= x;
             rect.top += y; rect.bottom -= y;
             SetBkColor(hdc, RGB(0, 255, 0));
             ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
    
             rect.left += x; rect.right -= x;
             rect.top += y; rect.bottom -= y;
             SetBkColor(hdc, RGB(0, 0, 255));
             ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
    
             rect.left += x; rect.right -= x;
             rect.top += y; rect.bottom -= y;
             SetBkColor(hdc, RGB(0, 0, 0));
             ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
    
             SetBkColor(hdc, clrbak);
             EndPaint(hWnd, &ps);
         }
         break;
     case WM_DESTROY:
         PostQuitMessage(0);
         break;
     case WM_MOUSEMOVE:
         {
            static POINT ptPrev1{ -1,-1 };
            static POINT ptPrev2{ -1,-1 };
    
            HDC hdc = GetDC(hWnd);
            int modebak = SetROP2(hdc, R2_XORPEN);
    
            HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
            HGDIOBJ hOld = SelectObject(hdc, hPen);
    
            // erase prev line
            if (ptPrev1.x != -1 && ptPrev2.x != -1)
            {
                MoveToEx(hdc, ptPrev1.x, ptPrev1.y, NULL);
                LineTo(hdc, ptPrev2.x, ptPrev2.y);
                ptPrev1.x = ptPrev1.y = ptPrev2.x = ptPrev2.y = -1;
            }
    
            // draw new line
            RECT rect;
            GetClientRect(hWnd, &rect);
            POINT ptCenter{ (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 };
            POINT ptMouse{ LOWORD(lParam), HIWORD(lParam) };
            if ((ptMouse.x != ptCenter.x) || (ptMouse.y != ptCenter.y))
            {
                MoveToEx(hdc, ptCenter.x, ptCenter.y, NULL);
                LineTo(hdc, ptMouse.x, ptMouse.y);
    
                ptPrev1 = ptCenter;
                ptPrev2 = ptMouse;
            }
    
            SelectObject(hdc, hOld);
            SetROP2(hdc, modebak);
            ReleaseDC(hWnd, hdc);
            DeleteObject(hPen);
         }
         break;
     default:
         return DefWindowProc(hWnd, message, wParam, lParam);
     }
     return 0;
 }
bsxbgnwa

bsxbgnwa1#

你说的没错,用SetROP 2(hdc,R2_XORPEN)画线,其中hdc是窗口的设备上下文,一般会引起 Flink ,但在Windows 7和Windows 10下 Flink 几乎可以忽略不计,在Windows 11下 Flink 明显得多,不要在hdc中画,hdc是窗口的设备上下文,而是在兼容的内存设备上下文中画(hMemDC=CreateCompatibleDC(hdc);)和只是BitBlt(hdc,0,0...)hMemDC到hdc。你不会失去绘图速度和 Flink 是完全消除。

相关问题