简体   繁体   English

是什么引起两个相等的后续SetWindowPos()调用来设置不同的窗口大小?

[英]What might cause two equal subsequent SetWindowPos() calls to set different window sizes?

As part of a project I'm working on, I'd like to highlight regions of the desktop. 作为我正在进行的项目的一部分,我想突出显示桌面区域。 Right now I implement this using a translucent red top level window, ie I 现在,我使用半透明的红色顶级窗口来实现此功能,即

  1. Create a custom window class with a red background brush. 用红色背景画笔创建一个自定义窗口类。
  2. Create a window of my custom class which has the WS_EX_LAYERED style set. 创建一个具有WS_EX_LAYERED样式集的自定义类的窗口。
  3. Call SetLayeredWindowAttributes to make the window 50% translucent. 调用SetLayeredWindowAttributes使窗口50%半透明。

It mostly works quite well, but I noticed a fairly peculiar interaction between my overlay window and the SetWindowPos function: when passing widths or heights to SetWindowPos which are smaller than 32 resp. 它通常工作得很好,但是我注意到覆盖窗口和SetWindowPos函数之间存在相当特殊的交互作用:将宽度或高度传递给小于32的SetWindowPos 39 pixels, the first call to SetWindowPos will actually make the window larger than requested but subsequent calls work as expected. 39像素,对SetWindowPos的第一次调用实际上会使窗口大于请求的大小,但随后的调用按预期工作。 Here's a small sample program which demonstrates the issue - it creates the overlay window in the top left corner of the desktop and then calls SetWindowPos twice with a one second delay. 这是一个演示该问题的小示例程序-它在桌面的左上角创建叠加窗口,然后以一秒钟的延迟两次调用SetWindowPos Notice how the red rectangle is first about square and then shrinks vertically. 注意红色矩形如何首先围绕正方形,然后垂直缩小。

#include <windows.h>

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    // Register custom class for overlay window, forcing red background
    WNDCLASSW overlayClassDef = {
        0,
        DefWindowProcW,
        0,
        0,
        hInstance,
        NULL,
        NULL,
        ::CreateSolidBrush( RGB( 255, 0, 0 ) ),
        NULL,
        L"Overlay_Window"
    };

    ATOM overlayClass = ::RegisterClassW( &overlayClassDef );

    // Create overlay window using 'layered' flag to enable making it
    // translucent
    HWND m_overlay = ::CreateWindowExW(
        WS_EX_LAYERED | WS_EX_NOACTIVATE,
        (LPCWSTR)overlayClass,
        NULL,
        0,
        0,
        0,
        0,
        0,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    // Strip WS_BORDER and WS_DLGFRAME styles to get perfectly flat window; these
    // styles appear to get added by default for toplevel windows.
    int windowStyle = ::GetWindowLongPtr( m_overlay, GWL_STYLE );
    windowStyle &= ~WS_BORDER;
    windowStyle &= ~WS_DLGFRAME;
    ::SetWindowLongPtr( m_overlay, GWL_STYLE, windowStyle );

    // Show the window and make it 50% translucent
    ::ShowWindow( m_overlay, SW_SHOWNA );
    ::SetLayeredWindowAttributes( m_overlay, 0, 127, LWA_ALPHA );

    // Set the position to 100/100 (50x20 pixels); the window on
    // screen becomes higher than 20 pixels though!
    ::SetWindowPos( m_overlay, HWND_TOPMOST, 100, 100, 50, 20, SWP_NOACTIVATE);
    ::Sleep( 1000 );

    // Set the position once more -- this time, the window shrinks
    // to 20 pixels vertically.
    ::SetWindowPos( m_overlay, HWND_TOPMOST, 100, 100, 50, 20, SWP_NOACTIVATE);
    ::Sleep( 1000 );

    // Releasing resources omitted for brevity
    return 0;
}

Some observations regarding this behaviour: 关于此行为的一些观察:

  1. The effect does not occur if either WS_BORDER or WS_DLGFRAME is set in the window flags; 如果在窗口标志中设置了WS_BORDERWS_DLGFRAME则不会发生这种情况。 however, I'd like to clear both flags to get a perfectly flat window. 但是,我想同时清除这两个标志才能获得完美的平面窗口。
  2. The effect does not seem to occur horizontally when using widths >= 32 pixels 当使用宽度> = 32像素时,效果似乎不会水平发生
  3. The effect does not seem to occur vertically when using heights >= 39 pixels 使用高度> = 39像素时,效果似乎不会垂直出现
  4. This can also be reproduced when not using a custom window class but rather instantiating the built-in STATIC class. 当不使用自定义窗口类而是实例化内置STATIC类时,也可以重现此内容。

Is there maybe a magic minimum window size close to 32 pixels which has to be treated specially? 是否有可能需要特别对待的接近32像素的魔术最小窗口大小?

After you update window style you need to make sure that window size and frame metrics get recalculated. 更新窗口样式后,需要确保重新计算窗口大小和框架度量。 In order to do so you need to manually call SetWindowPos with SWP_FRAMECHANGED flag right after updating visual style: 为此,您需要在更新视觉样式后立即使用SWP_FRAMECHANGED标志手动调用SetWindowPos

::SetWindowLongPtr( m_overlay, GWL_STYLE, windowStyle );
::SetWindowPos(m_overlay, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOREDRAW);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM