为方法增加一个超时等待

FindWindow 查找窗口直接执行可能窗口还没有准备好,返回结果必然是0。通常使用 Thread.Sleep 进行阻塞等待,是一种有效的手段。因计算机CPU运算效率差异,不能保证及时准确的得到想要的结果。所以有必要使用一个保证效率的基础上并可控的方式,下面是我的处理方式,代码使用 C# 编写,其他语言照葫芦画瓢。

TimeoutMonitor.cs

/// 
/// 超时监视器
/// 
public class TimeoutMonitor
{
    readonly int _tickCount;

    /// 
    /// 创建一个超时监视器
    /// 
    /// 超时时间(毫秒)
    public TimeoutMonitor(int timeout)
    {
        _tickCount = Environment.TickCount;
        Timeout = timeout;
    }

    /// 
    /// 超时时间(毫秒)
    /// 
    public int Timeout { get; }

    /// 
    /// 完成的
    /// 
    public bool IsCompleted => Environment.TickCount - _tickCount > Timeout;

    /// 
    /// 调用超时,如果超时将抛出 TimeoutException 错误
    /// 
    /// 错误描述
    public void ThrowIfTimeout(string error) => ThrowIfTimeout(error, 0);

    /// 
    /// 调用超时,如果超时将抛出 TimeoutException 错误
    /// 
    /// 错误描述
    /// 阻塞间隔(毫秒)
    public void ThrowIfTimeout(string error, int sleepTimeout)
    {
        if (IsCompleted) throw new TimeoutException(error);
        if (sleepTimeout > 0) Thread.Sleep(sleepTimeout);
    }

    /// 
    /// 根据条件调用超时,如果超时将抛出 TimeoutException 错误
    /// 
    /// 返回 true 时立即跳出后续
    /// 超时时间(毫秒)
    /// 错误描述
    public static void ThrowIfTimeout(Func func, int timeout, string error)
    {
        var tickCount = Environment.TickCount;
        while (Environment.TickCount - tickCount < timeout) if (func()) return;
        throw new TimeoutException(error);
    }

    /// 
    /// 等待超时退出
    /// 
    /// 返回 true 时立即跳出后续
    /// 超时时间(毫秒)
    /// 返回 true 未超时,反之 false 超时
    public static bool WaitTimeout(Func func, int timeout)
    {
        var tickCount = Environment.TickCount;
        while (Environment.TickCount - tickCount < timeout) if (func()) return true;
        return false;
    }
}

例子

可适用大多数非阻塞的方法:等待文件完全写入、等待窗口关闭……

FindWindowTimeout

在指定时间内一直 FindWindow 如果非 0 立即返回,到达指定时间后返回 0。

[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpszClass, string lpszWindow);

public static IntPtr FindWindowTimeout(string lpszClass, string lpszWindow, int timeout)
{
    var timeoutMonitor = new TimeoutMonitor(timeout);
    while (!timeoutMonitor.IsCompleted)
    {
        var hWnd = FindWindow(lpszClass, lpszWindow);
        if (hWnd != IntPtr.Zero) return hWnd;
    }
    return IntPtr.Zero;
}

等待文件完全写入

var fi = new FileInfo(@"C:\1.txt");
TimeoutMonitor.ThrowIfTimeout(() => fi.Exists && fi.Length > 0, 15000, "文件不存在");
var s = File.ReadAllText(fi.FullName);

等待窗口关闭

const int WM_CLOSE = 0x0010;

[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

[DllImport("user32.dll")]
static extern bool IsWindow(IntPtr hWnd);

public static bool WaitCloseWindow(IntPtr hWnd, int timeout)
{
    SendMessage(hWnd, WM_CLOSE, 0, 0);
    return TimeoutMonitor.WaitTimeout(() => !IsWindow(hWnd), timeout);
}

你可能感兴趣的:(为方法增加一个超时等待)