Browse Source

POC of my own Implement

HOME 11 months ago
parent
commit
16d0bfdfb9

+ 6 - 0
GpuFanControl/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
+    </startup>
+</configuration>

+ 87 - 0
GpuFanControl/GpuFanControl.csproj

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="C:\NuGetLocalRepo\ILRepack.2.0.18\build\ILRepack.props" Condition="Exists('C:\NuGetLocalRepo\ILRepack.2.0.18\build\ILRepack.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{FBEB7CB4-4D77-4424-A1E6-C56617AA2F02}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>GpuFanControl</RootNamespace>
+    <AssemblyName>GFC</AssemblyName>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="MSIAfterburner.NET, Version=1.1.1.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>ReferenceAssemblies\MSIAfterburner.NET.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MsiAfterburnerWrap\TryingSandBox.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <None Include="packages.config" />
+    <None Include="ReferenceAssemblies\MSIAfterburner.NET.chm" />
+  </ItemGroup>
+  <ItemGroup />
+  <ItemGroup>
+    <Content Include="ReferenceAssemblies\MSIAfterburner.NET.dll" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('C:\NuGetLocalRepo\ILRepack.2.0.18\build\ILRepack.props')" Text="$([System.String]::Format('$(ErrorText)', 'C:\NuGetLocalRepo\ILRepack.2.0.18\build\ILRepack.props'))" />
+  </Target>
+  <PropertyGroup>
+    <PostBuildEvent>if $(ConfigurationName) == Release setlocal enabledelayedexpansion enableextensions
+if $(ConfigurationName) == Release set DLL_LIST=
+if $(ConfigurationName) == Release for %25%25x in ($(TargetDir)*.dll) do set DLL_LIST=!DLL_LIST! "%25%25x"
+if $(ConfigurationName) == Release echo dlls: !DLL_LIST!
+
+if $(ConfigurationName) == Release if not exist "$(TargetDir)Packed" md "$(TargetDir)Packed"
+if $(ConfigurationName) == Release $(ILRepack) /ndebug "/out:$(TargetDir)Packed\$(TargetFileName)" "$(TargetPath)" !DLL_LIST!
+if $(ConfigurationName) == Release if exist "$(TargetDir)Packed\$(TargetFileName).config" del "$(TargetDir)Packed\$(TargetFileName).config"</PostBuildEvent>
+  </PropertyGroup>
+</Project>

+ 337 - 0
GpuFanControl/MsiAfterburnerWrap/TryingSandBox.cs

@@ -0,0 +1,337 @@
+using System;
+using System.IO;
+using System.IO.MemoryMappedFiles;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace GpuFanControl.MsiAfterburnerWrap
+{
+    using ShareMemoryStructs;
+
+    namespace ShareMemoryStructs
+    {
+        [Serializable]
+        public struct MACM_SHARED_MEMORY_HEADER
+        {
+            public uint signature;
+            public uint version;
+            public uint headerSize;
+            public uint gpuEntryCount;
+            public uint gpuEntrySize;
+            public uint masterGpu;
+            public MACM_SHARED_MEMORY_FLAG flags;
+            public uint time;
+            public MACM_SHARED_MEMORY_COMMAND command;
+        }
+
+        [Flags]
+        public enum MACM_SHARED_MEMORY_FLAG : uint
+        {
+            None = 0,
+            LINK = 1,
+            SYNC = 2,
+            THERMAL = 4,
+        }
+
+        [Flags]
+        public enum MACM_SHARED_MEMORY_COMMAND : uint
+        {
+            None = 0,
+            INIT = 11206656, // 0x00AB0000
+            FLUSH = 11206657, // 0x00AB0001
+        }
+
+        [Serializable]
+        public struct MACM_SHARED_MEMORY_GPU_ENTRY
+        {
+            public MACM_SHARED_MEMORY_GPU_ENTRY_FLAG flags;
+            public uint coreClockCur;
+            public uint coreClockMin;
+            public uint coreClockMax;
+            public uint coreClockDef;
+            public uint shaderClockCur;
+            public uint shaderClockMin;
+            public uint shaderClockMax;
+            public uint shaderClockDef;
+            public uint memoryClockCur;
+            public uint memoryClockMin;
+            public uint memoryClockMax;
+            public uint memoryClockDef;
+            public uint fanSpeedCur;
+            public MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG fanFlagsCur;
+            public uint fanSpeedMin;
+            public uint fanSpeedMax;
+            public uint fanSpeedDef;
+            public MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG fanFlagsDef;
+            public uint coreVoltageCur;
+            public uint coreVoltageMin;
+            public uint coreVoltageMax;
+            public uint coreVoltageDef;
+            public uint memoryVoltageCur;
+            public uint memoryVoltageMin;
+            public uint memoryVoltageMax;
+            public uint memoryVoltageDef;
+            public uint auxVoltageCur;
+            public uint auxVoltageMin;
+            public uint auxVoltageMax;
+            public uint auxVoltageDef;
+            public int coreVoltageBoostCur;
+            public int coreVoltageBoostMin;
+            public int coreVoltageBoostMax;
+            public int coreVoltageBoostDef;
+            public int memoryVoltageBoostCur;
+            public int memoryVoltageBoostMin;
+            public int memoryVoltageBoostMax;
+            public int memoryVoltageBoostDef;
+            public int auxVoltageBoostCur;
+            public int auxVoltageBoostMin;
+            public int auxVoltageBoostMax;
+            public int auxVoltageBoostDef;
+            public int powerLimitCur;
+            public int powerLimitMin;
+            public int powerLimitMax;
+            public int powerLimitDef;
+            public int coreClockBoostCur;
+            public int coreClockBoostMin;
+            public int coreClockBoostMax;
+            public int coreClockBoostDef;
+            public int memoryClockBoostCur;
+            public int memoryClockBoostMin;
+            public int memoryClockBoostMax;
+            public int memoryClockBoostDef;
+            public int thermalLimitCur;
+            public int thermalLimitMin;
+            public int thermalLimitMax;
+            public int thermalLimitDef;
+            public uint thermalPrioritizeCur;
+            public uint thermalPrioritizeDef;
+        }
+
+        [Flags]
+        public enum MACM_SHARED_MEMORY_GPU_ENTRY_FLAG : uint
+        {
+            None = 0,
+            CORE_CLOCK = 1,
+            SHADER_CLOCK = 2,
+            MEMORY_CLOCK = 4,
+            FAN_SPEED = 8,
+            CORE_VOLTAGE = 16, // 0x00000010
+            MEMORY_VOLTAGE = 32, // 0x00000020
+            AUX_VOLTAGE = 64, // 0x00000040
+            CORE_VOLTAGE_BOOST = 128, // 0x00000080
+            MEMORY_VOLTAGE_BOOST = 256, // 0x00000100
+            AUX_VOLTAGE_BOOST = 512, // 0x00000200
+            POWER_LIMIT = 1024, // 0x00000400
+            CORE_CLOCK_BOOST = 2048, // 0x00000800
+            MEMORY_CLOCK_BOOST = 4096, // 0x00001000
+            THERMAL_LIMIT = 8192, // 0x00002000
+            THERMAL_PRIORITIZE = 16384, // 0x00004000
+            SYNCHRONIZED_WITH_MASTER = 2147483648, // 0x80000000
+        }
+
+        [Flags]
+        public enum MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG : uint
+        {
+            None = 0,
+            AUTO = 1,
+        }
+    }
+
+    internal class MsiAfterBurnControlWrap
+    {
+        //const
+        private const string ShareMemoryName = "MACMSharedMemory";
+
+        private const string MutexName = "Global\\Access_MACMSharedMemory";
+        private const uint HeaderSignature = ('M' << 24 | ('A' << 16) | ('C' << 8) | ('M'));
+
+        private MemoryMappedFile _hMapFile;
+        private MemoryMappedViewStream _pMapAddr;
+
+        private byte[] _bufSnap;
+
+        public void Connect()
+        {
+            //connect , failure throws FileNotFoundException
+            _hMapFile = MemoryMappedFile.OpenExisting(ShareMemoryName, MemoryMappedFileRights.FullControl);
+            _pMapAddr = _hMapFile.CreateViewStream();
+            //var x_pMapAddr = _hMapFile.CreateViewAccessor();
+        }
+
+        public void Disconnect()
+        {
+            _pMapAddr?.Close();
+            _hMapFile?.Dispose();
+        }
+
+        public void Refresh()
+        {
+            using (var m = new Mutex(false, MutexName))
+            {
+                m.WaitOne();
+
+                var lenHeader = Marshal.SizeOf(typeof(MACM_SHARED_MEMORY_HEADER));
+                var bufHeader = new byte[lenHeader];
+
+                _pMapAddr.Seek(0, SeekOrigin.Begin);
+                _pMapAddr.Read(bufHeader, 0, lenHeader);
+
+                var stHeader = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(bufHeader);
+                if (stHeader.signature == HeaderSignature)
+                {
+                    var lenSnap = stHeader.headerSize + stHeader.gpuEntryCount * stHeader.gpuEntrySize;
+
+                    var bufSnap = new byte[lenSnap];
+
+                    _pMapAddr.Seek(0, SeekOrigin.Begin);
+                    _pMapAddr.Read(bufSnap, 0, (int)lenSnap);
+                    _bufSnap = bufSnap;
+                }
+                m.ReleaseMutex();
+            }
+        }
+
+        public void Commit()
+        {
+            using (var m = new Mutex(false, MutexName))
+            {
+                m.WaitOne();
+
+                _pMapAddr.Seek(0, SeekOrigin.Begin);
+                _pMapAddr.Write(_bufSnap, 0, _bufSnap.Length);
+                _pMapAddr.Flush();
+
+                _pMapAddr.Seek(0, SeekOrigin.Begin);
+                var header = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(_bufSnap);
+                header.command = MACM_SHARED_MEMORY_COMMAND.FLUSH;
+                StructToByteArray(header, _bufSnap);
+
+                _pMapAddr.Seek(0, SeekOrigin.Begin);
+                _pMapAddr.Write(_bufSnap, 0, _bufSnap.Length);
+                _pMapAddr.Flush();
+
+                m.ReleaseMutex();
+            }
+
+            Refresh();
+        }
+
+        public int GetNumberOfGpu()
+        {
+            var st = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(_bufSnap);
+            return (int)st.gpuEntryCount;
+        }
+
+        public MACM_SHARED_MEMORY_GPU_ENTRY? GetGpuEntry(int index, out string error)
+        {
+            var header = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(_bufSnap);
+            if (index > header.gpuEntryCount || index < 0)
+            {
+                error = "index out of range";
+                return null;
+            }
+            var entry = ByteArrayToStruct<MACM_SHARED_MEMORY_GPU_ENTRY>(_bufSnap, (int)header.headerSize + index * (int)header.gpuEntrySize);
+
+            error = null;
+            return entry;
+        }
+
+        public string SetGpuEntry(MACM_SHARED_MEMORY_GPU_ENTRY entry, int index, bool flush = false)
+        {
+            var header = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(_bufSnap);
+            if (index > header.gpuEntryCount || index < 0) return "index out of range";
+
+            StructToByteArray(entry, _bufSnap, (int)(header.headerSize + index * header.gpuEntrySize));
+
+            if (flush) Commit();
+
+            return null;
+        }
+
+        private T ByteArrayToStruct<T>(byte[] bytes, int offset = 0)
+        {
+            GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
+            T stuff;
+            try
+            {
+                stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject() + offset, typeof(T));
+            }
+            finally
+            {
+                handle.Free();
+            }
+            return stuff;
+        }
+
+        private static void StructToByteArray<T>(T str, byte[] snap, int offset = 0)
+        {
+            var h = default(GCHandle);
+
+            try
+            {
+                h = GCHandle.Alloc(snap, GCHandleType.Pinned);
+
+                Marshal.StructureToPtr<T>(str, h.AddrOfPinnedObject() + offset, false);
+            }
+            finally
+            {
+                if (h.IsAllocated)
+                {
+                    h.Free();
+                }
+            }
+        }
+    }
+
+    internal class TryingSandBox
+    {
+        public static void Go()
+        {
+            var ctl = new MsiAfterBurnControlWrap();
+            ctl.Connect();
+            ctl.Refresh();
+
+            var numberOfGpu = ctl.GetNumberOfGpu();
+
+            for (int i = 0; i < numberOfGpu; i++)
+            {
+                Console.WriteLine($"Get entry of GPU #{i}");
+
+                MACM_SHARED_MEMORY_GPU_ENTRY? g;
+                {
+                    g = ctl.GetGpuEntry(i, out string err);
+                    if (g.HasValue == false)
+                    {
+                        Console.WriteLine($"Err:{err}");
+                        continue;
+                    }
+                }
+
+                var entry = g.Value;
+                if (entry.flags.HasFlag(MACM_SHARED_MEMORY_GPU_ENTRY_FLAG.FAN_SPEED))
+                {
+                    Console.WriteLine($"Updating fan speed of GPU #{i}");
+
+                    //entry.fanFlagsCur = MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG.AUTO;
+
+                    entry.fanFlagsCur = MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG.None;
+                    entry.fanSpeedCur = entry.fanSpeedMax;
+
+
+                    var err=ctl.SetGpuEntry(entry, i);
+                    if(err!=null) Console.WriteLine($"Err: {err}");
+                }
+                else
+                {
+                    Console.WriteLine($"Err: No support fan speed");
+                }
+            }
+
+            Console.WriteLine("Commiting...");
+            ctl.Commit();
+            Console.WriteLine("Success");
+
+            ctl.Disconnect();
+        }
+    }
+}

+ 227 - 0
GpuFanControl/Program.cs

@@ -0,0 +1,227 @@
+using MSI.Afterburner;
+using System;
+using GpuFanControl.MsiAfterburnerWrap;
+
+namespace GpuFanControl
+{
+    internal class Program
+    {
+        private static int Main(string[] args)
+        {
+            TryingSandBox.Go();
+
+            return -9999;
+
+            if (args.Length == 0)
+            {
+                PrintUsage();
+                return -1;
+            }
+
+
+            if (args[0].ToLower().StartsWith("-q"))
+            {
+                int? index = null;
+                if (int.TryParse(args[0].Substring(2), out int parsedIndex))
+                {
+                    index = parsedIndex;
+                }
+
+                var cm = ConnectToAfterburner(out var errCode);
+                if (cm == null) return errCode;
+
+                void PrintSpeedTableHeader() => Console.WriteLine("index\tmode\tmin\tval\tmax\t%");
+
+                void PrintGpuFanSpeed(ControlMemoryGpuEntry g)
+                {
+                    if (!g.Flags.HasFlag(MACM_SHARED_MEMORY_GPU_ENTRY_FLAG.FAN_SPEED))
+                    {
+                        Console.WriteLine($"{g.Index}\t** No support fan speed **");
+                    }
+                    else
+                    {
+                        var gfr = g.FanSpeedMax - g.FanSpeedMin;
+                        Console.WriteLine($"{g.Index}\t{g.FanFlagsCur}\t{g.FanSpeedMin}\t{g.FanSpeedCur}\t{g.FanSpeedMax}\t{((float)g.FanSpeedCur - g.FanSpeedMin) / gfr * 100:N2}%");
+                    }
+                }
+
+                if (index.HasValue)
+                {
+                    if (index < 0 || index > cm.GpuEntries.Length - 1)
+                    {
+                        Console.WriteLine("Argument Error: index out of GPU entries");
+                        return -1;
+                    }
+                    //show specified
+                    PrintSpeedTableHeader();
+                    var g = cm.GpuEntries[index.Value];
+                    PrintGpuFanSpeed(g);
+                }
+                else
+                {
+                    //show all
+                    PrintSpeedTableHeader();
+                    foreach (var g in cm.GpuEntries)
+                    {
+                        PrintGpuFanSpeed(g);
+                    }
+                }
+            }
+
+            if (args[0].ToLower().StartsWith("-s"))
+            {
+                float? value = null;
+                var sParam = args[0].Substring(2);
+                if (sParam.ToLower() == "auto")
+                {
+                }
+                else if (float.TryParse(sParam, out var parsedValue))
+                {
+                    value = parsedValue;
+                }
+                else
+                {
+                    Console.WriteLine("Argument Error: -s ");
+                    return -1;
+                }
+
+                int? index = null;
+                if (args.Length > 1 && args[1].ToLower().StartsWith("-i") && int.TryParse(args[1].Substring(2), out int parsedIndex))
+                {
+                    index = parsedIndex;
+                }
+
+                var cm = ConnectToAfterburner(out var errCode);
+                if (cm == null) return errCode;
+
+                void SetGpuFanSpeed(ControlMemoryGpuEntry g)
+                {
+                    Console.WriteLine($"Try change parameter for GPU {g.Index}");
+                    try
+                    {
+                        if (value.HasValue)
+                        {
+                            g.FanFlagsCur = MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG.None;
+
+                            var gfr = g.FanSpeedMax - g.FanSpeedMin;
+                            var targetValue = (uint)Math.Round(g.FanSpeedMin + gfr * value.Value / 100);
+
+                            if (targetValue < g.FanSpeedMin) g.FanSpeedCur = g.FanSpeedMin;
+                            else if (targetValue > g.FanSpeedMax) g.FanSpeedCur = g.FanSpeedMax;
+                            else g.FanSpeedCur = targetValue;
+
+                            Console.WriteLine($"G{g.Index} min:{g.FanSpeedMin} max:{g.FanSpeedMax} set:{g.FanSpeedCur}");
+                        }
+                        else
+                        {
+                            g.FanFlagsCur = MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG.AUTO;
+                        }
+
+                        Console.WriteLine("Success.");
+                    }
+                    catch (Exception e)
+                    {
+                        Console.WriteLine($"Failure to change parameter for GPU {g.Index}, {e.Message}");
+                        return;
+                    }
+
+                    Console.WriteLine($"Commiting Change For GPU {g.Index}");
+                    try
+                    {
+                        cm.CommitChanges(g.Index);
+                        Console.WriteLine($"Success.");
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine($"Failure Commit Change For GPU {g.Index}, {ex.Message}");
+                    }
+
+                    Console.WriteLine($"Reloading Control Memory...");
+                    try
+                    {
+                        cm.ReloadAll();
+                        Console.WriteLine($"Success.");
+                    }
+                    catch (Exception e)
+                    {
+                        Console.WriteLine($"Failure Reloading Control Memory, {e.Message}");
+                    }
+                }
+
+                if (index.HasValue)
+                {
+                    if (index < 0 || index > cm.GpuEntries.Length - 1)
+                    {
+                        Console.WriteLine("Argument Error: index out of GPU entries");
+                        return -1;
+                    }
+
+                    //set specified
+                    var g = cm.GpuEntries[index.Value];
+                    SetGpuFanSpeed(g);
+                }
+                else
+                {
+                    //set all
+                    foreach (var g in cm.GpuEntries)
+                    {
+                        SetGpuFanSpeed(g);
+                    }
+                }
+            }
+
+            return 0;
+        }
+
+        private static ControlMemory ConnectToAfterburner(out int error)
+        {
+            Console.Write("Connecting to MSI Afterburner...");
+
+            try
+            {
+                var cm = new ControlMemory();
+                try
+                {
+                    var l = Console.CursorLeft;
+                    Console.CursorLeft = 0;
+                    Console.Write("".PadLeft(l));
+                    Console.CursorLeft = 0;
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine();
+                }
+
+                error = 0;
+                return cm;
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine();
+                Console.WriteLine(e.Message);
+                error = -2;
+                return null;
+            }
+        }
+
+        private static void PrintUsage()
+        {
+            Console.WriteLine("GPU Fan Control Utility");
+            Console.WriteLine("\tBased on MSI Afterburner 2.1 or later");
+            Console.WriteLine();
+            Console.WriteLine("Query GPU Fan Speed");
+            Console.WriteLine("\t-q[index] blank for all");
+            Console.WriteLine("\toutput: index\tmode\tmin\tval(%)\tmax");
+            Console.WriteLine();
+            Console.WriteLine("Set GPU Fan Speed");
+            Console.WriteLine("\t-s<auto|percent>");
+            Console.WriteLine("\t[-i<index>] blank for all");
+            Console.WriteLine();
+            Console.WriteLine("Exit Code:");
+            Console.WriteLine("\tSuccess:\t0");
+            Console.WriteLine("\tArgument Error:\t-1");
+            Console.WriteLine("\tConnect Fail:\t-2");
+            Console.WriteLine("\tUnknown Fail:\t-3");
+        }
+    }
+}

+ 36 - 0
GpuFanControl/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("GpuFanControl")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GpuFanControl")]
+[assembly: AssemblyCopyright("Copyright ©  2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("fbeb7cb4-4d77-4424-a1e6-c56617aa2f02")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

BIN
GpuFanControl/ReferenceAssemblies/MSIAfterburner.NET.chm


BIN
GpuFanControl/ReferenceAssemblies/MSIAfterburner.NET.dll


+ 4 - 0
GpuFanControl/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="ILRepack" version="2.0.18" targetFramework="net472" />
+</packages>

+ 10 - 0
StrangeTools.sln

@@ -20,6 +20,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotLoader", "DotLoader\DotL
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpTunnel", "TcpTunnel\TcpTunnel.csproj", "{9FA46C6F-A981-4303-8256-EC9B6536BFE5}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GpuFanControl", "GpuFanControl\GpuFanControl.csproj", "{FBEB7CB4-4D77-4424-A1E6-C56617AA2F02}"
+EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MojibakeCorrecting", "MojibakeCorrecting\MojibakeCorrecting.csproj", "{261D52DE-F168-41D2-AD50-78B5B1D801E3}"
 EndProject
 Global
@@ -52,6 +54,14 @@ Global
 		{9FA46C6F-A981-4303-8256-EC9B6536BFE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{9FA46C6F-A981-4303-8256-EC9B6536BFE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{9FA46C6F-A981-4303-8256-EC9B6536BFE5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FBEB7CB4-4D77-4424-A1E6-C56617AA2F02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FBEB7CB4-4D77-4424-A1E6-C56617AA2F02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FBEB7CB4-4D77-4424-A1E6-C56617AA2F02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FBEB7CB4-4D77-4424-A1E6-C56617AA2F02}.Release|Any CPU.Build.0 = Release|Any CPU
+		{261D52DE-F168-41D2-AD50-78B5B1D801E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{261D52DE-F168-41D2-AD50-78B5B1D801E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{261D52DE-F168-41D2-AD50-78B5B1D801E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{261D52DE-F168-41D2-AD50-78B5B1D801E3}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE