Browse Source

Rewrite Win32 RenderTimer to use undeprecated APIs.

pull/1715/head
Jeremy Koritzinsky 8 years ago
parent
commit
87e98cacf9
  1. 28
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  2. 41
      src/Windows/Avalonia.Win32/RenderTimer.cs

28
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -26,6 +26,9 @@ namespace Avalonia.Win32.Interop
public delegate void TimeCallback(uint uTimerID, uint uMsg, UIntPtr dwUser, UIntPtr dw1, UIntPtr dw2); public delegate void TimeCallback(uint uTimerID, uint uMsg, UIntPtr dwUser, UIntPtr dw1, UIntPtr dw2);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void WaitOrTimerCallback(IntPtr lpParameter, bool timerOrWaitFired);
public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
public enum Cursor public enum Cursor
@ -848,11 +851,25 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommand nCmdShow); public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommand nCmdShow);
[DllImport("Winmm.dll")] [DllImport("kernel32.dll", SetLastError = true)]
public static extern uint timeKillEvent(uint uTimerID); public static extern IntPtr CreateTimerQueue();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool DeleteTimerQueueEx(IntPtr TimerQueue, IntPtr CompletionEvent);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateTimerQueueTimer(
out IntPtr phNewTimer,
IntPtr TimerQueue,
WaitOrTimerCallback Callback,
IntPtr Parameter,
uint DueTime,
uint Period,
uint Flags);
[DllImport("Winmm.dll")] [DllImport("kernel32.dll", SetLastError = true)]
public static extern uint timeSetEvent(uint uDelay, uint uResolution, TimeCallback lpTimeProc, UIntPtr dwUser, uint fuEvent); public static extern bool DeleteTimerQueueTimer(IntPtr TimerQueue, IntPtr Timer, IntPtr CompletionEvent);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern int ToUnicode( public static extern int ToUnicode(
@ -972,9 +989,6 @@ namespace Avalonia.Win32.Interop
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorInfo([In] IntPtr hMonitor, [Out] MONITORINFO lpmi); public static extern bool GetMonitorInfo([In] IntPtr hMonitor, [Out] MONITORINFO lpmi);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "PostMessageW")] [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "PostMessageW")]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

41
src/Windows/Avalonia.Win32/RenderTimer.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Threading;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
@ -7,7 +8,21 @@ namespace Avalonia.Win32
{ {
internal class RenderTimer : DefaultRenderTimer internal class RenderTimer : DefaultRenderTimer
{ {
private UnmanagedMethods.TimeCallback timerDelegate; private UnmanagedMethods.WaitOrTimerCallback timerDelegate;
private static IntPtr _timerQueue;
private static void EnsureTimerQueueCreated()
{
if (Volatile.Read(ref _timerQueue) == null)
{
var queue = UnmanagedMethods.CreateTimerQueue();
if (Interlocked.CompareExchange(ref _timerQueue, queue, IntPtr.Zero) != IntPtr.Zero)
{
UnmanagedMethods.DeleteTimerQueueEx(queue, IntPtr.Zero);
}
}
}
public RenderTimer(int framesPerSecond) public RenderTimer(int framesPerSecond)
: base(framesPerSecond) : base(framesPerSecond)
@ -16,23 +31,25 @@ namespace Avalonia.Win32
protected override IDisposable StartCore(Action<long> tick) protected override IDisposable StartCore(Action<long> tick)
{ {
timerDelegate = (id, uMsg, user, dw1, dw2) => EnsureTimerQueueCreated();
{ var msPerFrame = 1000 / FramesPerSecond;
UnmanagedMethods.QueryPerformanceCounter(out long tickCount);
tick(tickCount); timerDelegate = (_, __) => tick(TimeStampToFrames());
};
var handle = UnmanagedMethods.timeSetEvent( UnmanagedMethods.CreateTimerQueueTimer(
(uint)(1000 / FramesPerSecond), out var timer,
0, _timerQueue,
timerDelegate, timerDelegate,
UIntPtr.Zero, IntPtr.Zero,
1); (uint)msPerFrame,
(uint)msPerFrame,
0
);
return Disposable.Create(() => return Disposable.Create(() =>
{ {
timerDelegate = null; timerDelegate = null;
UnmanagedMethods.timeKillEvent(handle); UnmanagedMethods.DeleteTimerQueueTimer(_timerQueue, timer, IntPtr.Zero);
}); });
} }
} }

Loading…
Cancel
Save