我正在修改现有的MFC应用程序以使用Win32 Application Desktop Toolbar API,而且我已经找到了一种解决方案,至少在Windows 10中是如此。但是,我看到的三种行为(在Windows的三个版本上)不能解释:
我的实现代码分为两个主要部分。第一个是用于输入/退出/修改窗口的当前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_NEW
或ABM_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轴的大小都为非零该消息,因此我希望这意味着保留已按预期进行。编辑:快速附录:PositionAppBar_
也用作处理ABN_POSCHANGED
消息类型的逻辑。