mirror of https://github.com/dahall/Vanara.git
Added MessagePump and ExaminedMessagePump as means to process Get/PeekMessage->DispatchMessage loops.
parent
0b67042aed
commit
7bf4c15e50
|
@ -0,0 +1,105 @@
|
||||||
|
using static Vanara.PInvoke.User32;
|
||||||
|
|
||||||
|
namespace Vanara.PInvoke;
|
||||||
|
|
||||||
|
/// <summary>Delegate for a method that processes a <see cref="MSG"/> structure.</summary>
|
||||||
|
/// <param name="msg">The <see cref="MSG"/> structure to process.</param>
|
||||||
|
public delegate void MsgPumpDelegate(ref MSG msg);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for a method that processes a <see cref="MSG"/> structure and returns a value determining if the next step should be processed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msg">The <see cref="MSG"/> structure to process.</param>
|
||||||
|
/// <returns><see langword="true"/> if the pump should proceed; otherwise <see langword="false"/>.</returns>
|
||||||
|
public delegate bool MsgPumpPredicateDelegate(ref MSG msg);
|
||||||
|
|
||||||
|
/// <summary>Interface defining a message pump.</summary>
|
||||||
|
public interface IMessagePump
|
||||||
|
{
|
||||||
|
/// <summary>Runs the message pump on the optionally specified window.</summary>
|
||||||
|
/// <param name="mainWindow">The window instance.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The result of <see cref="PeekMessage(out MSG, HWND, uint, uint, PM)"/> or <see cref="GetMessage(out MSG, HWND, uint, uint)"/>.
|
||||||
|
/// </returns>
|
||||||
|
int Run(IWindowCore mainWindow = null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>A basic message pump to use independently or with a window instance.</summary>
|
||||||
|
/// <example>
|
||||||
|
/// Simple example of a window creation and message pump.
|
||||||
|
/// <code>using (var win = new BasicMessageWindow() { Text = "Title", Visible = true })
|
||||||
|
/// return new MessagePump().Run(win);</code></example>
|
||||||
|
/// <seealso cref="IMessagePump" />
|
||||||
|
public class MessagePump : IMessagePump
|
||||||
|
{
|
||||||
|
/// <summary>Easy access to WM_QUIT value.</summary>
|
||||||
|
protected const ushort quitMsg = (ushort)WindowMessage.WM_QUIT;
|
||||||
|
|
||||||
|
/// <inhertdoc/>
|
||||||
|
public int Run(IWindowCore mainWindow = null)
|
||||||
|
{
|
||||||
|
if (mainWindow is not null)
|
||||||
|
mainWindow.Destroyed += onDestroy;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return RunLoop();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (mainWindow is not null)
|
||||||
|
mainWindow.Destroyed -= onDestroy;
|
||||||
|
}
|
||||||
|
static void onDestroy() => PostQuitMessage(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Defines and executes the message pump.</summary>
|
||||||
|
/// <returns>
|
||||||
|
/// The result of <see cref="PeekMessage(out MSG, HWND, uint, uint, PM)"/> or <see cref="GetMessage(out MSG, HWND, uint, uint)"/>.
|
||||||
|
/// </returns>
|
||||||
|
protected virtual int RunLoop()
|
||||||
|
{
|
||||||
|
int bRet;
|
||||||
|
while ((bRet = GetMessage(out MSG msg)) != 0)
|
||||||
|
{
|
||||||
|
if (bRet == -1)
|
||||||
|
Win32Error.ThrowLastError();
|
||||||
|
TranslateMessage(msg);
|
||||||
|
DispatchMessage(msg);
|
||||||
|
}
|
||||||
|
return bRet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>A message pump with events to process each step to use independently or with a window instance.</summary>
|
||||||
|
/// <seealso cref="MessagePump"/>
|
||||||
|
public class ExaminedMessagePump : MessagePump
|
||||||
|
{
|
||||||
|
/// <summary>Occurs after <see cref="DispatchMessage(in MSG)"/>.</summary>
|
||||||
|
public event MsgPumpDelegate PostProcess;
|
||||||
|
|
||||||
|
/// <summary>Occurs after <see cref="TranslateMessage(in MSG)"/> and determines if message should be dispatched.</summary>
|
||||||
|
public event MsgPumpPredicateDelegate PostTranslate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs after <see cref="PeekMessage(out MSG, HWND, uint, uint, PM)"/> and determines if message should be translated or dispatched.
|
||||||
|
/// </summary>
|
||||||
|
public event MsgPumpPredicateDelegate PreProcess;
|
||||||
|
|
||||||
|
/// <inhertdoc/>
|
||||||
|
protected override int RunLoop()
|
||||||
|
{
|
||||||
|
MSG msg;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (PeekMessage(out msg, default, 0, 0, PM.PM_REMOVE) && (PreProcess?.Invoke(ref msg) ?? true))
|
||||||
|
{
|
||||||
|
TranslateMessage(msg);
|
||||||
|
if (PostTranslate?.Invoke(ref msg) ?? true)
|
||||||
|
DispatchMessage(msg);
|
||||||
|
PostProcess?.Invoke(ref msg);
|
||||||
|
}
|
||||||
|
} while (Macros.LOWORD(msg.message) != quitMsg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue