112 lines
3.0 KiB
C#
112 lines
3.0 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using Microsoft.Win32.SafeHandles;
|
|
|
|
namespace MxGateway.Worker.Sta;
|
|
|
|
public sealed class StaMessagePump
|
|
{
|
|
private const uint Infinite = 0xFFFFFFFF;
|
|
private const uint MsgWaitFailed = 0xFFFFFFFF;
|
|
private const uint MwmoInputAvailable = 0x0004;
|
|
private const uint PmRemove = 0x0001;
|
|
private const uint QsAllInput = 0x04FF;
|
|
|
|
public void WaitForWorkOrMessages(WaitHandle commandWakeEvent, TimeSpan timeout)
|
|
{
|
|
if (commandWakeEvent is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(commandWakeEvent));
|
|
}
|
|
|
|
uint timeoutMilliseconds = ToTimeoutMilliseconds(timeout);
|
|
|
|
SafeWaitHandle safeHandle = commandWakeEvent.SafeWaitHandle;
|
|
IntPtr[] handles = [safeHandle.DangerousGetHandle()];
|
|
uint result = MsgWaitForMultipleObjectsEx(
|
|
(uint)handles.Length,
|
|
handles,
|
|
timeoutMilliseconds,
|
|
QsAllInput,
|
|
MwmoInputAvailable);
|
|
|
|
if (result == MsgWaitFailed)
|
|
{
|
|
throw new InvalidOperationException(
|
|
"The worker STA message pump failed while waiting for command work or Windows messages.");
|
|
}
|
|
}
|
|
|
|
public int PumpPendingMessages()
|
|
{
|
|
int pumpedMessages = 0;
|
|
|
|
while (PeekMessage(out NativeMessage message, IntPtr.Zero, 0, 0, PmRemove))
|
|
{
|
|
TranslateMessage(ref message);
|
|
DispatchMessage(ref message);
|
|
pumpedMessages++;
|
|
}
|
|
|
|
return pumpedMessages;
|
|
}
|
|
|
|
private static uint ToTimeoutMilliseconds(TimeSpan timeout)
|
|
{
|
|
if (timeout == Timeout.InfiniteTimeSpan)
|
|
{
|
|
return Infinite;
|
|
}
|
|
|
|
if (timeout <= TimeSpan.Zero)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return timeout.TotalMilliseconds >= uint.MaxValue
|
|
? uint.MaxValue - 1
|
|
: (uint)Math.Ceiling(timeout.TotalMilliseconds);
|
|
}
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern uint MsgWaitForMultipleObjectsEx(
|
|
uint count,
|
|
IntPtr[] handles,
|
|
uint milliseconds,
|
|
uint wakeMask,
|
|
uint flags);
|
|
|
|
[DllImport("user32.dll", SetLastError = true)]
|
|
private static extern bool PeekMessage(
|
|
out NativeMessage message,
|
|
IntPtr windowHandle,
|
|
uint messageFilterMin,
|
|
uint messageFilterMax,
|
|
uint removeMessage);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool TranslateMessage(ref NativeMessage message);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern IntPtr DispatchMessage(ref NativeMessage message);
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct NativeMessage
|
|
{
|
|
public IntPtr WindowHandle;
|
|
public uint Message;
|
|
public UIntPtr WParam;
|
|
public IntPtr LParam;
|
|
public uint Time;
|
|
public NativePoint Point;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct NativePoint
|
|
{
|
|
public int X;
|
|
public int Y;
|
|
}
|
|
}
|