Replace DllImport
usage with LibraryImport
(#4084)
* Replace usage of `DllImport` with `LibraryImport` * Mark methods as `partial` * Marshalling * More `partial` & marshalling * More `partial` and marshalling * More partial and marshalling * Update GdiPlusHelper to LibraryImport * Unicorn * More Partial * Marshal * Specify EntryPoint * Specify EntryPoint * Change GlobalMemoryStatusEx to LibraryImport * Change RegisterClassEx to LibraryImport * Define EntryPoints * Update Ryujinx.Ava/Ui/Controls/Win32NativeInterop.cs Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com> * Update Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com> * Move return mashal * Remove calling convention specification * Remove calling conventions * Update Ryujinx.Common/SystemInfo/WindowsSystemInfo.cs Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com> * Update Ryujinx/Modules/Updater/Updater.cs Co-authored-by: Mary-nyan <thog@protonmail.com> * Update Ryujinx.Ava/Modules/Updater/Updater.cs Co-authored-by: Mary-nyan <thog@protonmail.com> Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com> Co-authored-by: Mary-nyan <thog@protonmail.com>
This commit is contained in:
parent
f4d731ae20
commit
0fbcd630bc
30 changed files with 308 additions and 299 deletions
35
Ryujinx.Common/SystemInterop/DisplaySleep.cs
Normal file
35
Ryujinx.Common/SystemInterop/DisplaySleep.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
public partial class DisplaySleep
|
||||
{
|
||||
[Flags]
|
||||
enum EXECUTION_STATE : uint
|
||||
{
|
||||
ES_CONTINUOUS = 0x80000000,
|
||||
ES_DISPLAY_REQUIRED = 0x00000002,
|
||||
ES_SYSTEM_REQUIRED = 0x00000001
|
||||
}
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
private static partial EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||
|
||||
static public void Prevent()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
static public void Restore()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
96
Ryujinx.Common/SystemInterop/ForceDpiAware.cs
Normal file
96
Ryujinx.Common/SystemInterop/ForceDpiAware.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
public static partial class ForceDpiAware
|
||||
{
|
||||
[LibraryImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static partial bool SetProcessDPIAware();
|
||||
|
||||
private const string X11LibraryName = "libX11.so.6";
|
||||
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial IntPtr XOpenDisplay([MarshalAs(UnmanagedType.LPStr)] string display);
|
||||
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial IntPtr XGetDefault(IntPtr display, [MarshalAs(UnmanagedType.LPStr)] string program, [MarshalAs(UnmanagedType.LPStr)] string option);
|
||||
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial int XDisplayWidth(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial int XDisplayWidthMM(IntPtr display, int screenNumber);
|
||||
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial int XCloseDisplay(IntPtr display);
|
||||
|
||||
private static readonly double _standardDpiScale = 96.0;
|
||||
private static readonly double _maxScaleFactor = 1.25;
|
||||
|
||||
/// <summary>
|
||||
/// Marks the application as DPI-Aware when running on the Windows operating system.
|
||||
/// </summary>
|
||||
public static void Windows()
|
||||
{
|
||||
// Make process DPI aware for proper window sizing on high-res screens.
|
||||
if (OperatingSystem.IsWindowsVersionAtLeast(6))
|
||||
{
|
||||
SetProcessDPIAware();
|
||||
}
|
||||
}
|
||||
|
||||
public static double GetActualScaleFactor()
|
||||
{
|
||||
double userDpiScale = 96.0;
|
||||
|
||||
try
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
userDpiScale = GdiPlusHelper.GetDpiX(IntPtr.Zero);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
string xdgSessionType = Environment.GetEnvironmentVariable("XDG_SESSION_TYPE")?.ToLower();
|
||||
|
||||
if (xdgSessionType == null || xdgSessionType == "x11")
|
||||
{
|
||||
IntPtr display = XOpenDisplay(null);
|
||||
string dpiString = Marshal.PtrToStringAnsi(XGetDefault(display, "Xft", "dpi"));
|
||||
if (dpiString == null || !double.TryParse(dpiString, NumberStyles.Any, CultureInfo.InvariantCulture, out userDpiScale))
|
||||
{
|
||||
userDpiScale = (double)XDisplayWidth(display, 0) * 25.4 / (double)XDisplayWidthMM(display, 0);
|
||||
}
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
else if (xdgSessionType == "wayland")
|
||||
{
|
||||
// TODO
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: Wayland not yet supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: Unrecognised XDG_SESSION_TYPE: {xdgSessionType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: {e.Message}");
|
||||
}
|
||||
|
||||
return userDpiScale;
|
||||
}
|
||||
|
||||
public static double GetWindowScaleFactor()
|
||||
{
|
||||
double userDpiScale = GetActualScaleFactor();
|
||||
|
||||
return Math.Min(userDpiScale / _standardDpiScale, _maxScaleFactor);
|
||||
}
|
||||
}
|
||||
}
|
76
Ryujinx.Common/SystemInterop/GdiPlusHelper.cs
Normal file
76
Ryujinx.Common/SystemInterop/GdiPlusHelper.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static partial class GdiPlusHelper
|
||||
{
|
||||
private const string LibraryName = "gdiplus.dll";
|
||||
|
||||
private static readonly IntPtr _initToken;
|
||||
|
||||
static GdiPlusHelper()
|
||||
{
|
||||
CheckStatus(GdiplusStartup(out _initToken, StartupInputEx.Default, out _));
|
||||
}
|
||||
|
||||
private static void CheckStatus(int gdiStatus)
|
||||
{
|
||||
if (gdiStatus != 0)
|
||||
{
|
||||
throw new Exception($"GDI Status Error: {gdiStatus}");
|
||||
}
|
||||
}
|
||||
|
||||
private struct StartupInputEx
|
||||
{
|
||||
public int GdiplusVersion;
|
||||
|
||||
#pragma warning disable CS0649
|
||||
public IntPtr DebugEventCallback;
|
||||
public int SuppressBackgroundThread;
|
||||
public int SuppressExternalCodecs;
|
||||
public int StartupParameters;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public static StartupInputEx Default => new StartupInputEx
|
||||
{
|
||||
// We assume Windows 8 and upper
|
||||
GdiplusVersion = 2,
|
||||
DebugEventCallback = IntPtr.Zero,
|
||||
SuppressBackgroundThread = 0,
|
||||
SuppressExternalCodecs = 0,
|
||||
StartupParameters = 0,
|
||||
};
|
||||
}
|
||||
|
||||
private struct StartupOutput
|
||||
{
|
||||
public IntPtr NotificationHook;
|
||||
public IntPtr NotificationUnhook;
|
||||
}
|
||||
|
||||
[LibraryImport(LibraryName)]
|
||||
private static partial int GdiplusStartup(out IntPtr token, in StartupInputEx input, out StartupOutput output);
|
||||
|
||||
[LibraryImport(LibraryName)]
|
||||
private static partial int GdipCreateFromHWND(IntPtr hwnd, out IntPtr graphics);
|
||||
|
||||
[LibraryImport(LibraryName)]
|
||||
private static partial int GdipDeleteGraphics(IntPtr graphics);
|
||||
|
||||
[LibraryImport(LibraryName)]
|
||||
private static partial int GdipGetDpiX(IntPtr graphics, out float dpi);
|
||||
|
||||
public static float GetDpiX(IntPtr hwnd)
|
||||
{
|
||||
CheckStatus(GdipCreateFromHWND(hwnd, out IntPtr graphicsHandle));
|
||||
CheckStatus(GdipGetDpiX(graphicsHandle, out float result));
|
||||
CheckStatus(GdipDeleteGraphics(graphicsHandle));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
114
Ryujinx.Common/SystemInterop/WindowsMultimediaTimerResolution.cs
Normal file
114
Ryujinx.Common/SystemInterop/WindowsMultimediaTimerResolution.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
/// <summary>
|
||||
/// Handle Windows Multimedia timer resolution.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("windows")]
|
||||
public partial class WindowsMultimediaTimerResolution : IDisposable
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TimeCaps
|
||||
{
|
||||
public uint wPeriodMin;
|
||||
public uint wPeriodMax;
|
||||
};
|
||||
|
||||
[LibraryImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
|
||||
private static partial uint TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
|
||||
|
||||
[LibraryImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
||||
private static partial uint TimeBeginPeriod(uint uMilliseconds);
|
||||
|
||||
[LibraryImport("winmm.dll", EntryPoint = "timeEndPeriod")]
|
||||
private static partial uint TimeEndPeriod(uint uMilliseconds);
|
||||
|
||||
private uint _targetResolutionInMilliseconds;
|
||||
private bool _isActive;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="WindowsMultimediaTimerResolution"/> and activate the given resolution.
|
||||
/// </summary>
|
||||
/// <param name="targetResolutionInMilliseconds"></param>
|
||||
public WindowsMultimediaTimerResolution(uint targetResolutionInMilliseconds)
|
||||
{
|
||||
_targetResolutionInMilliseconds = targetResolutionInMilliseconds;
|
||||
|
||||
EnsureResolutionSupport();
|
||||
Activate();
|
||||
}
|
||||
|
||||
private void EnsureResolutionSupport()
|
||||
{
|
||||
TimeCaps timeCaps = default;
|
||||
|
||||
uint result = TimeGetDevCaps(ref timeCaps, (uint)Unsafe.SizeOf<TimeCaps>());
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"timeGetDevCaps failed with result: {result}");
|
||||
}
|
||||
else
|
||||
{
|
||||
uint supportedTargetResolutionInMilliseconds = Math.Min(Math.Max(timeCaps.wPeriodMin, _targetResolutionInMilliseconds), timeCaps.wPeriodMax);
|
||||
|
||||
if (supportedTargetResolutionInMilliseconds != _targetResolutionInMilliseconds)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Target resolution isn't supported by OS, using closest resolution: {supportedTargetResolutionInMilliseconds}ms");
|
||||
|
||||
_targetResolutionInMilliseconds = supportedTargetResolutionInMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Activate()
|
||||
{
|
||||
uint result = TimeBeginPeriod(_targetResolutionInMilliseconds);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"timeBeginPeriod failed with result: {result}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_isActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Disable()
|
||||
{
|
||||
if (_isActive)
|
||||
{
|
||||
uint result = TimeEndPeriod(_targetResolutionInMilliseconds);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"timeEndPeriod failed with result: {result}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_isActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue