【问题标题】:Windows: Limit on how many regions a Window can have?Windows:一个 Window 可以有多少个区域的限制?
【发布时间】:2021-12-11 07:39:08
【问题描述】:

首先:对于区域,我指的不是那个窗口所针对的区域(地球上的位置),而是窗口区域:https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createrectrgn

操作系统:Windows 10
编码环境:C\Win32

要更改 Windows 中窗口的形状,可以使用 SetWindowRgn() 函数。作为它的第二个参数,它需要一个窗口区域 - 例如 - 使用上面的 CreateRectRgn 等等。

我正在使用此功能以每秒最多 10 次更新窗口的形状。
程序运行几秒钟后,SetWindowRgn 返回 0,这意味着出现问题。
我的第一个想法是,其中一个参数无效,但我会跟踪它们的状态(如果它们的状态有效,我会先检查 1 行):窗口句柄永远不会改变,据我所知,永远不会改变无效,直到窗口存在/正在关闭(它不/不是,即使它返回 0)。
区域句柄也不是无效的,因为我(第一次)检查它是否已初始化(要将一个区域与另一个区域组合,目标区域需要存在),然后(第二次)它是否为 NULL(它不是好),然后(第三)如果它是一个有效的句柄(它也是)。我还使用 GetLastError() 来检查是否设置了错误(不是)。第三个参数不会改变结果。

然后我想,也许,即使 Windows 文档说:

特别是不要删除这个区域句柄。当不再需要该区域句柄时,系统将其删除。

句柄没有被删除,并且未使用的句柄在内存中堆积:情​​况并非如此(我使用线程循环检查,检查 GetProcessHandleCount() 是否更改)

然后我开始计时整个事情,看看是否有一些一致性,一些事情,总是在 SetWindowRgn 返回 0 之前发生:时间并不总是相同,但我添加了一个变量来检查我有多少次使用 SetWindowRgn() 函数:对于那个特定的窗口,我在代码中总是准确地调用这个函数 4993,但是我确实有来自同一进程的 2 个其他 Windows,总而言之,这让我在代码中调用了这个 Windows 函数 4995 次。
想象一下,CreateWindow 函数也调用了这个函数,它可能是 4998 次调用。在那之后,该窗口的 SetWindowRgn() 失败。 (我不再将它用于其他 2 个窗口)。

整个事情目前在一个大线程中运行。我正在检查几乎每个 win32 调用,以查看是否发生错误(但有时我希望它会崩溃而不是:S)。

TL;DR:Windows 让我只使用了大约 5000 次 SetWindowRgn()

我的问题现在是:这是真的吗?使用该功能的频率是否有限制?可能所有其他区域都在图形设备上杂乱无章并且不会被清理,从而导致内存溢出? (也许以某种方式冲洗可能会有所帮助..)我只是解开了一个无证的硬编码限制吗?我该怎么做才能继续使用 SetWindowRgn()?

抱歉,如果有些事情仍然不清楚,我会澄清,如果你问:),也感谢你的时间和回答!

【问题讨论】:

  • 检查是否在使用后处理掉 GDI 元素。在 Windows 中,GDI 资源有限。 (见docs.microsoft.com/en-us/windows/win32/sysinfo/gdi-objects)。
  • 你有 GDI 泄漏,可能是HRGN,也可能不是。每个进程限制为 10,000 个 gdi 句柄。请发布最小可复制示例。
  • GetProcessHandleCount() 指的是内核句柄,而不是 GDI 句柄。正如其他人所说,这听起来像是 GDI 资源泄漏。您可以使用任务管理器(详细信息)窗格查看您的进程使用的 GDI 句柄数。
  • 你真的不应该再使用区域来塑造窗口,当分层 Windows 早在 Windows 2000 中引入时,这种用法就被弃用了。当你需要更新一个窗口的形状经常/多次。
  • 是的,根据任务管理器中的一些细节,这是一个GDI资源泄漏。有一次,我修复了泄漏,我会回答我的问题等等......再次感谢:)......我无法找到一种方法来使用分层窗口作为自己来制作奇怪形状的窗口。如果我要找到方法,我会确保使用它们。

标签: windows winapi window gdi


【解决方案1】:

正如问题下的 cmets 正确建议的那样:问题是 GDI 资源泄漏。我在任务管理器中检查了一些细节后注意到了这一点。正如 Barmark Shemirani 评论的那样:SetWindowRgn() 在正好 10000 个 GDI 对象之后开始失败。
检查List 上所有可能的对象很容易查明泄漏。

代码中的问题是:我忘记删除不同 CombineRgn() 函数的 2 个结果。现在,我添加了 2 个 DeleteObject() 函数调用,现在一切正常。

指出问题的功劳归评论者所有! :)

【讨论】:

    猜你喜欢
    • 2016-06-17
    • 2011-07-14
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    相关资源
    最近更新 更多