应用程序桌面工具栏:Win7 / 8.1上的ABM_SETPOS消息未保留桌面空间

时间:2018-07-26 21:22:47

标签: mfc windows-7 windows-10 windows-8.1 appbar

我正在修改现有的MFC应用程序以使用Win32 Application Desktop Toolbar API,而且我已经找到了一种解决方案,至少在Windows 10中是如此。但是,我看到的三种行为(在Windows的三个版本上)不能解释:

  1. 在Windows 7上,我的应用栏定位代码根本不会移动窗口。可以按预期应用进入/退出窗口的Appar模式的样式更改,但是窗口保留在原位,并且桌面工作区的大小保持不变。
  2. 在Windows 8上,应用栏的位置通常与预期的位置相同,但最终可能会重叠任务栏,并且也不会像我期望的那样在桌面上保留空间。
  3. 在Windows 10上,单个应用栏会按预期工作,但是尝试将两个应用栏固定到同一屏幕边缘只会为其中的一个保留桌面空间(尽管它们都正确放置)。

我的实现代码分为两个主要部分。第一个是用于输入/退出/修改窗口的当前AppBarState的函数,它是一个枚举(包装在带有一些辅助函数的类中),包含每个窗口边缘的值以及一个禁用状态:

static constexpr DWORD AppBarStyleModifications = WS_CAPTION | WS_SIZEBOX | WS_SYSMENU;

if (!AppBarState::IsActive(eState_) && AppBarState::IsActive(eDesiredState)) {
    ModifyStyle(AppBarStyleModifications, 0, SWP_FRAMECHANGED | SWP_NOREDRAW);
    UpdateRegistration_(true);
}

if (AppBarState::IsActive(eDesiredState))
    PositionAppBar_(eDesiredState);

if (AppBarState::IsActive(eState_) && !AppBarState::IsActive(eDesiredState)) {
    UpdateRegistration_(false);
    ModifyStyle(0, AppBarStyleModifications);
}

在此代码中,UpdateRegistration_函数是一个简单的辅助函数,用于根据需要发送ABM_NEWABM_REMOVE消息。实现的主要“要素”在PositionAppBar_中,它看起来像这样(删除了一些健全性检查和错误处理的空间):

APPBARDATA Data;
Data.cbSize = sizeof(APPBARDATA);
Data.hWnd = GetSafeHwnd();
Data.uCallbackMessage = APPBAR_CALLBACK;
Data.uEdge = AppBarState::ConvertToPositionCode(eDesiredState);
Data.rc = CRect(GetMonitorInfo(*this).rcMonitor).MulDiv(winx::GetDpiScalingPercent(), 100);

SHAppBarMessage(ABM_QUERYPOS, &Data);

CRect WindowRect;
DwmGetWindowAttribute(Data.hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &WindowRect, sizeof(RECT));
switch (eDesiredState) {
    case AppBarState::PinnedLeft:
        Data.rc.right = Data.rc.left + WindowRect.Width();
        break;
    case AppBarState::PinnedTop:
        Data.rc.bottom = Data.rc.top + WindowRect.Height();
        break;
    case AppBarState::PinnedRight:
        Data.rc.left = Data.rc.right - WindowRect.Width();
        break;
    case AppBarState::PinnedBottom:
        Data.rc.top = Data.rc.bottom - WindowRect.Height();
        break;
}

SHAppBarMessage(ABM_SETPOS, &Data);

const auto TargetRect = CRect(Data.rc).MulDiv(100, winx::GetDpiScalingPercent());
MoveWindow(TargetRect, FALSE);

在这里winx::GetDpiScalingPercent()(顾名思义)是一个辅助函数,用于确定设备像素和应用程序坐标之间的DPI缩放比例。

尽管始终欢迎您对这里可能存在的问题发表任何意见或建议,但我将尝试通过一些更具体的问题来限制此处的范围:

  • 是否需要多次发送ABM_QUERYPOS消息以获得正确的结果? This answer on another question似乎表明确实是(或至少是)这种情况,但是从我的测试来看,第二次发送消息后出现的矩形似乎是相同的。
  • 是否存在ABM_SETPOS不会保留空间的有效方案,如果可以,在这些方案中可以采取什么步骤?我在上面的示例代码中省略了此步骤,但是我正在验证SHAppBarMessage的返回值,并确保发送后Data.rc矩形的x轴和y轴的大小都为非零该消息,因此我希望这意味着保留已按预期进行。
  • 我在这里不解释的Windows版本之间的此API(或其实现)是否存在显着差异?除了上面的appbar blog post所链接的内容之外,我找不到太多的文档,在我看来,它应该在三个OS版本中都可以正常工作,但是实际行为并不能证明这一点。我看到了。

编辑:快速附录:PositionAppBar_也用作处理ABN_POSCHANGED消息类型的逻辑。

0 个答案:

没有答案