Winapi AnimateWindow()在高dpi(Win10)上错误地绘制背景
我正在创建一个简单的Win32/MFC应用程序,其中包含一个主窗口和一个子窗口,该子窗口使用Winapi AnimateWindow()在高dpi(Win10)上错误地绘制背景,winapi,mfc,windows-10,highdpi,animatewindow,Winapi,Mfc,Windows 10,Highdpi,Animatewindow,我正在创建一个简单的Win32/MFC应用程序,其中包含一个主窗口和一个子窗口,该子窗口使用AnimateWindow()来显示(向上滑动)和隐藏(向下滑动)窗口。当在100%dpi缩放上运行应用程序时,一切正常 我已经覆盖了WM_ERASEBKGND以呈现随机的红色,以演示效果。当窗口在动画的每个“步骤”上向下滑动(隐藏)时,背景的“更新矩形”被重新绘制,正好在子窗口消失的地方,背景将再次可见 但是,当通过Windows设置更改dpi缩放时(在本例中为125%),将重新绘制不正确的区域。看
AnimateWindow()
来显示(向上滑动)和隐藏(向下滑动)窗口。当在100%dpi缩放上运行应用程序时,一切正常
我已经覆盖了WM_ERASEBKGND以呈现随机的红色,以演示效果。当窗口在动画的每个“步骤”上向下滑动(隐藏)时,背景的“更新矩形”被重新绘制,正好在子窗口消失的地方,背景将再次可见
但是,当通过Windows设置更改dpi缩放时(在本例中为125%),将重新绘制不正确的区域。看起来好像传入OnEraseBkgnd()
的区域仍在使用100%dpi缩放大小,但位置也已关闭:看起来好像左上角的x/y位置是在屏幕空间而不是客户端空间中传递的。因此,重绘区域看起来不同,这取决于窗口在屏幕上的位置
白色区域是子窗口的实际位置,也是背景重画实际发生的位置
我已经在Win10(1803和1809)和Win8.1上确认了这种影响
这是操作系统中的一个bug,还是除了不使用AnimateWindow()
,我还能做些什么来避免这个问题<代码>显示窗口()(使用SW\u SHOW
或SW\u HIDE
)工作正常,顺便说一句
更新:添加完整的源代码以重现问题。
在使用完全不支持dpi的清单时会出现问题,但在使用true
我刚刚在Win7虚拟机上进行了快速测试<代码>动画窗口()可与dpi缩放一起正确工作!您是否可以创建并添加您为应用程序声明的DPI感知类型?当您将
CDialogEx
替换为CDialog
时,是否可以复制?这不是第一次出现此类错误。只需尝试使用CDialog
而不是CDialogEx
。同样的效果。问题出在AnimateWindow()中。这是一个执行动画的阻塞函数,在执行此操作时,它会生成有缺陷的WM_ERASEBKGND
消息,并传递错误的更新矩形。奇怪的是,我在应用程序中使用AnimateWindow
自定义下拉菜单,但我从未注意到这个问题。我猜无效的更新矩形无关紧要,因为DWM将每个窗口缓存在自己的纹理中,并且可以在不涉及应用程序的情况下重新绘制未覆盖的部分。因此,如果AnimateWindow
遗漏了一些部分,DWM将仅从纹理中绘制其余部分。我刚刚在Win7虚拟机中进行了快速测试<代码>动画窗口()可与dpi缩放一起正确工作!您是否可以创建并添加您为应用程序声明的DPI感知类型?当您将CDialogEx
替换为CDialog
时,是否可以复制?这不是第一次出现此类错误。只需尝试使用CDialog
而不是CDialogEx
。同样的效果。问题出在AnimateWindow()中。这是一个执行动画的阻塞函数,在执行此操作时,它会生成有缺陷的WM_ERASEBKGND
消息,并传递错误的更新矩形。奇怪的是,我在应用程序中使用AnimateWindow
自定义下拉菜单,但我从未注意到这个问题。我猜无效的更新矩形无关紧要,因为DWM将每个窗口缓存在自己的纹理中,并且可以在不涉及应用程序的情况下重新绘制未覆盖的部分。因此,如果AnimateWindow
遗漏了某些部分,DWM将仅从纹理中绘制其余部分。
class CDialogTestApp : public CWinApp
{
virtual BOOL InitInstance();
};
CDialogTestApp theApp;
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg() : CDialogEx(IDD_ABOUTBOX) {}
};
class CDialogTestDlg : public CDialogEx
{
public:
CDialogTestDlg(CWnd* pParent = nullptr) : CDialogEx(IDD_DIALOGTEST_DIALOG, pParent) {}
protected:
virtual BOOL OnInitDialog();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
private:
CAboutDlg mDialog;
};
BEGIN_MESSAGE_MAP(CDialogTestDlg, CDialogEx)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
BOOL CDialogTestApp::InitInstance()
{
CWinApp::InitInstance();
CDialogTestDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
return FALSE;
}
BOOL CDialogTestDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
mDialog.Create(IDD_ABOUTBOX, this);
return TRUE;
}
BOOL CDialogTestDlg::OnEraseBkgnd(CDC* pDC)
{
COLORREF color = RGB(rand() & 255, 20, 40);
CRect rect;
GetClipBox(pDC->m_hDC, &rect); // retrieve the update-rectangle
CBrush brush(color);
FillRect(pDC->m_hDC, &rect, (HBRUSH)brush.m_hObject);
return TRUE;
}
void CDialogTestDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
if (mDialog.IsWindowVisible())
{
mDialog.AnimateWindow(200, AW_HIDE | AW_SLIDE | AW_VER_POSITIVE);
}
else
{
mDialog.SetWindowPos(&CWnd::wndTop, 0, 50, 0, 0, SWP_NOSIZE);
mDialog.AnimateWindow(200, AW_ACTIVATE | AW_SLIDE | AW_VER_NEGATIVE);
}
CDialogEx::OnLButtonUp(nFlags, point);
}