在多个监视器上创建一个 window 相关的 DeviceContext

Creating a window-relative DeviceContext on multiple monitors

我正在处理旧版 (1999) 代码库,它有一个烦人的错误,当 window 放在非主监视器上时,某些 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);

这会将东西绘制到正确的监视器上,但应用程序显然需要 window 相关的东西,因为所有东西最终都在桌面的左上角而不是 window.

现在,我的谷歌搜索似乎表明 运行 使用 EnumDisplayMonitors(GetDC(), &rect, PaintCallback, NULL) 两次绘制代码应该做正确的事情。不幸的是,我的代码不是 C 或 C++。这是一个 SmallTalk 图像(并且支持在 15 年前左右结束,所以向供应商投诉是不可能的),我只是不确定绘画处理是否发生在我可以访问的代码中,或者它是否足够深入我无法使用的 SmallTalk 的核心内容。

因此我的问题是:是否可以创建一个与我的 window 客户区相关的 DC(也许通过从 CreateDC 调整 DC)?我意识到如果 window 跨越两个显示器,这可能会崩溃,但这至少比当前状态要好。

更新:

我已经设法运行渲染代码两次,使用EnumDisplayMonitors,但是以奇怪的方式崩溃(这很可能是一个 SmallTalk 问题;编译器是旧的和特殊的,但是调试堆栈深处的代码是有问题的)。

回复评论:我觉得代码基本上是想借鉴windows,是的。表示各种 GUI 元素的 SmallTalk 对象带有 window 句柄,这些句柄用于创建具有 GetDC(hwnd) 的 DC,所以这很容易。所以在这种情况下,听起来 GetDC(hwnd) 应该 得到一个做正确事情的 DC;可能是 ST 代码在某个地方缓存了 DC,当 window 移动到不同的屏幕时,GetDC 将 return 一个不同的 DC(根据我对此的粗略了解,这听起来很合理).

看起来问题确实出在 GetDC 创建的 DC 的缓存上。我破解了渲染代码以不使用缓存(或多或少,代码有点混乱),乍一看似乎成功​​了。

为了后代,如果有人用谷歌搜索 Visual Smalltalk Enterprise 并找到这个答案,我所做的是编辑 GraphicsTool>>ifNilHandle: 以不实际检查句柄是否为 nil,但总是 运行块以获取新句柄,最后 return true 。这样,每次都会获取新的 DC。

更新:

这解决了我试图解决的直接问题,但不幸的是破坏了其他一些东西(最值得注意的是 WindowBuilder Pro,GUI 构建工具包)。问题显然是代码中某处的 DC 缓存过于急切,但它需要以比上面的大锤方法更集中的方式修复。