diff --git a/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs b/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs index 4679cb9..a9d6f54 100644 --- a/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs +++ b/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs @@ -23,7 +23,7 @@ public class WootingUpdateQueue : UpdateQueue public WootingUpdateQueue(IDeviceUpdateTrigger updateTrigger, byte deviceId) : base(updateTrigger) { - _deviceid = deviceId; + this._deviceid = deviceId; } #endregion diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs index 451c6b2..502927a 100644 --- a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs +++ b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs @@ -56,5 +56,6 @@ public class WootingKeyboardRGBDevice : WootingRGBDevice possiblePathList = (Environment.Is64BitProcess ? WootingDeviceProvider.PossibleX64NativePaths : WootingDeviceProvider.PossibleX86NativePaths) - .Select(Environment.ExpandEnvironmentVariables) - .ToList(); + List possiblePathList = GetPossibleLibraryPaths().ToList(); + string? dllPath = possiblePathList.FirstOrDefault(File.Exists); if (dllPath == null) throw new RGBDeviceException($"Can't find the Wooting-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'"); - - _handle = NativeLibrary.Load(dllPath); - if (_handle == IntPtr.Zero) throw new RGBDeviceException($"Wooting LoadLibrary failed with error code {Marshal.GetLastWin32Error()}"); - - _getDeviceInfoPointer = (GetDeviceInfoPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_device_info"), typeof(GetDeviceInfoPointer)); - _keyboardConnectedPointer = (KeyboardConnectedPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_kbd_connected"), typeof(KeyboardConnectedPointer)); - _resetPointer = (ResetPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_reset_rgb"), typeof(ResetPointer)); - _closePointer = (ClosePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_close"), typeof(ClosePointer)); - _arrayUpdateKeyboardPointer = (ArrayUpdateKeyboardPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_array_update_keyboard"), typeof(ArrayUpdateKeyboardPointer)); - _arraySetSinglePointer = (ArraySetSinglePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_array_set_single"), typeof(ArraySetSinglePointer)); - _getDeviceCountPointer = (GetDeviceCountPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_usb_keyboard_count"), typeof(GetDeviceCountPointer)); - _selectDevicePointer = (SelectDevicePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_usb_select_device"), typeof(SelectDevicePointer)); + if (!NativeLibrary.TryLoad(dllPath, out _handle)) throw new RGBDeviceException($"Wooting LoadLibrary failed with error code {Marshal.GetLastWin32Error()}"); + + if (!NativeLibrary.TryGetExport(_handle, "wooting_rgb_device_info", out _getDeviceInfoPointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_rgb_device_info'"); + if (!NativeLibrary.TryGetExport(_handle, "wooting_rgb_kbd_connected", out _keyboardConnectedPointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_rgb_kbd_connected'"); + if (!NativeLibrary.TryGetExport(_handle, "wooting_rgb_reset_rgb", out _resetPointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_rgb_reset_rgb'"); + if (!NativeLibrary.TryGetExport(_handle, "wooting_rgb_close", out _closePointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_rgb_close'"); + if (!NativeLibrary.TryGetExport(_handle, "wooting_rgb_array_update_keyboard", out _arrayUpdateKeyboardPointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_rgb_array_update_keyboard'"); + if (!NativeLibrary.TryGetExport(_handle, "wooting_rgb_array_set_single", out _arraySetSinglePointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_rgb_array_set_single'"); + if (!NativeLibrary.TryGetExport(_handle, "wooting_usb_keyboard_count", out _getDeviceCountPointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_usb_keyboard_count'"); + if (!NativeLibrary.TryGetExport(_handle, "wooting_usb_select_device", out _selectDevicePointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_usb_select_device'"); } + private static IEnumerable GetPossibleLibraryPaths() + { + IEnumerable possibleLibraryPaths; + + if (OperatingSystem.IsWindows()) + possibleLibraryPaths = Environment.Is64BitProcess ? WootingDeviceProvider.PossibleX64NativePaths : WootingDeviceProvider.PossibleX86NativePaths; + else if (OperatingSystem.IsLinux()) + possibleLibraryPaths = Environment.Is64BitProcess ? WootingDeviceProvider.PossibleX64NativePathsLinux : WootingDeviceProvider.PossibleX86NativePathsLinux; + else + possibleLibraryPaths = Enumerable.Empty(); + + return possibleLibraryPaths.Select(Environment.ExpandEnvironmentVariables); + } internal static void UnloadWootingSDK() { @@ -60,14 +68,15 @@ internal static class _WootingSDK Close(); - _getDeviceInfoPointer = null; - _keyboardConnectedPointer = null; - _arrayUpdateKeyboardPointer = null; - _arraySetSinglePointer = null; - _resetPointer = null; - _closePointer = null; + _getDeviceInfoPointer = IntPtr.Zero; + _keyboardConnectedPointer = IntPtr.Zero; + _resetPointer = IntPtr.Zero; + _closePointer = IntPtr.Zero; + _arrayUpdateKeyboardPointer = IntPtr.Zero; + _arraySetSinglePointer = IntPtr.Zero; + _getDeviceCountPointer = IntPtr.Zero; + _selectDevicePointer = IntPtr.Zero; - // ReSharper disable once EmptyEmbeddedStatement - DarthAffe 20.02.2016: We might need to reduce the internal reference counter more than once to set the library free NativeLibrary.Free(_handle); _handle = IntPtr.Zero; } @@ -78,52 +87,32 @@ internal static class _WootingSDK #region Pointers - private static GetDeviceInfoPointer? _getDeviceInfoPointer; - private static KeyboardConnectedPointer? _keyboardConnectedPointer; - private static ResetPointer? _resetPointer; - private static ClosePointer? _closePointer; - private static ArrayUpdateKeyboardPointer? _arrayUpdateKeyboardPointer; - private static ArraySetSinglePointer? _arraySetSinglePointer; - private static GetDeviceCountPointer? _getDeviceCountPointer; - private static SelectDevicePointer? _selectDevicePointer; + private static IntPtr _getDeviceInfoPointer; + private static IntPtr _keyboardConnectedPointer; + private static IntPtr _resetPointer; + private static IntPtr _closePointer; + private static IntPtr _arrayUpdateKeyboardPointer; + private static IntPtr _arraySetSinglePointer; + private static IntPtr _getDeviceCountPointer; + private static IntPtr _selectDevicePointer; #endregion - #region Delegates + internal static unsafe IntPtr GetDeviceInfo() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_getDeviceInfoPointer))(); + internal static unsafe bool KeyboardConnected() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_keyboardConnectedPointer))(); + internal static unsafe bool Reset() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_resetPointer))(); + internal static unsafe bool Close() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_closePointer))(); + internal static unsafe bool ArrayUpdateKeyboard() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_arrayUpdateKeyboardPointer))(); + internal static unsafe bool ArraySetSingle(byte row, byte column, byte red, byte green, byte blue) + => ((delegate* unmanaged[Cdecl])ThrowIfZero(_arraySetSinglePointer))(row, column, red, green, blue); + internal static unsafe byte GetDeviceCount() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_getDeviceCountPointer))(); + internal static unsafe void SelectDevice(byte index) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_selectDevicePointer))(index); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate IntPtr GetDeviceInfoPointer(); + private static IntPtr ThrowIfZero(IntPtr ptr) + { + if (ptr == IntPtr.Zero) throw new RGBDeviceException("The Wooting-SDK is not initialized."); + return ptr; + } - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate bool KeyboardConnectedPointer(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate bool ResetPointer(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate bool ClosePointer(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate bool ArrayUpdateKeyboardPointer(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate bool ArraySetSinglePointer(byte row, byte column, byte red, byte green, byte blue); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate byte GetDeviceCountPointer(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void SelectDevicePointer(byte index); - - #endregion - - internal static IntPtr GetDeviceInfo() => (_getDeviceInfoPointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); - internal static bool KeyboardConnected() => (_keyboardConnectedPointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); - internal static bool Reset() => (_resetPointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); - internal static bool Close() => (_closePointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); - internal static bool ArrayUpdateKeyboard() => (_arrayUpdateKeyboardPointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); - internal static bool ArraySetSingle(byte row, byte column, byte red, byte green, byte blue) => (_arraySetSinglePointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(row, column, red, green, blue); - internal static byte GetDeviceCount() => (_getDeviceCountPointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); - internal static void SelectDevice(byte index) => (_selectDevicePointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(index); #endregion } \ No newline at end of file diff --git a/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj b/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj index 7ab5f6c..607299b 100644 --- a/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj +++ b/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj @@ -36,6 +36,7 @@ True portable snupkg + true diff --git a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs index c4f1ce7..5ddf6cc 100644 --- a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs +++ b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs @@ -23,17 +23,29 @@ public class WootingDeviceProvider : AbstractRGBDeviceProvider public static WootingDeviceProvider Instance => _instance ?? new WootingDeviceProvider(); /// - /// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications. + /// Gets a modifiable list of paths used to find the native SDK-dlls for x86 windows applications. /// The first match will be used. /// public static List PossibleX86NativePaths { get; } = new() { "x86/wooting-rgb-sdk.dll" }; /// - /// Gets a modifiable list of paths used to find the native SDK-dlls for x64 applications. + /// Gets a modifiable list of paths used to find the native SDK-dlls for x86 linux applications. + /// The first match will be used. + /// + public static List PossibleX86NativePathsLinux { get; } = new() { "x86/wooting-rgb-sdk.so" }; + + /// + /// Gets a modifiable list of paths used to find the native SDK-dlls for x64 windows applications. /// The first match will be used. /// public static List PossibleX64NativePaths { get; } = new() { "x64/wooting-rgb-sdk64.dll" }; + /// + /// Gets a modifiable list of paths used to find the native SDK-dlls for x64 linux applications. + /// The first match will be used. + /// + public static List PossibleX64NativePathsLinux { get; } = new() { "x64/wooting-rgb-sdk64.so" }; + #endregion #region Constructors @@ -70,7 +82,7 @@ public class WootingDeviceProvider : AbstractRGBDeviceProvider { for (byte i = 0; i < _WootingSDK.GetDeviceCount(); i++) { - var updateQueue = new WootingUpdateQueue(GetUpdateTrigger(), i); + WootingUpdateQueue updateQueue = new(GetUpdateTrigger(), i); _WootingSDK.SelectDevice(i); _WootingDeviceInfo nativeDeviceInfo = (_WootingDeviceInfo)Marshal.PtrToStructure(_WootingSDK.GetDeviceInfo(), typeof(_WootingDeviceInfo))!;