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);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void WaitOrTimerCallback(IntPtr lpParameter, bool timerOrWaitFired);
public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
public enum Cursor
@ -848,11 +851,25 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommand nCmdShow);
[DllImport("Winmm.dll")]
public static extern uint timeKillEvent(uint uTimerID);
[DllImport("kernel32.dll", SetLastError = true)]
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")]
public static extern uint timeSetEvent(uint uDelay, uint uResolution, TimeCallback lpTimeProc, UIntPtr dwUser, uint fuEvent);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool DeleteTimerQueueTimer(IntPtr TimerQueue, IntPtr Timer, IntPtr CompletionEvent);
[DllImport("user32.dll")]
public static extern int ToUnicode(
@ -972,9 +989,6 @@ namespace Avalonia.Win32.Interop
[return: MarshalAs(UnmanagedType.Bool)]
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)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "PostMessageW")]
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.Reactive.Disposables;
using System.Threading;
using Avalonia.Rendering;
using Avalonia.Win32.Interop;
@ -7,7 +8,21 @@ namespace Avalonia.Win32
{
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)
: base(framesPerSecond)
@ -16,23 +31,25 @@ namespace Avalonia.Win32
protected override IDisposable StartCore(Action<long> tick)
{
timerDelegate = (id, uMsg, user, dw1, dw2) =>
{
UnmanagedMethods.QueryPerformanceCounter(out long tickCount);
tick(tickCount);
};
EnsureTimerQueueCreated();
var msPerFrame = 1000 / FramesPerSecond;
timerDelegate = (_, __) => tick(TimeStampToFrames());
var handle = UnmanagedMethods.timeSetEvent(
(uint)(1000 / FramesPerSecond),
0,
UnmanagedMethods.CreateTimerQueueTimer(
out var timer,
_timerQueue,
timerDelegate,
UIntPtr.Zero,
1);
IntPtr.Zero,
(uint)msPerFrame,
(uint)msPerFrame,
0
);
return Disposable.Create(() =>
{
timerDelegate = null;
UnmanagedMethods.timeKillEvent(handle);
UnmanagedMethods.DeleteTimerQueueTimer(_timerQueue, timer, IntPtr.Zero);
});
}
}

Loading…
Cancel
Save