1
0
mirror of https://github.com/DarthAffe/RGB.NET.git synced 2026-01-01 10:13:36 +00:00

Compare commits

..

No commits in common. "a9adf9763c79d32f5da7a61d28aad99c2e4aa32a" and "08142b30b25b0013e0753147394982778a13511c" have entirely different histories.

16 changed files with 432 additions and 461 deletions

View File

@ -16,14 +16,14 @@ internal static class _CoolerMasterSDK
{ {
#region Libary Management #region Libary Management
private static IntPtr _handle = IntPtr.Zero; private static IntPtr _dllHandle = IntPtr.Zero;
/// <summary> /// <summary>
/// Reloads the SDK. /// Reloads the SDK.
/// </summary> /// </summary>
internal static void Reload() internal static void Reload()
{ {
if (_handle != IntPtr.Zero) if (_dllHandle != IntPtr.Zero)
{ {
foreach (CoolerMasterDevicesIndexes index in Enum.GetValues(typeof(CoolerMasterDevicesIndexes))) foreach (CoolerMasterDevicesIndexes index in Enum.GetValues(typeof(CoolerMasterDevicesIndexes)))
EnableLedControl(false, index); EnableLedControl(false, index);
@ -34,7 +34,7 @@ internal static class _CoolerMasterSDK
private static void LoadCMSDK() private static void LoadCMSDK()
{ {
if (_handle != IntPtr.Zero) return; if (_dllHandle != IntPtr.Zero) return;
// HACK: Load library at runtime to support both, x86 and x64 with one managed dll // HACK: Load library at runtime to support both, x86 and x64 with one managed dll
List<string> possiblePathList = (Environment.Is64BitProcess ? CoolerMasterDeviceProvider.PossibleX64NativePaths : CoolerMasterDeviceProvider.PossibleX86NativePaths) List<string> possiblePathList = (Environment.Is64BitProcess ? CoolerMasterDeviceProvider.PossibleX64NativePaths : CoolerMasterDeviceProvider.PossibleX86NativePaths)
@ -43,43 +43,22 @@ internal static class _CoolerMasterSDK
string? dllPath = possiblePathList.FirstOrDefault(File.Exists); string? dllPath = possiblePathList.FirstOrDefault(File.Exists);
if (dllPath == null) throw new RGBDeviceException($"Can't find the CoolerMaster-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'"); if (dllPath == null) throw new RGBDeviceException($"Can't find the CoolerMaster-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'");
_handle = LoadLibrary(dllPath); _dllHandle = LoadLibrary(dllPath);
#if NET6_0 if (_dllHandle == IntPtr.Zero) throw new RGBDeviceException($"CoolerMaster LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
if (_handle == IntPtr.Zero) throw new RGBDeviceException($"CoolerMaster LoadLibrary failed with error code {Marshal.GetLastPInvokeError()}");
#else
if (_handle == IntPtr.Zero) throw new RGBDeviceException($"CoolerMaster LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
#endif
_getSDKVersionPointer = (GetSDKVersionPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_handle, "GetCM_SDK_DllVer"), typeof(GetSDKVersionPointer)); _getSDKVersionPointer = (GetSDKVersionPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "GetCM_SDK_DllVer"), typeof(GetSDKVersionPointer));
_setControlDevicenPointer = (SetControlDevicePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_handle, "SetControlDevice"), typeof(SetControlDevicePointer)); _setControlDevicenPointer = (SetControlDevicePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "SetControlDevice"), typeof(SetControlDevicePointer));
_isDevicePlugPointer = (IsDevicePlugPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_handle, "IsDevicePlug"), typeof(IsDevicePlugPointer)); _isDevicePlugPointer = (IsDevicePlugPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "IsDevicePlug"), typeof(IsDevicePlugPointer));
_getDeviceLayoutPointer = (GetDeviceLayoutPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_handle, "GetDeviceLayout"), typeof(GetDeviceLayoutPointer)); _getDeviceLayoutPointer = (GetDeviceLayoutPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "GetDeviceLayout"), typeof(GetDeviceLayoutPointer));
_enableLedControlPointer = (EnableLedControlPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_handle, "EnableLedControl"), typeof(EnableLedControlPointer)); _enableLedControlPointer = (EnableLedControlPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "EnableLedControl"), typeof(EnableLedControlPointer));
_refreshLedPointer = (RefreshLedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_handle, "RefreshLed"), typeof(RefreshLedPointer)); _refreshLedPointer = (RefreshLedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "RefreshLed"), typeof(RefreshLedPointer));
_setLedColorPointer = (SetLedColorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_handle, "SetLedColor"), typeof(SetLedColorPointer)); _setLedColorPointer = (SetLedColorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "SetLedColor"), typeof(SetLedColorPointer));
_setAllLedColorPointer = (SetAllLedColorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_handle, "SetAllLedColor"), typeof(SetAllLedColorPointer)); _setAllLedColorPointer = (SetAllLedColorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "SetAllLedColor"), typeof(SetAllLedColorPointer));
}
internal static void UnloadCMSDK()
{
if (_handle == IntPtr.Zero) return;
_getSDKVersionPointer = null;
_setControlDevicenPointer = null;
_isDevicePlugPointer = null;
_getDeviceLayoutPointer = null;
_enableLedControlPointer = null;
_refreshLedPointer = null;
_setLedColorPointer = null;
_setAllLedColorPointer = null;
NativeLibrary.Free(_handle);
_handle = IntPtr.Zero;
} }
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string dllToLoad); private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)] [DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name); private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name);

View File

@ -16,7 +16,7 @@ internal static class _CUESDK
{ {
#region Libary Management #region Libary Management
private static IntPtr _handle = IntPtr.Zero; private static IntPtr _dllHandle = IntPtr.Zero;
/// <summary> /// <summary>
/// Reloads the SDK. /// Reloads the SDK.
@ -29,88 +29,113 @@ internal static class _CUESDK
private static void LoadCUESDK() private static void LoadCUESDK()
{ {
if (_handle != IntPtr.Zero) return; if (_dllHandle != IntPtr.Zero) return;
List<string> possiblePathList = GetPossibleLibraryPaths().ToList();
// HACK: Load library at runtime to support both, x86 and x64 with one managed dll
List<string> possiblePathList = (Environment.Is64BitProcess ? CorsairDeviceProvider.PossibleX64NativePaths : CorsairDeviceProvider.PossibleX86NativePaths)
.Select(Environment.ExpandEnvironmentVariables)
.ToList();
string? dllPath = possiblePathList.FirstOrDefault(File.Exists); string? dllPath = possiblePathList.FirstOrDefault(File.Exists);
if (dllPath == null) throw new RGBDeviceException($"Can't find the CUE-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'"); if (dllPath == null) throw new RGBDeviceException($"Can't find the CUE-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'");
if (!NativeLibrary.TryLoad(dllPath, out _handle)) _dllHandle = LoadLibrary(dllPath);
#if NET6_0 if (_dllHandle == IntPtr.Zero) throw new RGBDeviceException($"Corsair LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
throw new RGBDeviceException($"Corsair LoadLibrary failed with error code {Marshal.GetLastPInvokeError()}");
#else
throw new RGBDeviceException($"Corsair LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
#endif
if (!NativeLibrary.TryGetExport(_handle, "CorsairSetLedsColorsBufferByDeviceIndex", out _corsairSetLedsColorsBufferByDeviceIndexPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairSetLedsColorsBufferByDeviceIndex'"); _corsairSetLedsColorsBufferByDeviceIndexPointer = (CorsairSetLedsColorsBufferByDeviceIndexPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairSetLedsColorsBufferByDeviceIndex"), typeof(CorsairSetLedsColorsBufferByDeviceIndexPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairSetLedsColorsFlushBuffer", out _corsairSetLedsColorsFlushBufferPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairSetLedsColorsFlushBuffer'"); _corsairSetLedsColorsFlushBufferPointer = (CorsairSetLedsColorsFlushBufferPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairSetLedsColorsFlushBuffer"), typeof(CorsairSetLedsColorsFlushBufferPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairGetLedsColorsByDeviceIndex", out _corsairGetLedsColorsByDeviceIndexPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairGetLedsColorsByDeviceIndex'"); _corsairGetLedsColorsByDeviceIndexPointer = (CorsairGetLedsColorsByDeviceIndexPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetLedsColorsByDeviceIndex"), typeof(CorsairGetLedsColorsByDeviceIndexPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairSetLayerPriority", out _corsairSetLayerPriorityPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairSetLayerPriority'"); _corsairSetLayerPriorityPointer = (CorsairSetLayerPriorityPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairSetLayerPriority"), typeof(CorsairSetLayerPriorityPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairGetDeviceCount", out _corsairGetDeviceCountPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairGetDeviceCount'"); _corsairGetDeviceCountPointer = (CorsairGetDeviceCountPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetDeviceCount"), typeof(CorsairGetDeviceCountPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairGetDeviceInfo", out _corsairGetDeviceInfoPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairGetDeviceInfo'"); _corsairGetDeviceInfoPointer = (CorsairGetDeviceInfoPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetDeviceInfo"), typeof(CorsairGetDeviceInfoPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairGetLedIdForKeyName", out _corsairGetLedIdForKeyNamePointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairGetLedIdForKeyName'"); _corsairGetLedPositionsByDeviceIndexPointer = (CorsairGetLedPositionsByDeviceIndexPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetLedPositionsByDeviceIndex"), typeof(CorsairGetLedPositionsByDeviceIndexPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairGetLedPositionsByDeviceIndex", out _corsairGetLedPositionsByDeviceIndexPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairGetLedPositionsByDeviceIndex'"); _corsairGetLedIdForKeyNamePointer = (CorsairGetLedIdForKeyNamePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetLedIdForKeyName"), typeof(CorsairGetLedIdForKeyNamePointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairRequestControl", out _corsairRequestControlPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairRequestControl'"); _corsairRequestControlPointer = (CorsairRequestControlPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairRequestControl"), typeof(CorsairRequestControlPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairReleaseControl", out _corsairReleaseControlPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairReleaseControl'"); _corsairReleaseControlPointer = (CorsairReleaseControlPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairReleaseControl"), typeof(CorsairReleaseControlPointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairPerformProtocolHandshake", out _corsairPerformProtocolHandshakePointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairPerformProtocolHandshake'"); _corsairPerformProtocolHandshakePointer = (CorsairPerformProtocolHandshakePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairPerformProtocolHandshake"), typeof(CorsairPerformProtocolHandshakePointer));
if (!NativeLibrary.TryGetExport(_handle, "CorsairGetLastError", out _corsairGetLastErrorPointer)) throw new RGBDeviceException("Failed to load Corsair function 'CorsairGetLastError'"); _corsairGetLastErrorPointer = (CorsairGetLastErrorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetLastError"), typeof(CorsairGetLastErrorPointer));
}
private static IEnumerable<string> GetPossibleLibraryPaths()
{
IEnumerable<string> possibleLibraryPaths;
if (OperatingSystem.IsWindows())
possibleLibraryPaths = Environment.Is64BitProcess ? CorsairDeviceProvider.PossibleX64NativePaths : CorsairDeviceProvider.PossibleX86NativePaths;
else
possibleLibraryPaths = Enumerable.Empty<string>();
return possibleLibraryPaths.Select(Environment.ExpandEnvironmentVariables);
} }
internal static void UnloadCUESDK() internal static void UnloadCUESDK()
{ {
if (_handle == IntPtr.Zero) return; if (_dllHandle == IntPtr.Zero) return;
_corsairSetLedsColorsBufferByDeviceIndexPointer = 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
_corsairSetLedsColorsFlushBufferPointer = IntPtr.Zero; while (FreeLibrary(_dllHandle)) ;
_corsairGetLedsColorsByDeviceIndexPointer = IntPtr.Zero; _dllHandle = IntPtr.Zero;
_corsairSetLayerPriorityPointer = IntPtr.Zero;
_corsairGetDeviceCountPointer = IntPtr.Zero;
_corsairGetDeviceInfoPointer = IntPtr.Zero;
_corsairGetLedIdForKeyNamePointer = IntPtr.Zero;
_corsairGetLedPositionsByDeviceIndexPointer = IntPtr.Zero;
_corsairRequestControlPointer = IntPtr.Zero;
_corsairReleaseControlPointer = IntPtr.Zero;
_corsairPerformProtocolHandshakePointer = IntPtr.Zero;
_corsairGetLastErrorPointer = IntPtr.Zero;
NativeLibrary.Free(_handle);
_handle = IntPtr.Zero;
} }
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr dllHandle);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name);
#endregion #endregion
#region SDK-METHODS #region SDK-METHODS
#region Pointers #region Pointers
private static IntPtr _corsairSetLedsColorsBufferByDeviceIndexPointer; private static CorsairSetLedsColorsBufferByDeviceIndexPointer? _corsairSetLedsColorsBufferByDeviceIndexPointer;
private static IntPtr _corsairSetLedsColorsFlushBufferPointer; private static CorsairSetLedsColorsFlushBufferPointer? _corsairSetLedsColorsFlushBufferPointer;
private static IntPtr _corsairGetLedsColorsByDeviceIndexPointer; private static CorsairGetLedsColorsByDeviceIndexPointer? _corsairGetLedsColorsByDeviceIndexPointer;
private static IntPtr _corsairSetLayerPriorityPointer; private static CorsairSetLayerPriorityPointer? _corsairSetLayerPriorityPointer;
private static IntPtr _corsairGetDeviceCountPointer; private static CorsairGetDeviceCountPointer? _corsairGetDeviceCountPointer;
private static IntPtr _corsairGetDeviceInfoPointer; private static CorsairGetDeviceInfoPointer? _corsairGetDeviceInfoPointer;
private static IntPtr _corsairGetLedIdForKeyNamePointer; private static CorsairGetLedIdForKeyNamePointer? _corsairGetLedIdForKeyNamePointer;
private static IntPtr _corsairGetLedPositionsByDeviceIndexPointer; private static CorsairGetLedPositionsByDeviceIndexPointer? _corsairGetLedPositionsByDeviceIndexPointer;
private static IntPtr _corsairRequestControlPointer; private static CorsairRequestControlPointer? _corsairRequestControlPointer;
private static IntPtr _corsairReleaseControlPointer; private static CorsairReleaseControlPointer? _corsairReleaseControlPointer;
private static IntPtr _corsairPerformProtocolHandshakePointer; private static CorsairPerformProtocolHandshakePointer? _corsairPerformProtocolHandshakePointer;
private static IntPtr _corsairGetLastErrorPointer; private static CorsairGetLastErrorPointer? _corsairGetLastErrorPointer;
#endregion #endregion
#region Delegates
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool CorsairSetLedsColorsBufferByDeviceIndexPointer(int deviceIndex, int size, IntPtr ledsColors);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool CorsairSetLedsColorsFlushBufferPointer();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool CorsairGetLedsColorsByDeviceIndexPointer(int deviceIndex, int size, IntPtr ledsColors);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool CorsairSetLayerPriorityPointer(int priority);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int CorsairGetDeviceCountPointer();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr CorsairGetDeviceInfoPointer(int deviceIndex);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr CorsairGetLedPositionsByDeviceIndexPointer(int deviceIndex);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate CorsairLedId CorsairGetLedIdForKeyNamePointer(char keyName);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool CorsairRequestControlPointer(CorsairAccessMode accessMode);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool CorsairReleaseControlPointer(CorsairAccessMode accessMode);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate _CorsairProtocolDetails CorsairPerformProtocolHandshakePointer();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate CorsairError CorsairGetLastErrorPointer();
#endregion
// ReSharper disable EventExceptionNotDocumented
/// <summary> /// <summary>
/// CUE-SDK: set specified LEDs to some colors. /// CUE-SDK: set specified LEDs to some colors.
/// This function set LEDs colors in the buffer which is written to the devices via CorsairSetLedsColorsFlushBuffer or CorsairSetLedsColorsFlushBufferAsync. /// This function set LEDs colors in the buffer which is written to the devices via CorsairSetLedsColorsFlushBuffer or CorsairSetLedsColorsFlushBufferAsync.
@ -118,76 +143,72 @@ internal static class _CUESDK
/// and follows after one or more calls of CorsairSetLedsColorsBufferByDeviceIndex to set the LEDs buffer. /// and follows after one or more calls of CorsairSetLedsColorsBufferByDeviceIndex to set the LEDs buffer.
/// This function does not take logical layout into account. /// This function does not take logical layout into account.
/// </summary> /// </summary>
internal static unsafe bool CorsairSetLedsColorsBufferByDeviceIndex(int deviceIndex, int size, IntPtr ledsColors) internal static bool CorsairSetLedsColorsBufferByDeviceIndex(int deviceIndex, int size, IntPtr ledsColors)
=> ((delegate* unmanaged[Cdecl]<int, int, IntPtr, bool>)ThrowIfZero(_corsairSetLedsColorsBufferByDeviceIndexPointer))(deviceIndex, size, ledsColors); => (_corsairSetLedsColorsBufferByDeviceIndexPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke(deviceIndex, size, ledsColors);
/// <summary> /// <summary>
/// CUE-SDK: writes to the devices LEDs colors buffer which is previously filled by the CorsairSetLedsColorsBufferByDeviceIndex function. /// CUE-SDK: writes to the devices LEDs colors buffer which is previously filled by the CorsairSetLedsColorsBufferByDeviceIndex function.
/// This function executes synchronously, if you are concerned about delays consider using CorsairSetLedsColorsFlushBufferAsync /// This function executes synchronously, if you are concerned about delays consider using CorsairSetLedsColorsFlushBufferAsync
/// </summary> /// </summary>
internal static unsafe bool CorsairSetLedsColorsFlushBuffer() => ((delegate* unmanaged[Cdecl]<bool>)ThrowIfZero(_corsairSetLedsColorsFlushBufferPointer))(); internal static bool CorsairSetLedsColorsFlushBuffer() => (_corsairSetLedsColorsFlushBufferPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke();
/// <summary> /// <summary>
/// CUE-SDK: get current color for the list of requested LEDs. /// CUE-SDK: get current color for the list of requested LEDs.
/// The color should represent the actual state of the hardware LED, which could be a combination of SDK and/or CUE input. /// The color should represent the actual state of the hardware LED, which could be a combination of SDK and/or CUE input.
/// This function works for keyboard, mouse, mousemat, headset, headset stand and DIY-devices. /// This function works for keyboard, mouse, mousemat, headset, headset stand and DIY-devices.
/// </summary> /// </summary>
internal static unsafe bool CorsairGetLedsColorsByDeviceIndex(int deviceIndex, int size, IntPtr ledsColors) internal static bool CorsairGetLedsColorsByDeviceIndex(int deviceIndex, int size, IntPtr ledsColors)
=> ((delegate* unmanaged[Cdecl]<int, int, IntPtr, bool>)ThrowIfZero(_corsairGetLedsColorsByDeviceIndexPointer))(deviceIndex, size, ledsColors); => (_corsairGetLedsColorsByDeviceIndexPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke(deviceIndex, size, ledsColors);
/// <summary> /// <summary>
/// CUE-SDK: set layer priority for this shared client. /// CUE-SDK: set layer priority for this shared client.
/// By default CUE has priority of 127 and all shared clients have priority of 128 if they dont call this function. /// By default CUE has priority of 127 and all shared clients have priority of 128 if they dont call this function.
/// Layers with higher priority value are shown on top of layers with lower priority. /// Layers with higher priority value are shown on top of layers with lower priority.
/// </summary> /// </summary>
internal static unsafe bool CorsairSetLayerPriority(int priority) => ((delegate* unmanaged[Cdecl]<int, bool>)ThrowIfZero(_corsairSetLayerPriorityPointer))(priority); internal static bool CorsairSetLayerPriority(int priority) => (_corsairSetLayerPriorityPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke(priority);
/// <summary> /// <summary>
/// CUE-SDK: returns number of connected Corsair devices that support lighting control. /// CUE-SDK: returns number of connected Corsair devices that support lighting control.
/// </summary> /// </summary>
internal static unsafe int CorsairGetDeviceCount() => ((delegate* unmanaged[Cdecl]<int>)ThrowIfZero(_corsairGetDeviceCountPointer))(); internal static int CorsairGetDeviceCount() => (_corsairGetDeviceCountPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke();
/// <summary> /// <summary>
/// CUE-SDK: returns information about device at provided index. /// CUE-SDK: returns information about device at provided index.
/// </summary> /// </summary>
internal static unsafe IntPtr CorsairGetDeviceInfo(int deviceIndex) => ((delegate* unmanaged[Cdecl]<int, IntPtr>)ThrowIfZero(_corsairGetDeviceInfoPointer))(deviceIndex); internal static IntPtr CorsairGetDeviceInfo(int deviceIndex) => (_corsairGetDeviceInfoPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke(deviceIndex);
/// <summary> /// <summary>
/// CUE-SDK: provides list of keyboard or mousepad LEDs with their physical positions. /// CUE-SDK: provides list of keyboard or mousepad LEDs with their physical positions.
/// </summary> /// </summary>
internal static unsafe IntPtr CorsairGetLedPositionsByDeviceIndex(int deviceIndex) => ((delegate* unmanaged[Cdecl]<int, IntPtr>)ThrowIfZero(_corsairGetLedPositionsByDeviceIndexPointer))(deviceIndex); internal static IntPtr CorsairGetLedPositionsByDeviceIndex(int deviceIndex) => (_corsairGetLedPositionsByDeviceIndexPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke(deviceIndex);
/// <summary> /// <summary>
/// CUE-SDK: retrieves led id for key name taking logical layout into account. /// CUE-SDK: retrieves led id for key name taking logical layout into account.
/// </summary> /// </summary>
internal static unsafe CorsairLedId CorsairGetLedIdForKeyName(char keyName) => ((delegate* unmanaged[Cdecl]<char, CorsairLedId>)ThrowIfZero(_corsairGetLedIdForKeyNamePointer))(keyName); internal static CorsairLedId CorsairGetLedIdForKeyName(char keyName) => (_corsairGetLedIdForKeyNamePointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke(keyName);
/// <summary> /// <summary>
/// CUE-SDK: requestes control using specified access mode. /// CUE-SDK: requestes control using specified access mode.
/// By default client has shared control over lighting so there is no need to call CorsairRequestControl unless client requires exclusive control. /// By default client has shared control over lighting so there is no need to call CorsairRequestControl unless client requires exclusive control.
/// </summary> /// </summary>
internal static unsafe bool CorsairRequestControl(CorsairAccessMode accessMode) => ((delegate* unmanaged[Cdecl]<CorsairAccessMode, bool>)ThrowIfZero(_corsairRequestControlPointer))(accessMode); internal static bool CorsairRequestControl(CorsairAccessMode accessMode) => (_corsairRequestControlPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke(accessMode);
/// <summary> /// <summary>
/// CUE-SDK: releases previously requested control for specified access mode. /// CUE-SDK: releases previously requested control for specified access mode.
/// </summary> /// </summary>
internal static unsafe bool CorsairReleaseControl(CorsairAccessMode accessMode) => ((delegate* unmanaged[Cdecl]<CorsairAccessMode, bool>)ThrowIfZero(_corsairReleaseControlPointer))(accessMode); internal static bool CorsairReleaseControl(CorsairAccessMode accessMode) => (_corsairReleaseControlPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke(accessMode);
/// <summary> /// <summary>
/// CUE-SDK: checks file and protocol version of CUE to understand which of SDK functions can be used with this version of CUE. /// CUE-SDK: checks file and protocol version of CUE to understand which of SDK functions can be used with this version of CUE.
/// </summary> /// </summary>
internal static unsafe _CorsairProtocolDetails CorsairPerformProtocolHandshake() => ((delegate* unmanaged[Cdecl]<_CorsairProtocolDetails>)ThrowIfZero(_corsairPerformProtocolHandshakePointer))(); internal static _CorsairProtocolDetails CorsairPerformProtocolHandshake() => (_corsairPerformProtocolHandshakePointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke();
/// <summary> /// <summary>
/// CUE-SDK: returns last error that occured while using any of Corsair* functions. /// CUE-SDK: returns last error that occured while using any of Corsair* functions.
/// </summary> /// </summary>
internal static unsafe CorsairError CorsairGetLastError() => ((delegate* unmanaged[Cdecl]<CorsairError>)ThrowIfZero(_corsairGetLastErrorPointer))(); internal static CorsairError CorsairGetLastError() => (_corsairGetLastErrorPointer ?? throw new RGBDeviceException("The Corsair-SDK is not initialized.")).Invoke();
private static IntPtr ThrowIfZero(IntPtr ptr) // ReSharper restore EventExceptionNotDocumented
{
if (ptr == IntPtr.Zero) throw new RGBDeviceException("The Corsair-SDK is not initialized.");
return ptr;
}
#endregion #endregion
} }

View File

@ -36,7 +36,6 @@
<IncludeSymbols>True</IncludeSymbols> <IncludeSymbols>True</IncludeSymbols>
<DebugType>portable</DebugType> <DebugType>portable</DebugType>
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'"> <PropertyGroup Condition="'$(Configuration)'=='Debug'">

View File

@ -13,11 +13,11 @@ using RGB.NET.Core;
namespace RGB.NET.Devices.Logitech.Native; namespace RGB.NET.Devices.Logitech.Native;
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
internal static class _LogitechGSDK internal class _LogitechGSDK
{ {
#region Libary Management #region Libary Management
private static IntPtr _handle = IntPtr.Zero; private static IntPtr _dllHandle = IntPtr.Zero;
/// <summary> /// <summary>
/// Reloads the SDK. /// Reloads the SDK.
@ -30,90 +30,110 @@ internal static class _LogitechGSDK
private static void LoadLogitechGSDK() private static void LoadLogitechGSDK()
{ {
if (_handle != IntPtr.Zero) return; if (_dllHandle != IntPtr.Zero) return;
List<string> possiblePathList = GetPossibleLibraryPaths().ToList();
// HACK: Load library at runtime to support both, x86 and x64 with one managed dll
List<string> possiblePathList = (Environment.Is64BitProcess ? LogitechDeviceProvider.PossibleX64NativePaths : LogitechDeviceProvider.PossibleX86NativePaths)
.Select(Environment.ExpandEnvironmentVariables)
.ToList();
string? dllPath = possiblePathList.FirstOrDefault(File.Exists); string? dllPath = possiblePathList.FirstOrDefault(File.Exists);
if (dllPath == null) throw new RGBDeviceException($"Can't find the Logitech-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'"); if (dllPath == null) throw new RGBDeviceException($"Can't find the Logitech-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'");
if (!NativeLibrary.TryLoad(dllPath, out _handle)) _dllHandle = LoadLibrary(dllPath);
#if NET6_0 if (_dllHandle == IntPtr.Zero) throw new RGBDeviceException($"Logitech LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
throw new RGBDeviceException($"Logitech LoadLibrary failed with error code {Marshal.GetLastPInvokeError()}");
#else
throw new RGBDeviceException($"Logitech LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
#endif
if (!NativeLibrary.TryGetExport(_handle, "LogiLedInit", out _logiLedInitPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedInit'"); _logiLedInitPointer = (LogiLedInitPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedInit"), typeof(LogiLedInitPointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedShutdown", out _logiLedShutdownPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedShutdown'"); _logiLedShutdownPointer = (LogiLedShutdownPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedShutdown"), typeof(LogiLedShutdownPointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetTargetDevice", out _logiLedSetTargetDevicePointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetTargetDevice'"); _logiLedSetTargetDevicePointer = (LogiLedSetTargetDevicePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetTargetDevice"), typeof(LogiLedSetTargetDevicePointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedGetSdkVersion", out _logiLedGetSdkVersionPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedGetSdkVersion'"); _logiLedGetSdkVersionPointer = (LogiLedGetSdkVersionPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedGetSdkVersion"), typeof(LogiLedGetSdkVersionPointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedSaveCurrentLighting", out _lgiLedSaveCurrentLightingPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSaveCurrentLighting'"); _lgiLedSaveCurrentLightingPointer = (LogiLedSaveCurrentLightingPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSaveCurrentLighting"), typeof(LogiLedSaveCurrentLightingPointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedRestoreLighting", out _logiLedRestoreLightingPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedRestoreLighting'"); _logiLedRestoreLightingPointer = (LogiLedRestoreLightingPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedRestoreLighting"), typeof(LogiLedRestoreLightingPointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetLighting", out _logiLedSetLightingPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetLighting'"); _logiLedSetLightingPointer = (LogiLedSetLightingPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLighting"), typeof(LogiLedSetLightingPointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetLightingForKeyWithKeyName", out _logiLedSetLightingForKeyWithKeyNamePointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetLightingForKeyWithKeyName'"); _logiLedSetLightingForKeyWithKeyNamePointer = (LogiLedSetLightingForKeyWithKeyNamePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLightingForKeyWithKeyName"), typeof(LogiLedSetLightingForKeyWithKeyNamePointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetLightingFromBitmap", out _logiLedSetLightingFromBitmapPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetLightingFromBitmap'"); _logiLedSetLightingFromBitmapPointer = (LogiLedSetLightingFromBitmapPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLightingFromBitmap"), typeof(LogiLedSetLightingFromBitmapPointer));
if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetLightingForTargetZone", out _logiLedSetLightingForTargetZonePointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetLightingForTargetZone'"); _logiLedSetLightingForTargetZonePointer = (LogiLedSetLightingForTargetZonePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLightingForTargetZone"), typeof(LogiLedSetLightingForTargetZonePointer));
}
private static IEnumerable<string> GetPossibleLibraryPaths()
{
IEnumerable<string> possibleLibraryPaths;
if (OperatingSystem.IsWindows())
possibleLibraryPaths = Environment.Is64BitProcess ? LogitechDeviceProvider.PossibleX64NativePaths : LogitechDeviceProvider.PossibleX86NativePaths;
else
possibleLibraryPaths = Enumerable.Empty<string>();
return possibleLibraryPaths.Select(Environment.ExpandEnvironmentVariables);
} }
internal static void UnloadLogitechGSDK() internal static void UnloadLogitechGSDK()
{ {
if (_handle == IntPtr.Zero) return; if (_dllHandle == IntPtr.Zero) return;
_logiLedInitPointer = IntPtr.Zero; LogiLedShutdown();
_logiLedShutdownPointer = IntPtr.Zero;
_logiLedSetTargetDevicePointer = IntPtr.Zero;
_logiLedGetSdkVersionPointer = IntPtr.Zero;
_lgiLedSaveCurrentLightingPointer = IntPtr.Zero;
_logiLedRestoreLightingPointer = IntPtr.Zero;
_logiLedSetLightingPointer = IntPtr.Zero;
_logiLedSetLightingForKeyWithKeyNamePointer = IntPtr.Zero;
_logiLedSetLightingFromBitmapPointer = IntPtr.Zero;
_logiLedSetLightingForTargetZonePointer = IntPtr.Zero;
NativeLibrary.Free(_handle); // 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
_handle = IntPtr.Zero; while (FreeLibrary(_dllHandle)) ;
_dllHandle = IntPtr.Zero;
} }
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr dllHandle);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name);
#endregion #endregion
#region SDK-METHODS #region SDK-METHODS
#region Pointers #region Pointers
private static IntPtr _logiLedInitPointer; private static LogiLedInitPointer? _logiLedInitPointer;
private static IntPtr _logiLedShutdownPointer; private static LogiLedShutdownPointer? _logiLedShutdownPointer;
private static IntPtr _logiLedSetTargetDevicePointer; private static LogiLedSetTargetDevicePointer? _logiLedSetTargetDevicePointer;
private static IntPtr _logiLedGetSdkVersionPointer; private static LogiLedGetSdkVersionPointer? _logiLedGetSdkVersionPointer;
private static IntPtr _lgiLedSaveCurrentLightingPointer; private static LogiLedSaveCurrentLightingPointer? _lgiLedSaveCurrentLightingPointer;
private static IntPtr _logiLedRestoreLightingPointer; private static LogiLedRestoreLightingPointer? _logiLedRestoreLightingPointer;
private static IntPtr _logiLedSetLightingPointer; private static LogiLedSetLightingPointer? _logiLedSetLightingPointer;
private static IntPtr _logiLedSetLightingForKeyWithKeyNamePointer; private static LogiLedSetLightingForKeyWithKeyNamePointer? _logiLedSetLightingForKeyWithKeyNamePointer;
private static IntPtr _logiLedSetLightingFromBitmapPointer; private static LogiLedSetLightingFromBitmapPointer? _logiLedSetLightingFromBitmapPointer;
private static IntPtr _logiLedSetLightingForTargetZonePointer; private static LogiLedSetLightingForTargetZonePointer? _logiLedSetLightingForTargetZonePointer;
#endregion #endregion
internal static unsafe bool LogiLedInit() #region Delegates
=> ((delegate* unmanaged[Cdecl]<bool>)ThrowIfZero(_logiLedInitPointer))();
internal static unsafe void LogiLedShutdown() [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
=> ((delegate* unmanaged[Cdecl]<void>)ThrowIfZero(_logiLedShutdownPointer))(); private delegate bool LogiLedInitPointer();
internal static unsafe bool LogiLedSetTargetDevice(LogitechDeviceCaps targetDevice) [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
=> ((delegate* unmanaged[Cdecl]<int, bool>)ThrowIfZero(_logiLedSetTargetDevicePointer))((int)targetDevice); private delegate void LogiLedShutdownPointer();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedSetTargetDevicePointer(int targetDevice);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedGetSdkVersionPointer(ref int majorNum, ref int minorNum, ref int buildNum);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedSaveCurrentLightingPointer();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedRestoreLightingPointer();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedSetLightingPointer(int redPercentage, int greenPercentage, int bluePercentage);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedSetLightingForKeyWithKeyNamePointer(int keyCode, int redPercentage, int greenPercentage, int bluePercentage);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedSetLightingFromBitmapPointer(byte[] bitmap);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedSetLightingForTargetZonePointer(LogitechDeviceType deviceType, int zone, int redPercentage, int greenPercentage, int bluePercentage);
#endregion
// ReSharper disable EventExceptionNotDocumented
internal static bool LogiLedInit() => (_logiLedInitPointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke();
internal static void LogiLedShutdown() => (_logiLedShutdownPointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke();
internal static bool LogiLedSetTargetDevice(LogitechDeviceCaps targetDevice) => (_logiLedSetTargetDevicePointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke((int)targetDevice);
internal static string LogiLedGetSdkVersion() internal static string LogiLedGetSdkVersion()
{ {
@ -125,32 +145,25 @@ internal static class _LogitechGSDK
return $"{major}.{minor}.{build}"; return $"{major}.{minor}.{build}";
} }
internal static unsafe bool LogiLedGetSdkVersion(ref int majorNum, ref int minorNum, ref int buildNum) internal static bool LogiLedGetSdkVersion(ref int majorNum, ref int minorNum, ref int buildNum) =>
=> ((delegate* unmanaged[Cdecl]<ref int, ref int, ref int, bool>)ThrowIfZero(_logiLedGetSdkVersionPointer))(ref majorNum, ref minorNum, ref buildNum); (_logiLedGetSdkVersionPointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke(ref majorNum, ref minorNum, ref buildNum);
internal static unsafe bool LogiLedSaveCurrentLighting() internal static bool LogiLedSaveCurrentLighting() => (_lgiLedSaveCurrentLightingPointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke();
=> ((delegate* unmanaged[Cdecl]<bool>)ThrowIfZero(_lgiLedSaveCurrentLightingPointer))();
internal static unsafe bool LogiLedRestoreLighting() internal static bool LogiLedRestoreLighting() => (_logiLedRestoreLightingPointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke();
=> ((delegate* unmanaged[Cdecl]<bool>)ThrowIfZero(_logiLedRestoreLightingPointer))();
internal static unsafe bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage) internal static bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage) =>
=> ((delegate* unmanaged[Cdecl]<int, int, int, bool>)ThrowIfZero(_logiLedSetLightingPointer))(redPercentage, greenPercentage, bluePercentage); (_logiLedSetLightingPointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke(redPercentage, greenPercentage, bluePercentage);
internal static unsafe bool LogiLedSetLightingForKeyWithKeyName(int keyCode, int redPercentage, int greenPercentage, int bluePercentage) internal static bool LogiLedSetLightingForKeyWithKeyName(int keyCode, int redPercentage, int greenPercentage, int bluePercentage)
=> ((delegate* unmanaged[Cdecl]<int, int, int, int, bool>)ThrowIfZero(_logiLedSetLightingForKeyWithKeyNamePointer))(keyCode, redPercentage, greenPercentage, bluePercentage); => (_logiLedSetLightingForKeyWithKeyNamePointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke(keyCode, redPercentage, greenPercentage, bluePercentage);
internal static unsafe bool LogiLedSetLightingFromBitmap(byte[] bitmap) internal static bool LogiLedSetLightingFromBitmap(byte[] bitmap) => (_logiLedSetLightingFromBitmapPointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke(bitmap);
=> ((delegate* unmanaged[Cdecl]<byte[], bool>)ThrowIfZero(_logiLedSetLightingFromBitmapPointer))(bitmap);
internal static unsafe bool LogiLedSetLightingForTargetZone(LogitechDeviceType deviceType, int zone, int redPercentage, int greenPercentage, int bluePercentage) internal static bool LogiLedSetLightingForTargetZone(LogitechDeviceType deviceType, int zone, int redPercentage, int greenPercentage, int bluePercentage)
=> ((delegate* unmanaged[Cdecl]<LogitechDeviceType, int, int, int, int, bool>)ThrowIfZero(_logiLedSetLightingForTargetZonePointer))(deviceType, zone, redPercentage, greenPercentage, bluePercentage); => (_logiLedSetLightingForTargetZonePointer ?? throw new RGBDeviceException("The Logitech-GSDK is not initialized.")).Invoke(deviceType, zone, redPercentage, greenPercentage, bluePercentage);
private static IntPtr ThrowIfZero(IntPtr ptr) // ReSharper restore EventExceptionNotDocumented
{
if (ptr == IntPtr.Zero) throw new RGBDeviceException("The Logitech-SDK is not initialized.");
return ptr;
}
#endregion #endregion
} }

View File

@ -36,7 +36,6 @@
<IncludeSymbols>True</IncludeSymbols> <IncludeSymbols>True</IncludeSymbols>
<DebugType>portable</DebugType> <DebugType>portable</DebugType>
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'"> <PropertyGroup Condition="'$(Configuration)'=='Debug'">

View File

@ -16,7 +16,7 @@ internal static class _MsiSDK
{ {
#region Libary Management #region Libary Management
private static IntPtr _handle = IntPtr.Zero; private static IntPtr _dllHandle = IntPtr.Zero;
/// <summary> /// <summary>
/// Reloads the SDK. /// Reloads the SDK.
@ -29,76 +29,57 @@ internal static class _MsiSDK
private static void LoadMsiSDK() private static void LoadMsiSDK()
{ {
if (_handle != IntPtr.Zero) return; if (_dllHandle != IntPtr.Zero) return;
List<string> possiblePathList = GetPossibleLibraryPaths().ToList();
// HACK: Load library at runtime to support both, x86 and x64 with one managed dll
List<string> possiblePathList = (Environment.Is64BitProcess ? MsiDeviceProvider.PossibleX64NativePaths : MsiDeviceProvider.PossibleX86NativePaths)
.Select(Environment.ExpandEnvironmentVariables)
.ToList();
string? dllPath = possiblePathList.FirstOrDefault(File.Exists); string? dllPath = possiblePathList.FirstOrDefault(File.Exists);
if (dllPath == null) throw new RGBDeviceException($"Can't find the CUE-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'"); if (dllPath == null) throw new RGBDeviceException($"Can't find the Msi-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'");
SetDllDirectory(Path.GetDirectoryName(Path.GetFullPath(dllPath))!); SetDllDirectory(Path.GetDirectoryName(Path.GetFullPath(dllPath))!);
if (!NativeLibrary.TryLoad(dllPath, out _handle)) _dllHandle = LoadLibrary(dllPath);
#if NET6_0 if (_dllHandle == IntPtr.Zero) throw new RGBDeviceException($"MSI LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
throw new RGBDeviceException($"MSI LoadLibrary failed with error code {Marshal.GetLastPInvokeError()}");
#else
throw new RGBDeviceException($"MSI LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
#endif
_initializePointer = (InitializePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_Initialize"), typeof(InitializePointer)); _initializePointer = (InitializePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_Initialize"), typeof(InitializePointer));
_getDeviceInfoPointer = (GetDeviceInfoPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetDeviceInfo"), typeof(GetDeviceInfoPointer)); _getDeviceInfoPointer = (GetDeviceInfoPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetDeviceInfo"), typeof(GetDeviceInfoPointer));
_getLedInfoPointer = (GetLedInfoPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetLedInfo"), typeof(GetLedInfoPointer)); _getLedInfoPointer = (GetLedInfoPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetLedInfo"), typeof(GetLedInfoPointer));
_getLedColorPointer = (GetLedColorPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetLedColor"), typeof(GetLedColorPointer)); _getLedColorPointer = (GetLedColorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetLedColor"), typeof(GetLedColorPointer));
_getLedStylePointer = (GetLedStylePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetLedStyle"), typeof(GetLedStylePointer)); _getLedStylePointer = (GetLedStylePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetLedStyle"), typeof(GetLedStylePointer));
_getLedMaxBrightPointer = (GetLedMaxBrightPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetLedMaxBright"), typeof(GetLedMaxBrightPointer)); _getLedMaxBrightPointer = (GetLedMaxBrightPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetLedMaxBright"), typeof(GetLedMaxBrightPointer));
_getLedBrightPointer = (GetLedBrightPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetLedBright"), typeof(GetLedBrightPointer)); _getLedBrightPointer = (GetLedBrightPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetLedBright"), typeof(GetLedBrightPointer));
_getLedMaxSpeedPointer = (GetLedMaxSpeedPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetLedMaxSpeed"), typeof(GetLedMaxSpeedPointer)); _getLedMaxSpeedPointer = (GetLedMaxSpeedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetLedMaxSpeed"), typeof(GetLedMaxSpeedPointer));
_getLedSpeedPointer = (GetLedSpeedPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetLedSpeed"), typeof(GetLedSpeedPointer)); _getLedSpeedPointer = (GetLedSpeedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetLedSpeed"), typeof(GetLedSpeedPointer));
_setLedColorPointer = (SetLedColorPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_SetLedColor"), typeof(SetLedColorPointer)); _setLedColorPointer = (SetLedColorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_SetLedColor"), typeof(SetLedColorPointer));
_setLedStylePointer = (SetLedStylePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_SetLedStyle"), typeof(SetLedStylePointer)); _setLedStylePointer = (SetLedStylePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_SetLedStyle"), typeof(SetLedStylePointer));
_setLedBrightPointer = (SetLedBrightPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_SetLedBright"), typeof(SetLedBrightPointer)); _setLedBrightPointer = (SetLedBrightPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_SetLedBright"), typeof(SetLedBrightPointer));
_setLedSpeedPointer = (SetLedSpeedPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_SetLedSpeed"), typeof(SetLedSpeedPointer)); _setLedSpeedPointer = (SetLedSpeedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_SetLedSpeed"), typeof(SetLedSpeedPointer));
_getErrorMessagePointer = (GetErrorMessagePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "MLAPI_GetErrorMessage"), typeof(GetErrorMessagePointer)); _getErrorMessagePointer = (GetErrorMessagePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "MLAPI_GetErrorMessage"), typeof(GetErrorMessagePointer));
}
private static IEnumerable<string> GetPossibleLibraryPaths()
{
IEnumerable<string> possibleLibraryPaths;
if (OperatingSystem.IsWindows())
possibleLibraryPaths = Environment.Is64BitProcess ? MsiDeviceProvider.PossibleX64NativePaths : MsiDeviceProvider.PossibleX86NativePaths;
else
possibleLibraryPaths = Enumerable.Empty<string>();
return possibleLibraryPaths.Select(Environment.ExpandEnvironmentVariables);
} }
internal static void UnloadMsiSDK() internal static void UnloadMsiSDK()
{ {
if (_handle == IntPtr.Zero) return; if (_dllHandle == IntPtr.Zero) return;
_initializePointer = null; // ReSharper disable once EmptyEmbeddedStatement - DarthAffe 07.10.2017: We might need to reduce the internal reference counter more than once to set the library free
_getDeviceInfoPointer = null; while (FreeLibrary(_dllHandle)) ;
_getLedColorPointer = null; _dllHandle = IntPtr.Zero;
_getLedColorPointer = null;
_getLedStylePointer = null;
_getLedMaxBrightPointer = null;
_getLedBrightPointer = null;
_getLedMaxSpeedPointer = null;
_getLedSpeedPointer = null;
_setLedColorPointer = null;
_setLedStylePointer = null;
_setLedBrightPointer = null;
_setLedSpeedPointer = null;
_getErrorMessagePointer = null;
NativeLibrary.Free(_handle);
_handle = IntPtr.Zero;
} }
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool SetDllDirectory(string lpPathName); private static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr dllHandle);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name);
#endregion #endregion
#region SDK-METHODS #region SDK-METHODS

View File

@ -16,7 +16,7 @@ internal static class _RazerSDK
{ {
#region Libary Management #region Libary Management
private static IntPtr _handle = IntPtr.Zero; private static IntPtr _dllHandle = IntPtr.Zero;
/// <summary> /// <summary>
/// Reloads the SDK. /// Reloads the SDK.
@ -29,108 +29,132 @@ internal static class _RazerSDK
private static void LoadRazerSDK() private static void LoadRazerSDK()
{ {
if (_handle != IntPtr.Zero) return; if (_dllHandle != IntPtr.Zero) return;
List<string> possiblePathList = GetPossibleLibraryPaths().ToList();
// HACK: Load library at runtime to support both, x86 and x64 with one managed dll
List<string> possiblePathList = (Environment.Is64BitProcess ? RazerDeviceProvider.PossibleX64NativePaths : RazerDeviceProvider.PossibleX86NativePaths)
.Select(Environment.ExpandEnvironmentVariables)
.ToList();
string? dllPath = possiblePathList.FirstOrDefault(File.Exists); 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 (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)) _dllHandle = LoadLibrary(dllPath);
#if NET6_0 if (_dllHandle == IntPtr.Zero) throw new RGBDeviceException($"Razer LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
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'"); _initPointer = (InitPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "Init"), typeof(InitPointer));
if (!NativeLibrary.TryGetExport(_handle, "UnInit", out _unInitPointer)) throw new RGBDeviceException("Failed to load Razer function 'UnInit'"); _unInitPointer = (UnInitPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "UnInit"), typeof(UnInitPointer));
if (!NativeLibrary.TryGetExport(_handle, "QueryDevice", out _queryDevicePointer)) throw new RGBDeviceException("Failed to load Razer function 'QueryDevice'"); _queryDevicePointer = (QueryDevicePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "QueryDevice"), typeof(QueryDevicePointer));
if (!NativeLibrary.TryGetExport(_handle, "CreateEffect", out _createEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateEffect'"); _createEffectPointer = (CreateEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CreateEffect"), typeof(CreateEffectPointer));
if (!NativeLibrary.TryGetExport(_handle, "CreateHeadsetEffect", out _createHeadsetEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateHeadsetEffect'"); _createHeadsetEffectPointer = (CreateHeadsetEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CreateHeadsetEffect"), typeof(CreateHeadsetEffectPointer));
if (!NativeLibrary.TryGetExport(_handle, "CreateChromaLinkEffect", out _createChromaLinkEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateChromaLinkEffect'"); _createChromaLinkEffectPointer = (CreateChromaLinkEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CreateChromaLinkEffect"), typeof(CreateChromaLinkEffectPointer));
if (!NativeLibrary.TryGetExport(_handle, "CreateKeyboardEffect", out _createKeyboardEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateKeyboardEffect'"); _createKeyboardEffectPointer = (CreateKeyboardEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CreateKeyboardEffect"), typeof(CreateKeyboardEffectPointer));
if (!NativeLibrary.TryGetExport(_handle, "CreateKeypadEffect", out _createKeypadEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateKeypadEffect'"); _createKeypadEffectPointer = (CreateKeypadEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CreateKeypadEffect"), typeof(CreateKeypadEffectPointer));
if (!NativeLibrary.TryGetExport(_handle, "CreateMouseEffect", out _createMouseEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateMouseEffect'"); _createMouseEffectPointer = (CreateMouseEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CreateMouseEffect"), typeof(CreateMouseEffectPointer));
if (!NativeLibrary.TryGetExport(_handle, "CreateMousepadEffect", out _createMousepadEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'CreateMousepadEffect'"); _createMousepadEffectPointer = (CreateMousepadEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CreateMousepadEffect"), typeof(CreateMousepadEffectPointer));
if (!NativeLibrary.TryGetExport(_handle, "SetEffect", out _setEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'SetEffect'"); _setEffectPointer = (SetEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "SetEffect"), typeof(SetEffectPointer));
if (!NativeLibrary.TryGetExport(_handle, "DeleteEffect", out _deleteEffectPointer)) throw new RGBDeviceException("Failed to load Razer function 'DeleteEffect'"); _deleteEffectPointer = (DeleteEffectPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "DeleteEffect"), typeof(DeleteEffectPointer));
}
private static IEnumerable<string> GetPossibleLibraryPaths()
{
IEnumerable<string> possibleLibraryPaths;
if (OperatingSystem.IsWindows())
possibleLibraryPaths = Environment.Is64BitProcess ? RazerDeviceProvider.PossibleX64NativePaths : RazerDeviceProvider.PossibleX86NativePaths;
else
possibleLibraryPaths = Enumerable.Empty<string>();
return possibleLibraryPaths.Select(Environment.ExpandEnvironmentVariables);
} }
internal static void UnloadRazerSDK() internal static void UnloadRazerSDK()
{ {
if (_handle == IntPtr.Zero) return; if (_dllHandle == IntPtr.Zero) return;
_initPointer = IntPtr.Zero; // ReSharper disable once EmptyEmbeddedStatement - DarthAffe 09.11.2017: We might need to reduce the internal reference counter more than once to set the library free
_unInitPointer = IntPtr.Zero; while (FreeLibrary(_dllHandle)) ;
_queryDevicePointer = IntPtr.Zero; _dllHandle = IntPtr.Zero;
_createEffectPointer = IntPtr.Zero;
_createHeadsetEffectPointer = IntPtr.Zero;
_createChromaLinkEffectPointer = IntPtr.Zero;
_createKeyboardEffectPointer = IntPtr.Zero;
_createKeypadEffectPointer = IntPtr.Zero;
_createMouseEffectPointer = IntPtr.Zero;
_createMousepadEffectPointer = IntPtr.Zero;
_setEffectPointer = IntPtr.Zero;
_deleteEffectPointer = IntPtr.Zero;
NativeLibrary.Free(_handle);
_handle = IntPtr.Zero;
} }
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr dllHandle);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name);
#endregion #endregion
#region SDK-METHODS #region SDK-METHODS
#region Pointers #region Pointers
private static IntPtr _initPointer; private static InitPointer? _initPointer;
private static IntPtr _unInitPointer; private static UnInitPointer? _unInitPointer;
private static IntPtr _queryDevicePointer; private static QueryDevicePointer? _queryDevicePointer;
private static IntPtr _createEffectPointer; private static CreateEffectPointer? _createEffectPointer;
private static IntPtr _createHeadsetEffectPointer; private static CreateHeadsetEffectPointer? _createHeadsetEffectPointer;
private static IntPtr _createChromaLinkEffectPointer; private static CreateChromaLinkEffectPointer? _createChromaLinkEffectPointer;
private static IntPtr _createKeyboardEffectPointer; private static CreateKeyboardEffectPointer? _createKeyboardEffectPointer;
private static IntPtr _createKeypadEffectPointer; private static CreateKeypadEffectPointer? _createKeypadEffectPointer;
private static IntPtr _createMouseEffectPointer; private static CreateMouseEffectPointer? _createMouseEffectPointer;
private static IntPtr _createMousepadEffectPointer; private static CreateMousepadEffectPointer? _createMousepadEffectPointer;
private static IntPtr _setEffectPointer; private static SetEffectPointer? _setEffectPointer;
private static IntPtr _deleteEffectPointer; private static DeleteEffectPointer? _deleteEffectPointer;
#endregion #endregion
#region Delegates
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError InitPointer();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError UnInitPointer();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError QueryDevicePointer(Guid deviceId, IntPtr deviceInfo);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError CreateEffectPointer(Guid deviceId, int effectType, IntPtr param, ref Guid effectId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError CreateHeadsetEffectPointer(int effectType, IntPtr param, ref Guid effectId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError CreateChromaLinkEffectPointer(int effectType, IntPtr param, ref Guid effectId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError CreateKeyboardEffectPointer(int effectType, IntPtr param, ref Guid effectId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError CreateKeypadEffectPointer(int effectType, IntPtr param, ref Guid effectId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError CreateMouseEffectPointer(int effectType, IntPtr param, ref Guid effectId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError CreateMousepadEffectPointer(int effectType, IntPtr param, ref Guid effectId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError SetEffectPointer(Guid effectId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate RazerError DeleteEffectPointer(Guid effectId);
#endregion
// ReSharper disable EventExceptionNotDocumented
/// <summary> /// <summary>
/// Razer-SDK: Initialize Chroma SDK. /// Razer-SDK: Initialize Chroma SDK.
/// </summary> /// </summary>
internal static unsafe RazerError Init() => ((delegate* unmanaged[Cdecl]<RazerError>)ThrowIfZero(_initPointer))(); internal static RazerError Init() => (_initPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke();
/// <summary> /// <summary>
/// Razer-SDK: UnInitialize Chroma SDK. /// Razer-SDK: UnInitialize Chroma SDK.
/// </summary> /// </summary>
internal static unsafe RazerError UnInit() internal static RazerError UnInit() => (_unInitPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke();
=> ((delegate* unmanaged[Cdecl]<RazerError>)ThrowIfZero(_unInitPointer))();
/// <summary> /// <summary>
/// Razer-SDK: Query for device information. /// Razer-SDK: Query for device information.
/// </summary> /// </summary>
internal static unsafe RazerError QueryDevice(Guid deviceId, out _DeviceInfo deviceInfo) internal static RazerError QueryDevice(Guid deviceId, out _DeviceInfo deviceInfo)
{ {
int structSize = Marshal.SizeOf(typeof(_DeviceInfo)); int structSize = Marshal.SizeOf(typeof(_DeviceInfo));
IntPtr deviceInfoPtr = Marshal.AllocHGlobal(structSize); IntPtr deviceInfoPtr = Marshal.AllocHGlobal(structSize);
RazerError error = ((delegate* unmanaged[Cdecl]<Guid, IntPtr, RazerError>)ThrowIfZero(_queryDevicePointer))(deviceId, deviceInfoPtr); RazerError error = (_queryDevicePointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(deviceId, deviceInfoPtr);
deviceInfo = (_DeviceInfo)Marshal.PtrToStructure(deviceInfoPtr, typeof(_DeviceInfo))!; deviceInfo = (_DeviceInfo)Marshal.PtrToStructure(deviceInfoPtr, typeof(_DeviceInfo))!;
Marshal.FreeHGlobal(deviceInfoPtr); Marshal.FreeHGlobal(deviceInfoPtr);
@ -138,38 +162,25 @@ internal static class _RazerSDK
return error; return error;
} }
internal static unsafe RazerError CreateEffect(Guid deviceId, int effectType, IntPtr param, ref Guid effectId) internal static RazerError CreateEffect(Guid deviceId, int effectType, IntPtr param, ref Guid effectId) => (_createEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(deviceId, effectType, param, ref effectId);
=> ((delegate* unmanaged[Cdecl]<Guid, int, IntPtr, ref Guid, RazerError>)ThrowIfZero(_createEffectPointer))(deviceId, effectType, param, ref effectId);
internal static unsafe RazerError CreateHeadsetEffect(int effectType, IntPtr param, ref Guid effectId) internal static RazerError CreateHeadsetEffect(int effectType, IntPtr param, ref Guid effectId) => (_createHeadsetEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(effectType, param, ref effectId);
=> ((delegate* unmanaged[Cdecl]<int, IntPtr, ref Guid, RazerError>)ThrowIfZero(_createHeadsetEffectPointer))(effectType, param, ref effectId);
internal static unsafe RazerError CreateChromaLinkEffect(int effectType, IntPtr param, ref Guid effectId) internal static RazerError CreateChromaLinkEffect(int effectType, IntPtr param, ref Guid effectId) => (_createChromaLinkEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(effectType, param, ref effectId);
=> ((delegate* unmanaged[Cdecl]<int, IntPtr, ref Guid, RazerError>)ThrowIfZero(_createChromaLinkEffectPointer))(effectType, param, ref effectId);
internal static unsafe RazerError CreateKeyboardEffect(int effectType, IntPtr param, ref Guid effectId) internal static RazerError CreateKeyboardEffect(int effectType, IntPtr param, ref Guid effectId) => (_createKeyboardEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(effectType, param, ref effectId);
=> ((delegate* unmanaged[Cdecl]<int, IntPtr, ref Guid, RazerError>)ThrowIfZero(_createKeyboardEffectPointer))(effectType, param, ref effectId);
internal static unsafe RazerError CreateKeypadEffect(int effectType, IntPtr param, ref Guid effectId) internal static RazerError CreateKeypadEffect(int effectType, IntPtr param, ref Guid effectId) => (_createKeypadEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(effectType, param, ref effectId);
=> ((delegate* unmanaged[Cdecl]<int, IntPtr, ref Guid, RazerError>)ThrowIfZero(_createKeypadEffectPointer))(effectType, param, ref effectId);
internal static unsafe RazerError CreateMouseEffect(int effectType, IntPtr param, ref Guid effectId) internal static RazerError CreateMouseEffect(int effectType, IntPtr param, ref Guid effectId) => (_createMouseEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(effectType, param, ref effectId);
=> ((delegate* unmanaged[Cdecl]<int, IntPtr, ref Guid, RazerError>)ThrowIfZero(_createMouseEffectPointer))(effectType, param, ref effectId);
internal static unsafe RazerError CreateMousepadEffect(int effectType, IntPtr param, ref Guid effectId) internal static RazerError CreateMousepadEffect(int effectType, IntPtr param, ref Guid effectId) => (_createMousepadEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(effectType, param, ref effectId);
=> ((delegate* unmanaged[Cdecl]<int, IntPtr, ref Guid, RazerError>)ThrowIfZero(_createMousepadEffectPointer))(effectType, param, ref effectId);
internal static unsafe RazerError SetEffect(Guid effectId) internal static RazerError SetEffect(Guid effectId) => (_setEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(effectId);
=> ((delegate* unmanaged[Cdecl]<Guid, RazerError>)ThrowIfZero(_setEffectPointer))(effectId);
internal static unsafe RazerError DeleteEffect(Guid effectId) internal static RazerError DeleteEffect(Guid effectId) => (_deleteEffectPointer ?? throw new RGBDeviceException("The Razer-SDK is not initialized.")).Invoke(effectId);
=> ((delegate* unmanaged[Cdecl]<Guid, RazerError>)ThrowIfZero(_deleteEffectPointer))(effectId);
private static IntPtr ThrowIfZero(IntPtr ptr) // ReSharper restore EventExceptionNotDocumented
{
if (ptr == IntPtr.Zero) throw new RGBDeviceException("The Razer-SDK is not initialized.");
return ptr;
}
#endregion #endregion
} }

View File

@ -36,7 +36,6 @@
<IncludeSymbols>True</IncludeSymbols> <IncludeSymbols>True</IncludeSymbols>
<DebugType>portable</DebugType> <DebugType>portable</DebugType>
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'"> <PropertyGroup Condition="'$(Configuration)'=='Debug'">

View File

@ -16,9 +16,9 @@ public abstract class WootingRGBDevice<TDeviceInfo> : AbstractRGBDevice<TDeviceI
/// Initializes a new instance of the <see cref="WootingRGBDevice{TDeviceInfo}"/> class. /// Initializes a new instance of the <see cref="WootingRGBDevice{TDeviceInfo}"/> class.
/// </summary> /// </summary>
/// <param name="info">The generic information provided by Wooting for the device.</param> /// <param name="info">The generic information provided by Wooting for the device.</param>
/// <param name="updateQueue">The update queue used to update this device.</param> /// <param name="updateTrigger">The update trigger used to update this device.</param>
protected WootingRGBDevice(TDeviceInfo info, IUpdateQueue updateQueue) protected WootingRGBDevice(TDeviceInfo info, IDeviceUpdateTrigger updateTrigger)
: base(info, updateQueue) : base(info, new WootingUpdateQueue(updateTrigger))
{ } { }
#endregion #endregion

View File

@ -37,8 +37,6 @@ public class WootingRGBDeviceInfo : IRGBDeviceInfo
/// </summary> /// </summary>
public WootingLayoutType WootingLayoutType { get; } public WootingLayoutType WootingLayoutType { get; }
public byte WootingDeviceIndex { get; }
#endregion #endregion
#region Constructors #region Constructors
@ -48,12 +46,11 @@ public class WootingRGBDeviceInfo : IRGBDeviceInfo
/// </summary> /// </summary>
/// <param name="deviceType">The type of the <see cref="IRGBDevice"/>.</param> /// <param name="deviceType">The type of the <see cref="IRGBDevice"/>.</param>
/// <param name="deviceInfo">The <see cref="_WootingDeviceInfo"/> of the <see cref="IRGBDevice"/>.</param> /// <param name="deviceInfo">The <see cref="_WootingDeviceInfo"/> of the <see cref="IRGBDevice"/>.</param>
internal WootingRGBDeviceInfo(RGBDeviceType deviceType, _WootingDeviceInfo deviceInfo, byte deviceIndex) internal WootingRGBDeviceInfo(RGBDeviceType deviceType, _WootingDeviceInfo deviceInfo)
{ {
this.DeviceType = deviceType; this.DeviceType = deviceType;
this.WootingDeviceType = deviceInfo.DeviceType; this.WootingDeviceType = deviceInfo.DeviceType;
this.WootingLayoutType = deviceInfo.LayoutType; this.WootingLayoutType = deviceInfo.LayoutType;
this.WootingDeviceIndex = deviceIndex;
Model = deviceInfo.Model; Model = deviceInfo.Model;
DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model); DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model);

View File

@ -10,20 +10,15 @@ namespace RGB.NET.Devices.Wooting.Generic;
/// </summary> /// </summary>
public class WootingUpdateQueue : UpdateQueue public class WootingUpdateQueue : UpdateQueue
{ {
#region Properties & Fields
private readonly byte _deviceid;
#endregion
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WootingUpdateQueue"/> class. /// Initializes a new instance of the <see cref="WootingUpdateQueue"/> class.
/// </summary> /// </summary>
/// <param name="updateTrigger">The update trigger used by this queue.</param> /// <param name="updateTrigger">The update trigger used by this queue.</param>
public WootingUpdateQueue(IDeviceUpdateTrigger updateTrigger, byte deviceId) public WootingUpdateQueue(IDeviceUpdateTrigger updateTrigger)
: base(updateTrigger) : base(updateTrigger)
{ {
this._deviceid = deviceId;
} }
#endregion #endregion
@ -35,8 +30,6 @@ public class WootingUpdateQueue : UpdateQueue
{ {
lock (_WootingSDK.SdkLock) lock (_WootingSDK.SdkLock)
{ {
_WootingSDK.SelectDevice(_deviceid);
foreach ((object key, Color color) in dataSet) foreach ((object key, Color color) in dataSet)
{ {
(int row, int column) = ((int, int))key; (int row, int column) = ((int, int))key;

View File

@ -1,7 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using RGB.NET.Core; using RGB.NET.Core;
using RGB.NET.Devices.Wooting.Generic; using RGB.NET.Devices.Wooting.Generic;
using RGB.NET.Devices.Wooting.Native;
namespace RGB.NET.Devices.Wooting.Keyboard; namespace RGB.NET.Devices.Wooting.Keyboard;
@ -25,8 +24,8 @@ public class WootingKeyboardRGBDevice : WootingRGBDevice<WootingKeyboardRGBDevic
/// </summary> /// </summary>
/// <param name="info">The specific information provided by Wooting for the keyboard</param> /// <param name="info">The specific information provided by Wooting for the keyboard</param>
/// <param name="updateTrigger">The update trigger used to update this device.</param> /// <param name="updateTrigger">The update trigger used to update this device.</param>
internal WootingKeyboardRGBDevice(WootingKeyboardRGBDeviceInfo info, IUpdateQueue updateQueue) internal WootingKeyboardRGBDevice(WootingKeyboardRGBDeviceInfo info, IDeviceUpdateTrigger updateTrigger)
: base(info, updateQueue) : base(info, updateTrigger)
{ {
InitializeLayout(); InitializeLayout();
} }
@ -49,13 +48,5 @@ public class WootingKeyboardRGBDevice : WootingRGBDevice<WootingKeyboardRGBDevic
/// <inheritdoc /> /// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(GetUpdateData(ledsToUpdate)); protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(GetUpdateData(ledsToUpdate));
public override void Dispose()
{
_WootingSDK.SelectDevice(DeviceInfo.WootingDeviceIndex);
_WootingSDK.Reset();
base.Dispose();
}
#endregion #endregion
} }

View File

@ -24,8 +24,8 @@ public class WootingKeyboardRGBDeviceInfo : WootingRGBDeviceInfo, IKeyboardDevic
/// Internal constructor of managed <see cref="T:RGB.NET.Devices.Wooting.WootingKeyboardRGBDeviceInfo" />. /// Internal constructor of managed <see cref="T:RGB.NET.Devices.Wooting.WootingKeyboardRGBDeviceInfo" />.
/// </summary> /// </summary>
/// <param name="deviceInfo">The native <see cref="T:RGB.NET.Devices.Wooting.Native._WootingDeviceInfo" />.</param> /// <param name="deviceInfo">The native <see cref="T:RGB.NET.Devices.Wooting.Native._WootingDeviceInfo" />.</param>
internal WootingKeyboardRGBDeviceInfo(_WootingDeviceInfo deviceInfo, byte deviceIndex) internal WootingKeyboardRGBDeviceInfo(_WootingDeviceInfo deviceInfo)
: base(RGBDeviceType.Keyboard, deviceInfo, deviceIndex) : base(RGBDeviceType.Keyboard, deviceInfo)
{ {
Layout = WootingLayoutType switch Layout = WootingLayoutType switch
{ {

View File

@ -15,7 +15,7 @@ internal static class _WootingSDK
{ {
#region Library management #region Library management
private static IntPtr _handle = IntPtr.Zero; private static IntPtr _dllHandle = IntPtr.Zero;
internal static object SdkLock = new(); internal static object SdkLock = new();
/// <summary> /// <summary>
@ -29,95 +29,102 @@ internal static class _WootingSDK
private static void LoadWootingSDK() private static void LoadWootingSDK()
{ {
if (_handle != IntPtr.Zero) return; if (_dllHandle != IntPtr.Zero) return;
List<string> possiblePathList = GetPossibleLibraryPaths().ToList();
// HACK: Load library at runtime to support both, x86 and x64 with one managed dll
List<string> possiblePathList = (Environment.Is64BitProcess ? WootingDeviceProvider.PossibleX64NativePaths : WootingDeviceProvider.PossibleX86NativePaths)
.Select(Environment.ExpandEnvironmentVariables)
.ToList();
string? dllPath = possiblePathList.FirstOrDefault(File.Exists); 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))}'"); 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))}'");
if (!NativeLibrary.TryLoad(dllPath, out _handle)) SetDllDirectory(Path.GetDirectoryName(Path.GetFullPath(dllPath))!);
#if NET6_0
throw new RGBDeviceException($"Wooting LoadLibrary failed with error code {Marshal.GetLastPInvokeError()}");
#else
throw new RGBDeviceException($"Wooting LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
#endif
if (!NativeLibrary.TryGetExport(_handle, "wooting_rgb_device_info", out _getDeviceInfoPointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_rgb_device_info'"); _dllHandle = LoadLibrary(dllPath);
if (!NativeLibrary.TryGetExport(_handle, "wooting_rgb_kbd_connected", out _keyboardConnectedPointer)) throw new RGBDeviceException("Failed to load wooting function 'wooting_rgb_kbd_connected'"); if (_dllHandle == IntPtr.Zero) throw new RGBDeviceException($"Wooting LoadLibrary failed with error code {Marshal.GetLastWin32Error()}");
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<string> GetPossibleLibraryPaths() _getDeviceInfoPointer = (GetDeviceInfoPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_device_info"), typeof(GetDeviceInfoPointer));
{ _keyboardConnectedPointer = (KeyboardConnectedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_kbd_connected"), typeof(KeyboardConnectedPointer));
IEnumerable<string> possibleLibraryPaths; _resetPointer = (ResetPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_reset_rgb"), typeof(ResetPointer));
_closePointer = (ClosePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_close"), typeof(ClosePointer));
if (OperatingSystem.IsWindows()) _arrayUpdateKeyboardPointer = (ArrayUpdateKeyboardPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_array_update_keyboard"), typeof(ArrayUpdateKeyboardPointer));
possibleLibraryPaths = Environment.Is64BitProcess ? WootingDeviceProvider.PossibleX64NativePaths : WootingDeviceProvider.PossibleX86NativePaths; _arraySetSinglePointer = (ArraySetSinglePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_array_set_single"), typeof(ArraySetSinglePointer));
else if (OperatingSystem.IsLinux())
possibleLibraryPaths = Environment.Is64BitProcess ? WootingDeviceProvider.PossibleX64NativePathsLinux : WootingDeviceProvider.PossibleX86NativePathsLinux;
else
possibleLibraryPaths = Enumerable.Empty<string>();
return possibleLibraryPaths.Select(Environment.ExpandEnvironmentVariables);
} }
internal static void UnloadWootingSDK() internal static void UnloadWootingSDK()
{ {
if (_handle == IntPtr.Zero) return; if (_dllHandle == IntPtr.Zero) return;
Reset();
Close(); Close();
_getDeviceInfoPointer = IntPtr.Zero; _getDeviceInfoPointer = null;
_keyboardConnectedPointer = IntPtr.Zero; _keyboardConnectedPointer = null;
_resetPointer = IntPtr.Zero; _arrayUpdateKeyboardPointer = null;
_closePointer = IntPtr.Zero; _arraySetSinglePointer = null;
_arrayUpdateKeyboardPointer = IntPtr.Zero; _resetPointer = null;
_arraySetSinglePointer = IntPtr.Zero; _closePointer = null;
_getDeviceCountPointer = IntPtr.Zero;
_selectDevicePointer = IntPtr.Zero;
NativeLibrary.Free(_handle); // 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
_handle = IntPtr.Zero; while (FreeLibrary(_dllHandle)) ;
_dllHandle = IntPtr.Zero;
} }
[DllImport("kernel32.dll")]
private static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr dllHandle);
[DllImport("kernel32.dll")]
private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name);
#endregion #endregion
#region SDK-METHODS #region SDK-METHODS
#region Pointers #region Pointers
private static IntPtr _getDeviceInfoPointer; private static GetDeviceInfoPointer? _getDeviceInfoPointer;
private static IntPtr _keyboardConnectedPointer; private static KeyboardConnectedPointer? _keyboardConnectedPointer;
private static IntPtr _resetPointer; private static ResetPointer? _resetPointer;
private static IntPtr _closePointer; private static ClosePointer? _closePointer;
private static IntPtr _arrayUpdateKeyboardPointer; private static ArrayUpdateKeyboardPointer? _arrayUpdateKeyboardPointer;
private static IntPtr _arraySetSinglePointer; private static ArraySetSinglePointer? _arraySetSinglePointer;
private static IntPtr _getDeviceCountPointer;
private static IntPtr _selectDevicePointer;
#endregion #endregion
internal static unsafe IntPtr GetDeviceInfo() => ((delegate* unmanaged[Cdecl]<IntPtr>)ThrowIfZero(_getDeviceInfoPointer))(); #region Delegates
internal static unsafe bool KeyboardConnected() => ((delegate* unmanaged[Cdecl]<bool>)ThrowIfZero(_keyboardConnectedPointer))();
internal static unsafe bool Reset() => ((delegate* unmanaged[Cdecl]<bool>)ThrowIfZero(_resetPointer))();
internal static unsafe bool Close() => ((delegate* unmanaged[Cdecl]<bool>)ThrowIfZero(_closePointer))();
internal static unsafe bool ArrayUpdateKeyboard() => ((delegate* unmanaged[Cdecl]<bool>)ThrowIfZero(_arrayUpdateKeyboardPointer))();
internal static unsafe bool ArraySetSingle(byte row, byte column, byte red, byte green, byte blue)
=> ((delegate* unmanaged[Cdecl]<byte, byte, byte, byte, byte, bool>)ThrowIfZero(_arraySetSinglePointer))(row, column, red, green, blue);
internal static unsafe byte GetDeviceCount() => ((delegate* unmanaged[Cdecl]<byte>)ThrowIfZero(_getDeviceCountPointer))();
internal static unsafe void SelectDevice(byte index) => ((delegate* unmanaged[Cdecl]<byte, void>)ThrowIfZero(_selectDevicePointer))(index);
private static IntPtr ThrowIfZero(IntPtr ptr) [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
{ private delegate IntPtr GetDeviceInfoPointer();
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);
#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);
#endregion #endregion
} }

View File

@ -36,7 +36,6 @@
<IncludeSymbols>True</IncludeSymbols> <IncludeSymbols>True</IncludeSymbols>
<DebugType>portable</DebugType> <DebugType>portable</DebugType>
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'"> <PropertyGroup Condition="'$(Configuration)'=='Debug'">

View File

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using RGB.NET.Core; using RGB.NET.Core;
using RGB.NET.Devices.Wooting.Generic;
using RGB.NET.Devices.Wooting.Keyboard; using RGB.NET.Devices.Wooting.Keyboard;
using RGB.NET.Devices.Wooting.Native; using RGB.NET.Devices.Wooting.Native;
@ -23,29 +22,17 @@ public class WootingDeviceProvider : AbstractRGBDeviceProvider
public static WootingDeviceProvider Instance => _instance ?? new WootingDeviceProvider(); public static WootingDeviceProvider Instance => _instance ?? new WootingDeviceProvider();
/// <summary> /// <summary>
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 windows applications. /// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications.
/// The first match will be used. /// The first match will be used.
/// </summary> /// </summary>
public static List<string> PossibleX86NativePaths { get; } = new() { "x86/wooting-rgb-sdk.dll" }; public static List<string> PossibleX86NativePaths { get; } = new() { "x86/wooting-rgb-sdk.dll" };
/// <summary> /// <summary>
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 linux applications. /// Gets a modifiable list of paths used to find the native SDK-dlls for x64 applications.
/// The first match will be used.
/// </summary>
public static List<string> PossibleX86NativePathsLinux { get; } = new() { "x86/wooting-rgb-sdk.so" };
/// <summary>
/// Gets a modifiable list of paths used to find the native SDK-dlls for x64 windows applications.
/// The first match will be used. /// The first match will be used.
/// </summary> /// </summary>
public static List<string> PossibleX64NativePaths { get; } = new() { "x64/wooting-rgb-sdk64.dll" }; public static List<string> PossibleX64NativePaths { get; } = new() { "x64/wooting-rgb-sdk64.dll" };
/// <summary>
/// Gets a modifiable list of paths used to find the native SDK-dlls for x64 linux applications.
/// The first match will be used.
/// </summary>
public static List<string> PossibleX64NativePathsLinux { get; } = new() { "x64/wooting-rgb-sdk64.so" };
#endregion #endregion
#region Constructors #region Constructors
@ -80,14 +67,9 @@ public class WootingDeviceProvider : AbstractRGBDeviceProvider
{ {
if (_WootingSDK.KeyboardConnected()) if (_WootingSDK.KeyboardConnected())
{ {
for (byte i = 0; i < _WootingSDK.GetDeviceCount(); i++) _WootingDeviceInfo nativeDeviceInfo = (_WootingDeviceInfo)Marshal.PtrToStructure(_WootingSDK.GetDeviceInfo(), typeof(_WootingDeviceInfo))!;
{
WootingUpdateQueue updateQueue = new(GetUpdateTrigger(), i);
_WootingSDK.SelectDevice(i);
_WootingDeviceInfo nativeDeviceInfo = (_WootingDeviceInfo)Marshal.PtrToStructure(_WootingSDK.GetDeviceInfo(), typeof(_WootingDeviceInfo))!;
yield return new WootingKeyboardRGBDevice(new WootingKeyboardRGBDeviceInfo(nativeDeviceInfo, i), updateQueue); yield return new WootingKeyboardRGBDevice(new WootingKeyboardRGBDeviceInfo(nativeDeviceInfo), GetUpdateTrigger());
}
} }
} }
} }