// ReSharper disable UnusedMethodReturnValue.Global // ReSharper disable UnusedMember.Global using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using RGB.NET.Core; namespace RGB.NET.Devices.CoolerMaster.Native { // ReSharper disable once InconsistentNaming internal static class _CoolerMasterSDK { #region Libary Management private static IntPtr _dllHandle = IntPtr.Zero; /// /// Gets the loaded architecture (x64/x86). /// internal static string LoadedArchitecture { get; private set; } /// /// Reloads the SDK. /// internal static void Reload() { UnloadCMSDK(); LoadCMSDK(); } private static void LoadCMSDK() { if (_dllHandle != IntPtr.Zero) return; // HACK: Load library at runtime to support both, x86 and x64 with one managed dll List possiblePathList = Environment.Is64BitProcess ? CoolerMasterDeviceProvider.PossibleX64NativePaths : CoolerMasterDeviceProvider.PossibleX86NativePaths; 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))}'"); _dllHandle = LoadLibrary(dllPath); _getSDKVersionPointer = (GetSDKVersionPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "GetCM_SDK_DllVer"), typeof(GetSDKVersionPointer)); _setControlDevicenPointer = (SetControlDevicePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "SetControlDevice"), typeof(SetControlDevicePointer)); _isDevicePlugPointer = (IsDevicePlugPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "IsDevicePlug"), typeof(IsDevicePlugPointer)); _getDeviceLayoutPointer = (GetDeviceLayoutPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "GetDeviceLayout"), typeof(GetDeviceLayoutPointer)); _enableLedControlPointer = (EnableLedControlPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "EnableLedControl"), typeof(EnableLedControlPointer)); _refreshLedPointer = (RefreshLedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "RefreshLed"), typeof(RefreshLedPointer)); _setLedColorPointer = (SetLedColorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "SetLedColor"), typeof(SetLedColorPointer)); _setAllLedColorPointer = (SetAllLedColorPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "SetAllLedColor"), typeof(SetAllLedColorPointer)); } internal static void UnloadCMSDK() { if (_dllHandle == IntPtr.Zero) return; // 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 while (FreeLibrary(_dllHandle)) ; _dllHandle = IntPtr.Zero; } [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 #region SDK-METHODS #region Pointers private static GetSDKVersionPointer _getSDKVersionPointer; private static SetControlDevicePointer _setControlDevicenPointer; private static IsDevicePlugPointer _isDevicePlugPointer; private static GetDeviceLayoutPointer _getDeviceLayoutPointer; private static EnableLedControlPointer _enableLedControlPointer; private static RefreshLedPointer _refreshLedPointer; private static SetLedColorPointer _setLedColorPointer; private static SetAllLedColorPointer _setAllLedColorPointer; #endregion #region Delegates [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int GetSDKVersionPointer(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void SetControlDevicePointer(CoolerMasterDevicesIndexes devicesIndexes); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool IsDevicePlugPointer(CoolerMasterDevicesIndexes devIndex); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate CoolerMasterPhysicalKeyboardLayout GetDeviceLayoutPointer(CoolerMasterDevicesIndexes devIndex); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool EnableLedControlPointer(bool value, CoolerMasterDevicesIndexes devIndex); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool RefreshLedPointer(bool autoRefresh, CoolerMasterDevicesIndexes devIndex); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool SetLedColorPointer(int row, int column, byte r, byte g, byte b, CoolerMasterDevicesIndexes devIndex); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool SetAllLedColorPointer(_CoolerMasterColorMatrix colorMatrix, CoolerMasterDevicesIndexes devIndex); #endregion // ReSharper disable EventExceptionNotDocumented /// /// CM-SDK: Get SDK Dll's Version. /// internal static int GetSDKVersion() => _getSDKVersionPointer(); /// /// CM-SDK: set operating device /// internal static void SetControlDevice(CoolerMasterDevicesIndexes devicesIndexes) => _setControlDevicenPointer(devicesIndexes); /// /// CM-SDK: verify if the deviced is plugged in /// internal static bool IsDevicePlugged(CoolerMasterDevicesIndexes devIndex = CoolerMasterDevicesIndexes.Default) => _isDevicePlugPointer(devIndex); /// /// CM-SDK: Obtain current device layout /// internal static CoolerMasterPhysicalKeyboardLayout GetDeviceLayout(CoolerMasterDevicesIndexes devIndex = CoolerMasterDevicesIndexes.Default) => _getDeviceLayoutPointer(devIndex); /// /// CM-SDK: set control over device’s LED /// internal static bool EnableLedControl(bool value, CoolerMasterDevicesIndexes devIndex = CoolerMasterDevicesIndexes.Default) => _enableLedControlPointer(value, devIndex); /// /// CM-SDK: Print out the lights setting from Buffer to LED /// internal static bool RefreshLed(bool autoRefresh, CoolerMasterDevicesIndexes devIndex = CoolerMasterDevicesIndexes.Default) => _refreshLedPointer(autoRefresh, devIndex); /// /// CM-SDK: Set single Key LED color /// internal static bool SetLedColor(int row, int column, byte r, byte g, byte b, CoolerMasterDevicesIndexes devIndex = CoolerMasterDevicesIndexes.Default) => _setLedColorPointer(row, column, r, g, b, devIndex); /// /// CM-SDK: Set Keyboard "every LED" color /// internal static bool SetAllLedColor(_CoolerMasterColorMatrix colorMatrix, CoolerMasterDevicesIndexes devIndex = CoolerMasterDevicesIndexes.Default) => _setAllLedColorPointer(colorMatrix, devIndex); // ReSharper restore EventExceptionNotDocumented #endregion } }