同步重绘窗口控件(使用阻塞方法)

7
我想做的是让一个控件(在同一进程中,但我无法控制它)重新绘制自己,并且我的代码会阻塞,直到它完成重绘。我尝试使用UpdateWindow,但似乎不等待重绘完成。我需要等待它完成重绘的原因是之后我想抓取屏幕。该控件不是dotNet控件,而是常规的Windows控件。我已确认以下内容:句柄正确;UpdateWindow返回true;在调用UpdateWindow之前尝试发送InvalidateRect(hWnd, IntPtr.Zero, true)以确保窗口需要无效化;尝试在控件的父窗口上执行相同的操作。使用的代码:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InvalidateRect(IntPtr hWnd, IntPtr rect, bool bErase);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateWindow(IntPtr hWnd);

public bool PaintWindow(IntPtr hWnd)
{
    InvalidateRect(hWnd, IntPtr.Zero, true);
    return UpdateWindow(hWnd);
}
//returns true

也许你可以在 WM_PAINT 情况下禁用渲染,然后再重新启用它。 - S.A.Parkhid
@S.A.Parkhid,您能详细说明一下吗? - Rotem
嗯...你觉得为什么_UpdateWindow似乎不等待重绘完成呢? - Nick Hill
1个回答

2
您可以使用Application.DoEvents强制应用程序处理所有排队的消息(包括WM_PAINT!)。就像这样:
public bool PaintWindow(IntPtr hWnd)
{
    InvalidateRect(hWnd, IntPtr.Zero, true);
    if (UpdateWindow(hWnd))
    {
        Application.DoEvents();
        return true;
    }

    return false;
}

但是,如果您要抓取屏幕,那么通过发送WM_PRINT消息一举两得不是更好吗?
您可以使用以下代码实现:
internal static class NativeWinAPI
{
    [Flags]
    internal enum DrawingOptions
    {
        PRF_CHECKVISIBLE = 0x01,
        PRF_NONCLIENT = 0x02,
        PRF_CLIENT = 0x04,
        PRF_ERASEBKGND = 0x08,
        PRF_CHILDREN = 0x10,
        PRF_OWNED = 0x20
    }

    internal const int WM_PRINT = 0x0317;

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg,
        IntPtr wParam, IntPtr lParam);
}

public static void TakeScreenshot(IntPtr hwnd, Graphics g)
{
    IntPtr hdc = IntPtr.Zero;
    try
    {
        hdc = g.GetHdc();

        NativeWinAPI.SendMessage(hwnd, NativeWinAPI.WM_PRINT, hdc,
            new IntPtr((int)(
                NativeWinAPI.DrawingOptions.PRF_CHILDREN |
                NativeWinAPI.DrawingOptions.PRF_CLIENT |
                NativeWinAPI.DrawingOptions.PRF_NONCLIENT |
                NativeWinAPI.DrawingOptions.PRF_OWNED
                ))
            );
    }
    finally
    {
        if (hdc != IntPtr.Zero)
            g.ReleaseHdc(hdc);
    }
}

谢谢,我会尝试一下并告诉你结果。 - Rotem
明天才能测试,我会尽快更新。 - Rotem
Application.DoEvents 工作正常,但 WM_PRINT 不幸地没有。感谢您的帮助! - Rotem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接