#pragma warning disable IDE1006 // Naming Styles // ReSharper disable UnusedMethodReturnValue.Global // ReSharper disable UnusedMember.Global using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using RGB.NET.Core; namespace RGB.NET.Devices.Razer.Native; // ReSharper disable once InconsistentNaming internal static class _RazerSDK { #region Libary Management private static nint _handle = 0; /// /// Reloads the SDK. /// internal static void Reload() { UnloadRazerSDK(); LoadRazerSDK(); } private static void LoadRazerSDK() { if (_handle != 0) return; List possiblePathList = GetPossibleLibraryPaths().ToList(); string? dllPath = possiblePathList.FirstOrDefault(File.Exists); if (dllPath == null) throw new RGBDeviceException($"Can't find the Razer-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'"); if (!NativeLibrary.TryLoad(dllPath, out _handle)) #if NET6_0 throw new RGBDeviceException($"Razer LoadLibrary failed with error code {Marshal.GetLastPInvokeError()}"); #else throw new RGBDeviceException($"Razer LoadLibrary failed with error code {Marshal.GetLastWin32Error()}"); #endif if (!NativeLibrary.TryGetExport(_handle, "Init", out _initPointer)) throw new RGBDeviceException("Failed to load Razer function 'Init'"); if (!NativeLibrary.TryGetExport(_handle, "UnInit", out _unInitPointer)) throw new RGBDeviceException("Failed to load Razer function 'UnInit'"); if (!NativeLibrary.TryGetExport(_handle, "QueryDevice", out _queryDevicePointer)) throw new RGBDeviceException("Failed to load Razer function 'QueryDevice'"); if (!NativeLibrary.TryGetExport(_handle, "CreateEffect", out _createEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateEffect'"); if (!NativeLibrary.TryGetExport(_handle, "CreateHeadsetEffect", out _createHeadsetEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateHeadsetEffect'"); if (!NativeLibrary.TryGetExport(_handle, "CreateChromaLinkEffect", out _createChromaLinkEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateChromaLinkEffect'"); if (!NativeLibrary.TryGetExport(_handle, "CreateKeyboardEffect", out _createKeyboardEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateKeyboardEffect'"); if (!NativeLibrary.TryGetExport(_handle, "CreateKeypadEffect", out _createKeypadEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateKeypadEffect'"); if (!NativeLibrary.TryGetExport(_handle, "CreateMouseEffect", out _createMouseEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateMouseEffect'"); if (!NativeLibrary.TryGetExport(_handle, "CreateMousepadEffect", out _createMousepadEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateMousepadEffect'"); if (!NativeLibrary.TryGetExport(_handle, "SetEffect", out _setEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'SetEffect'"); if (!NativeLibrary.TryGetExport(_handle, "DeleteEffect", out _deleteEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'DeleteEffect'"); } private static IEnumerable GetPossibleLibraryPaths() { IEnumerable possibleLibraryPaths; if (OperatingSystem.IsWindows()) possibleLibraryPaths = Environment.Is64BitProcess ? RazerDeviceProvider.PossibleX64NativePaths : RazerDeviceProvider.PossibleX86NativePaths; else possibleLibraryPaths = []; return possibleLibraryPaths.Select(Environment.ExpandEnvironmentVariables); } internal static void UnloadRazerSDK() { if (_handle == 0) return; _initPointer = 0; _unInitPointer = 0; _queryDevicePointer = 0; _createEffectPointer = 0; _createHeadsetEffectPointer = 0; _createChromaLinkEffectPointer = 0; _createKeyboardEffectPointer = 0; _createKeypadEffectPointer = 0; _createMouseEffectPointer = 0; _createMousepadEffectPointer = 0; _setEffectPointer = 0; _deleteEffectPointer = 0; NativeLibrary.Free(_handle); _handle = 0; } #endregion #region SDK-METHODS #region Pointers private static nint _initPointer; private static nint _unInitPointer; private static nint _queryDevicePointer; private static nint _createEffectPointer; private static nint _createHeadsetEffectPointer; private static nint _createChromaLinkEffectPointer; private static nint _createKeyboardEffectPointer; private static nint _createKeypadEffectPointer; private static nint _createMouseEffectPointer; private static nint _createMousepadEffectPointer; private static nint _setEffectPointer; private static nint _deleteEffectPointer; #endregion /// /// Razer-SDK: Initialize Chroma SDK. /// internal static unsafe RazerError Init() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_initPointer))(); /// /// Razer-SDK: UnInitialize Chroma SDK. /// internal static unsafe RazerError UnInit() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_unInitPointer))(); /// /// Razer-SDK: Query for device information. /// internal static unsafe RazerError QueryDevice(Guid deviceId, out _DeviceInfo deviceInfo) { int structSize = Marshal.SizeOf(typeof(_DeviceInfo)); nint deviceInfoPtr = Marshal.AllocHGlobal(structSize); RazerError error = ((delegate* unmanaged[Cdecl])ThrowIfZero(_queryDevicePointer))(deviceId, deviceInfoPtr); deviceInfo = (_DeviceInfo)Marshal.PtrToStructure(deviceInfoPtr, typeof(_DeviceInfo))!; Marshal.FreeHGlobal(deviceInfoPtr); return error; } internal static unsafe RazerError CreateEffect(Guid deviceId, int effectType, nint param, ref Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_createEffectPointer))(deviceId, effectType, param, ref effectId); internal static unsafe RazerError CreateHeadsetEffect(int effectType, nint param, ref Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_createHeadsetEffectPointer))(effectType, param, ref effectId); internal static unsafe RazerError CreateChromaLinkEffect(int effectType, nint param, ref Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_createChromaLinkEffectPointer))(effectType, param, ref effectId); internal static unsafe RazerError CreateKeyboardEffect(int effectType, nint param, ref Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_createKeyboardEffectPointer))(effectType, param, ref effectId); internal static unsafe RazerError CreateKeypadEffect(int effectType, nint param, ref Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_createKeypadEffectPointer))(effectType, param, ref effectId); internal static unsafe RazerError CreateMouseEffect(int effectType, nint param, ref Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_createMouseEffectPointer))(effectType, param, ref effectId); internal static unsafe RazerError CreateMousepadEffect(int effectType, nint param, ref Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_createMousepadEffectPointer))(effectType, param, ref effectId); internal static unsafe RazerError SetEffect(Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_setEffectPointer))(effectId); internal static unsafe RazerError DeleteEffect(Guid effectId) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_deleteEffectPointer))(effectId); private static nint ThrowIfZero(nint ptr) { if (ptr == 0) throw new RGBDeviceException("The Razer-SDK is not initialized."); return ptr; } #endregion }