【问题标题】:Paint Win32 window to file将 Win32 窗口绘制到文件
【发布时间】:2010-08-19 18:26:28
【问题描述】:

在 WPF 应用程序 (C#) 中,其中一个元素是 Win32 窗口,它是通过重写 HwndHost 类创建的。在任何给定时间,WPF 中大约有 10 个此 Win32 窗口的实例。一个应该完全渲染(工作正常),另外 9 个应该只显示预览,不创建 Win32 窗口,只是一个位图。

我一直在尝试找到生成所述位图的方法。尝试了很多不同的东西,但到目前为止没有任何效果。我遇到的主要问题是 HwndHost.WndProc 仅在窗口可见时才被调用。

我可以截取可见窗口的屏幕截图,将其渲染到内存并创建位图。我只需要在窗口不可见的情况下执行此操作。

我的理解仍然很模糊,所以任何见解都值得赞赏。

【问题讨论】:

  • 你是说 HwndHost.WndProc 只在窗口在屏幕上可见时才被调用,还是在窗口至少在屏幕上显示一次后才被调用?很可能直到第一次显示窗口时才创建窗口句柄。如果窗口(或其父窗口)在显示后被隐藏或最小化,您仍然应该在 wndproc 中收到消息。
  • 直到窗口第一次出现在屏幕上。是否可以在显示此窗口之前将其绘制到内存中?或者也许一种解决方法是在新窗口中生成 Show();隐藏();然后试着画?
  • 请在标签中留下诸如“C#”之类的标签,并将它们放在您的标题之外。这是多余的。
  • 是的,您可以在实际显示之前强制创建窗口句柄。访问窗口句柄属性应该足以强制创建句柄(这是一种按需模式)。在开始运行屏幕截图之前尝试读取 HwndHost.Handle。
  • 通过设置消息参数来模拟 WM_PAINT 消息 您需要创建一个内存 DC,其中包含位图并包含在 WM_PAINT 参数中。 SendMessage(HwndHost.Handle、WM_PAINT 等)

标签: c# .net wpf winapi


【解决方案1】:

您可以通过模拟 WM_PAINT 消息来强制窗口绘制位图。您需要设置一个内存 DC 并在其中选择目标位图,然后将该 DC 句柄作为 arg 传递到绘制消息中。详情请参阅MSDN docs

一旦 args 都准备好滚动,请执行 SendMessage(HwndHost.Handle、WM_PAINT 等)。当该调用返回时,位图应该包含窗口的图像。

请注意,要完全绘制整个窗口涉及许多消息。一般模式是:

  1. 使窗口的整个客户区无效。否则,将不会绘制任何内容,因为剪辑 rect 将为空。
  2. 在内存 DC 中设置内存位图
  3. 向窗口句柄发送 WM_ERASEBKGND 消息,传入内存 dc 句柄
  4. 向窗口句柄发送 WM_PAINT 消息,传入内存 dc 句柄

窗口的图像现在应该在内存位图中。

如果您还想捕获目标窗口的边框、窗口框架和窗口标题,则需要模拟非客户端绘制消息:WM_NCPAINT 是主要的,我想不到。

还有一个 WM_PRINT 消息,据说它有助于绘制到用于打印的内存 DC,但我在几个版本的 Windows 之前遇到了问题。子控件不自己绘制等。

【讨论】:

  • 谢谢,这是我昨晚开始的方向。现在读到这里,就更清楚了。很详细,非常感谢!
【解决方案2】:

You should not directly send a WM_PAINT message, as per MSDN spec. 从 Windows XP 开始,您可以使用 PrintWindow(),可能会使用设置了 RDW_INTERNALPAINT 标志的 RedrawWindow() 强制更新。

【讨论】:

    【解决方案3】:

    我不知道这在带有 WPF 的 C# 中是如何工作的,所以我将只为您提供 Windows API 的视角,并希望其中的一些能够引导您找到解决方案。

    所有的绘图都是在设备上下文 (DC) 中完成的。当 Windows 要求您绘制窗口时,它还允许您访问与窗口的可绘制表面相对应的 DC。

    要在没有窗口的情况下进行绘制,您需要创建自己的 DC,并且由于这些位不会进入窗口,因此您需要在 DC 中选择一个位图来保存结果。在 Windows API 中,您将使用 CreateCompatibleDCSelectObject。一旦你有了一个 DC,你就可以像往常一样在其中绘制,然后取消选择位图。

    【讨论】:

      【解决方案4】:

      研究“双缓冲”的图形技术。一旦你理解了这项技术——这并不难——你就会找到解决问题的方法。在我看来。 :-)

      链接:

      Win32 Double Buffering

      MSDN Double BufferingLots 'O 链接

      WinForms Double Buffering 通过 Google 找到 - 质量未知

      【讨论】:

        猜你喜欢
        • 2010-10-01
        • 1970-01-01
        • 2013-04-09
        • 1970-01-01
        • 2010-11-23
        • 1970-01-01
        • 2014-03-04
        • 2020-11-13
        • 1970-01-01
        相关资源
        最近更新 更多