【发布时间】:2016-10-19 12:16:11
【问题描述】:
我正在研究一个旧版 (1999) 代码库,该代码库有一个烦人的错误,即当窗口放置在非主监视器上时,滚动某些 GUI 元素时无法正确重绘。
据我所知(对 Windows 的 API 不是很熟悉),问题是代码获取 DeviceContext 以使用 GetDC(hwnd) 绘制,我可以从文档中获得 DC 用于仅主监视器(但文档不是很清楚,TBH)。
我已经设法在屏幕上画了东西,基本上使用:
RECT rect;
GetWindowRect(hwnd, &rect);
HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY);
MONITORINFOEX minfo;
minfo.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &minfo);
HDC = CreateDC(NULL, minfo.szDevice, NULL, NULL);
这会将内容绘制到正确的监视器上,但应用程序显然需要与窗口相关的内容,因为所有内容最终都位于桌面的左上角而不是窗口中。
现在,我的谷歌搜索似乎表明使用 EnumDisplayMonitors(GetDC(), &rect, PaintCallback, NULL) 运行两次绘制代码应该是正确的。不幸的是,我的代码不是 C 或 C++。这是一个 SmallTalk 图像(并且支持在 15 年前左右就结束了,所以向供应商抱怨已经结束了),我只是不确定绘画处理是否发生在我可以访问的代码中,或者它是否足够深入我无法理解的 SmallTalk 的胆量。
因此我的问题是:是否可以创建一个与我的窗口客户区相关的 DC(也许通过从 CreateDC 调整 DC)?我意识到如果窗口跨越两个监视器,这可能会中断,但至少比当前状态要少。
更新:
我已经成功地使用EnumDisplayMonitors 运行了两次渲染代码,但是以奇怪的方式崩溃(这很可能是 SmallTalk 问题;编译器是旧的并且是特殊的,但是在堆栈深处调试代码是有问题)。
回答cmets:我认为代码基本上是想在windows上绘制,是的。代表各种 GUI 元素的 SmallTalk 对象带有用于创建带有GetDC(hwnd) 的 DC 的窗口句柄,所以这很容易。所以听起来GetDC(hwnd)应该得到一个做正确事情的 DC,在这种情况下;可能是 ST 代码在某处缓存 DC,GetDC 将在窗口移动到不同屏幕时返回不同的 DC(从我粗略的了解来看,这听起来似乎是合理的)。
【问题讨论】:
-
看起来你想在某个窗口上画画。使用
FindWindow获取窗口句柄,或使用 Visual Studio 中的 Spy++ 实用程序查找窗口句柄。创建 DC:HDC hdc = GetDC(hwnd),完成后调用ReleaseDC(hwnd, hdc)。但这当然是一种廉价的黑客攻击,您的图纸将很快被删除。为什么不通过创建自己的窗口来正确地做到这一点? -
我认为问题与 GetDC 本身无关。也许还有一些代码使用 GetClientRect/GetWindowRect 并且坐标是以某种方式相对于主屏幕获取的。