#if SELFTEST
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace TIASshot {
/// <summary>
/// UI スレッドのメッセージを回しながら待つ処理(SELFTEST 限定).
/// SelfTestRunner と TIASshot.Tests の共通ハーネス(層②)の両方から使う.
/// ワーカースレッドからの Control.Invoke(ShowMessage / EnableShots 等)やタイマーの Tick は
/// UI スレッドがメッセージを処理しないと実行されないため,Join や Sleep だけで待つと相互待機でハングする.
/// 必ずフォームを生成したスレッド(STA)から呼ぶこと.
/// </summary>
internal static class SelfTestPump {
// 1 回のメッセージ処理ごとの休止(ms)(CPU を占有しないため.応答性を損なわない短さにする)
private const int SleepMs = 2;
/// <summary>
/// 条件が成立するまでメッセージを処理して待つ.
/// </summary>
/// <param name="condition">成立を待つ条件(UI スレッドで評価する)</param>
/// <param name="timeout">待機の上限</param>
/// <param name="afterEachPump">メッセージ処理ごとに呼ぶ処理(null 可.UI 例外の再送出等に使う)</param>
/// <returns>上限内に成立したら true,タイムアウトしたら false</returns>
public static bool PumpUntil(Func<bool> condition, TimeSpan timeout, Action afterEachPump = null) {
var sw = Stopwatch.StartNew();
while (!condition()) {
if (sw.Elapsed > timeout) return false;
Application.DoEvents();
afterEachPump?.Invoke();
Thread.Sleep(SleepMs);
}
return true;
}
/// <summary>
/// 指定時間だけメッセージを処理し続ける(タイマー駆動の表示更新等を反映させるため).
/// </summary>
/// <param name="duration">処理し続ける時間</param>
/// <param name="afterEachPump">メッセージ処理ごとに呼ぶ処理(null 可)</param>
public static void PumpFor(TimeSpan duration, Action afterEachPump = null) {
var sw = Stopwatch.StartNew();
while (sw.Elapsed < duration) {
Application.DoEvents();
afterEachPump?.Invoke();
Thread.Sleep(SleepMs);
}
}
}
}
#endif