├── Miner-WPF ├── 设置.png ├── Ulord.ico ├── Ulord.png ├── UlordRig.exe ├── App.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── packages.config ├── Miner-WPF.csproj.user ├── Models │ ├── AppInfo.cs │ ├── Enums.cs │ ├── ViewModels │ │ ├── MainWindowViewModel.cs │ │ ├── BindableBase.cs │ │ └── ConfigWindowViewModel.cs │ ├── Result.cs │ ├── Converters │ │ ├── PerfomanceLabelContentConverter.cs │ │ ├── IsAutomaticEnabledConverter.cs │ │ ├── IsParamInputEnabledConverter.cs │ │ └── MiningButtonContentConverter.cs │ ├── ConstantParameters.cs │ └── Config.cs ├── Controls │ ├── WPFNotifyIcon.cs │ ├── NotifyWindow.xaml.cs │ ├── ResourceDictionary.xaml │ ├── NotifyWindow.xaml │ ├── NoticeTextBox.xaml.cs │ ├── WPFNotifyIcon.Designer.cs │ ├── NoticeTextBox.xaml │ └── WPFNotifyIcon.resx ├── App.xaml ├── Program.cs ├── MainWindow.xaml ├── App.xaml.cs ├── Commons │ ├── FileHelper.cs │ ├── Win32Native.cs │ └── Configuration.cs ├── Miner-WPF.csproj ├── WindowConfig.xaml.cs ├── MainWindow.xaml.cs └── WindowConfig.xaml ├── .vs └── Miner │ └── v15 │ └── .suo ├── Common ├── packages.config ├── Properties │ └── AssemblyInfo.cs ├── Connection.cs ├── Common.csproj ├── ProcessControl.cs └── FileOperation.cs ├── Test ├── packages.config ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── Config.cs ├── Test.csproj └── Program.cs ├── packages ├── Newtonsoft.Json.11.0.2 │ ├── Newtonsoft.Json.11.0.2.nupkg │ ├── lib │ │ └── net45 │ │ │ └── Newtonsoft.Json.dll │ └── LICENSE.md └── Microsoft.Expression.Drawing.3.0.0 │ ├── Microsoft.Expression.Drawing.3.0.0.nupkg │ └── lib │ └── net45 │ └── Microsoft.Expression.Drawing.dll ├── Contract ├── IPerformance.cs ├── IMiner.cs ├── Properties │ └── AssemblyInfo.cs └── Contract.csproj ├── .gitignore ├── README.md ├── Ulord ├── Performance.cs ├── Properties │ └── AssemblyInfo.cs ├── Miner.cs └── Ulord.csproj └── Miner.sln /Miner-WPF/设置.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/Miner-WPF/设置.png -------------------------------------------------------------------------------- /.vs/Miner/v15/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/.vs/Miner/v15/.suo -------------------------------------------------------------------------------- /Miner-WPF/Ulord.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/Miner-WPF/Ulord.ico -------------------------------------------------------------------------------- /Miner-WPF/Ulord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/Miner-WPF/Ulord.png -------------------------------------------------------------------------------- /Miner-WPF/UlordRig.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/Miner-WPF/UlordRig.exe -------------------------------------------------------------------------------- /Common/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Test/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/Newtonsoft.Json.11.0.2/Newtonsoft.Json.11.0.2.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/packages/Newtonsoft.Json.11.0.2/Newtonsoft.Json.11.0.2.nupkg -------------------------------------------------------------------------------- /packages/Newtonsoft.Json.11.0.2/lib/net45/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/packages/Newtonsoft.Json.11.0.2/lib/net45/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /Test/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Miner-WPF/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/Microsoft.Expression.Drawing.3.0.0/Microsoft.Expression.Drawing.3.0.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/packages/Microsoft.Expression.Drawing.3.0.0/Microsoft.Expression.Drawing.3.0.0.nupkg -------------------------------------------------------------------------------- /packages/Microsoft.Expression.Drawing.3.0.0/lib/net45/Microsoft.Expression.Drawing.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlordChain/UlordMiner-Desktop/HEAD/packages/Microsoft.Expression.Drawing.3.0.0/lib/net45/Microsoft.Expression.Drawing.dll -------------------------------------------------------------------------------- /Miner-WPF/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Miner-WPF/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Miner-WPF/Miner-WPF.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ProjectFiles 5 | 6 | -------------------------------------------------------------------------------- /Miner-WPF/Models/AppInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Miner_WPF.Models 2 | { 3 | public class AppInfo 4 | { 5 | public string Version { set; get; } 6 | public string Address { set; get; } 7 | public string MD5 { set; get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Miner-WPF/Models/Enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Miner_WPF.Models 8 | { 9 | public enum TailDirection 10 | { 11 | Left, 12 | Right, 13 | Both, 14 | None 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Miner-WPF/Models/ViewModels/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace Miner_WPF.Models.ViewModels 2 | { 3 | public class MainWindowViewModel : BindableBase 4 | { 5 | private double computeAbility; 6 | 7 | public double ComputeAbility { get => computeAbility; set => SetProperty(ref computeAbility, value); } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Contract/IPerformance.cs: -------------------------------------------------------------------------------- 1 | namespace Contract 2 | { 3 | public interface IPerformance 4 | { 5 | int Sum { get; } 6 | int Accept { get; } 7 | double Hashrate { get; } 8 | double Difficulty { get; } 9 | void SetPerformance(int sum, int accept, double hashrate, double difficulty); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Miner-WPF/Models/Result.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Miner_WPF.Models 8 | { 9 | internal class Result 10 | { 11 | public double Hashrate { set; get; } 12 | public int Accept { set; get; } 13 | public int Total { set; get; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Miner-WPF/Controls/WPFNotifyIcon.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace Miner_WPF.Controls 4 | { 5 | public partial class WPFNotifyIcon : Control 6 | { 7 | public WPFNotifyIcon() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | protected override void OnPaint(PaintEventArgs pe) 13 | { 14 | base.OnPaint(pe); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。 3 | ################################################################################ 4 | 5 | /Common/bin 6 | /Common/obj 7 | /Contract/obj 8 | /Contract/bin 9 | /Installer/Debug 10 | /Installer/Release 11 | /Miner-UWP 12 | /Miner-WPF/bin 13 | /Miner-WPF/obj 14 | /Ulord/obj 15 | /Ulord/bin 16 | /Test/obj 17 | /Test/bin 18 | /.vs 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UlordMiner-Desktop 2 | 3 | Ulord miner desktop application 4 | 5 | ## Requirements 6 | 7 | - Microsoft Visual Studio 2017 or higher 8 | - .Net Framework 4.6 9 | - [Microsoft Visual Studio 2017 Installer Projects](https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects) (If you need to generate an installer) 10 | 11 | ## Usage 12 | 13 | - Reference: [Ulord miner help](https://testnet-pool.ulord.one/) -------------------------------------------------------------------------------- /Contract/IMiner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Net; 4 | 5 | namespace Contract 6 | { 7 | public interface IMiner 8 | { 9 | bool Run(string file, string arg, DataReceivedEventHandler outputHandler = default(DataReceivedEventHandler), DataReceivedEventHandler errorHandler = default(DataReceivedEventHandler)); 10 | bool Alive(string file, string arg); 11 | bool Terminate(string file); 12 | IPerformance GetPerformance(string file, string arg, IPEndPoint endPoint, string request, Func parseResult, Action setPerformance, out bool alive); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Miner-WPF/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Miner-WPF/Models/Converters/PerfomanceLabelContentConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace Miner_WPF.Models.Converters 6 | { 7 | [ValueConversion(typeof(double), typeof(object))] 8 | class PerfomanceLabelContentConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | return Binary.GetBinaryString((double)value,1); 13 | } 14 | 15 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Miner-WPF/Models/Converters/IsAutomaticEnabledConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace Miner_WPF.Models.Converters 6 | { 7 | [ValueConversion(typeof(bool), typeof(bool?))] 8 | public class IsAutomaticEnabledConverter : IMultiValueConverter 9 | { 10 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | bool isAlive = (bool)values[0]; 13 | bool automatic = (bool)values[1]; 14 | return !isAlive || automatic; 15 | } 16 | 17 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 18 | { 19 | throw new NotImplementedException(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Miner-WPF/Models/Converters/IsParamInputEnabledConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace Miner_WPF.Models.Converters 6 | { 7 | [ValueConversion(typeof(bool), typeof(bool?))] 8 | public class IsParamInputEnabledConverter : IMultiValueConverter 9 | { 10 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | bool isAlive = (bool)values[0]; 13 | bool automatic = (bool)values[1]; 14 | return !isAlive && !automatic; 15 | } 16 | 17 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 18 | { 19 | throw new NotImplementedException(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Miner-WPF/Models/Converters/MiningButtonContentConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace Miner_WPF.Models.Converters 6 | { 7 | [ValueConversion(typeof(bool), typeof(object))] 8 | class MiningButtonContentConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | if ((bool)value) 13 | { 14 | return "结束挖矿"; 15 | } 16 | else 17 | { 18 | return "开始挖矿"; 19 | } 20 | } 21 | 22 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | throw new NotImplementedException(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Miner-WPF/Models/ViewModels/BindableBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace Miner_WPF.Models.ViewModels 6 | { 7 | public class BindableBase : INotifyPropertyChanged 8 | { 9 | public event PropertyChangedEventHandler PropertyChanged; 10 | 11 | protected void SetProperty(ref T prop, T value, [CallerMemberName] string callerName = "") 12 | { 13 | if (!EqualityComparer.Default.Equals(prop, value)) 14 | { 15 | prop = value; 16 | OnPropertyChanged(callerName); 17 | } 18 | } 19 | 20 | protected virtual void OnPropertyChanged(string propertyName) 21 | { 22 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Ulord/Performance.cs: -------------------------------------------------------------------------------- 1 | using Contract; 2 | 3 | namespace Ulord 4 | { 5 | public class Performance : IPerformance 6 | { 7 | private int sum; 8 | private int accept; 9 | private double hashrate; 10 | private double difficulty; 11 | 12 | public int Sum { get => sum; internal set => sum = value; } 13 | 14 | public int Accept { get => accept; internal set => accept = value; } 15 | 16 | public double Hashrate { get => hashrate; internal set => hashrate = value; } 17 | 18 | public double Difficulty { get => difficulty; internal set => difficulty = value; } 19 | 20 | public void SetPerformance(int sum, int accept, double hashrate, double difficulty) 21 | { 22 | Sum = sum; 23 | Accept = accept; 24 | Hashrate = hashrate; 25 | Difficulty = difficulty; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Miner-WPF/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Miner_WPF 5 | { 6 | class Program 7 | { 8 | /// 9 | /// Application Entry Point. 10 | /// 11 | [System.STAThreadAttribute()] 12 | //[System.Diagnostics.DebuggerNonUserCodeAttribute()] 13 | [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] 14 | public static void Main() 15 | { 16 | // Only one instance 17 | bool createNew; 18 | Mutex mutex = new Mutex(true, "UlordMiner", out createNew); 19 | if (!createNew) 20 | { 21 | Commons.Configuration.ShowErrMessage("已经有一个客户端在您的计算机上运行!"); 22 | Environment.Exit(0); 23 | return; 24 | } 25 | Miner_WPF.App app = new Miner_WPF.App(); 26 | app.InitializeComponent(); 27 | app.Run(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Miner-WPF/Models/ViewModels/ConfigWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using Contract; 2 | 3 | namespace Miner_WPF.Models.ViewModels 4 | { 5 | public class ConfigWindowViewModel : BindableBase 6 | { 7 | private bool isAlive; 8 | private double computeAbility; 9 | private double accept; 10 | private double reject; 11 | public Config Config { set; get; } 12 | public bool IsAlive { get => isAlive; set => SetProperty(ref isAlive, value); } 13 | public double ComputeAbility { get => computeAbility; set => SetProperty(ref computeAbility, value); } 14 | public double Accept { get => accept; set => SetProperty(ref accept, value); } 15 | public double Reject { get => reject; set => SetProperty(ref reject, value); } 16 | public void SetPerformance(IPerformance perfmon) 17 | { 18 | ComputeAbility = perfmon.Hashrate; 19 | Accept = perfmon.Accept; 20 | Reject = perfmon.Sum - perfmon.Accept; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Common")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Common")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("084b4296-6da9-435a-b3f1-403268095a05")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("034cd5af-f956-4fe4-b79f-ef907a653e89")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Ulord/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Ulord")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Ulord")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("f82039b3-5473-4536-8834-7ba7ac66f103")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Miner-WPF/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Miner_WPF.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.3.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Contract/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Contract")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Contract")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("ab1f9fef-bce7-446e-9039-eb215501c773")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Test/Config.cs: -------------------------------------------------------------------------------- 1 | using Contract; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Test 9 | { 10 | public class Config 11 | { 12 | private string url; 13 | private string user; 14 | private string id; 15 | private string pass; 16 | private int thread; 17 | private int cpuUsage; 18 | private bool automatic; 19 | 20 | public string Url { get => url; set => url = value; } 21 | public string User { get => user; set => user = value; } 22 | public string Id { get => id; set => id = value; } 23 | public string Pass { get => pass; set => pass = value; } 24 | public int Thread { get => thread; set => thread = value; } 25 | public int CpuUsage { get => cpuUsage; set => cpuUsage = value; } 26 | public bool Automatic { get => automatic; set => automatic = value; } 27 | } 28 | internal class Result 29 | { 30 | public double Hashrate { set; get; } 31 | public int Accept { set; get; } 32 | public int Total { set; get; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/Newtonsoft.Json.11.0.2/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2007 James Newton-King 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Miner-WPF/Controls/NotifyWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Windows; 4 | using System.Windows.Media.Animation; 5 | 6 | namespace Miner_WPF.Controls 7 | { 8 | /// 9 | /// NotifyWindow.xaml 的交互逻辑 10 | /// 11 | public partial class NotifyWindow : Window 12 | { 13 | public NotifyWindow() 14 | { 15 | InitializeComponent(); 16 | this.Left = SystemParameters.WorkArea.Width - this.Width - 5; 17 | this.Top = SystemParameters.WorkArea.Height - this.Height - 5; 18 | this.Loaded += (s, e) => 19 | { 20 | Storyboard storyboard = (Storyboard)this.Resources["load"]; 21 | storyboard.Begin(); 22 | }; 23 | } 24 | public void StartTask(Action task) 25 | { 26 | Task.Factory.StartNew(() => 27 | { 28 | task.Invoke(); 29 | this.Dispatcher.Invoke(() => this.Visibility = Visibility.Collapsed); 30 | }); 31 | } 32 | public void SetMessage(string message) 33 | { 34 | text_Msg.Dispatcher.Invoke(() => text_Msg.Text = message); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Miner-WPF/Models/ConstantParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Miner_WPF.Models 4 | { 5 | public class Binary 6 | { 7 | public const int K = 1024; 8 | public const int M = 1024 * 1024; 9 | public const int G = 1024 * 1024 * 1024; 10 | public const long T = 1099511627776L; 11 | public const long P = 1125899906842624L; 12 | public static string GetBinaryString(double value, int digits = 1) 13 | { 14 | 15 | if (value >= P) 16 | { 17 | return $"{Math.Round(value / P, digits)}P"; 18 | } 19 | else if (value >= T) 20 | { 21 | return $"{Math.Round(value / T, digits)}T"; 22 | } 23 | else if (value >= G) 24 | { 25 | return $"{Math.Round(value / G, digits)}G"; 26 | } 27 | else if (value >= M) 28 | { 29 | return $"{Math.Round(value / M, digits)}M"; 30 | } 31 | else if (value >= K) 32 | { 33 | return $"{Math.Round(value / K, digits)}K"; 34 | } 35 | else 36 | { 37 | return Math.Round(value, digits).ToString(); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Miner-WPF/Models/Config.cs: -------------------------------------------------------------------------------- 1 | using Miner_WPF.Models.ViewModels; 2 | 3 | namespace Miner_WPF.Models 4 | { 5 | public class Config : BindableBase 6 | { 7 | private string url; 8 | private string user; 9 | private string id; 10 | private string pass; 11 | private int thread; 12 | private int cpuUsage; 13 | private bool automatic; 14 | 15 | public string Url { get => url; set => SetProperty(ref url, value); } 16 | public string User { get => user; set => SetProperty(ref user, value); } 17 | public string Id { get => id; set => SetProperty(ref id, value); } 18 | public string Pass { get => pass; set => SetProperty(ref pass, value); } 19 | public int Thread { get => thread; set => SetProperty(ref thread, value); } 20 | public int CpuUsage { get => cpuUsage; set => SetProperty(ref cpuUsage, value); } 21 | public bool Automatic { get => automatic; set => SetProperty(ref automatic, value); } 22 | 23 | public void SetConfig(Config config) 24 | { 25 | this.Url = config.Url; 26 | this.User = config.User; 27 | this.Id = config.Id; 28 | this.Pass = config.Pass; 29 | this.Automatic = config.Automatic; 30 | this.CpuUsage = config.CpuUsage; 31 | this.Thread = config.Thread; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Common/Connection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Sockets; 4 | using System.Text; 5 | 6 | namespace Common 7 | { 8 | public class Connection 9 | { 10 | private const int TIMEOUT = 5 * 1000; 11 | private IPEndPoint endPoint; 12 | public Connection(IPEndPoint endPoint) 13 | { 14 | this.endPoint = endPoint; 15 | } 16 | #region Received 17 | public T Received(string request, long size, Func parseResult, Action action = null) 18 | { 19 | string str = string.Empty; 20 | byte[] bys = new byte[size]; 21 | try 22 | { 23 | using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { SendTimeout = TIMEOUT, ReceiveTimeout = TIMEOUT }) 24 | { 25 | socket.Connect(endPoint); 26 | socket.Receive(bys); 27 | } 28 | 29 | str = Encoding.UTF8.GetString(bys).Trim('\0'); 30 | return parseResult(str); 31 | } 32 | catch (Exception ex) 33 | { 34 | action?.Invoke(ex); 35 | return default(T); 36 | } 37 | } 38 | public T Received(string request, Func parseResult, Action action = null) 39 | { 40 | return Received(request, 4096, parseResult, action); 41 | } 42 | #endregion 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Miner-WPF/Controls/ResourceDictionary.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Miner-WPF/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Ulord/Miner.cs: -------------------------------------------------------------------------------- 1 | using Common; 2 | using Contract; 3 | using System; 4 | using System.ComponentModel.Composition; 5 | using System.Diagnostics; 6 | using System.Net; 7 | 8 | namespace Ulord 9 | { 10 | [Export(typeof(IMiner))] 11 | public class Miner : IMiner 12 | { 13 | private ProcessControl processControl; 14 | private Connection connection; 15 | public Miner() 16 | { 17 | processControl = new ProcessControl(); 18 | } 19 | public bool Alive(string file, string arg) 20 | { 21 | return processControl.Alive; 22 | } 23 | public bool Terminate(string file) 24 | { 25 | return processControl.TerminateProcess(file); 26 | } 27 | 28 | public IPerformance GetPerformance(string file, string arg, IPEndPoint endPoint, string request, Func parseResult, Action setPerformance, out bool alive) 29 | { 30 | IPerformance performance = new Performance(); 31 | if (alive = Alive(file, arg)) 32 | { 33 | if (connection == null) 34 | { 35 | connection = new Connection(endPoint); 36 | } 37 | T result = connection.Received(request, parseResult); 38 | if (result != null) 39 | { 40 | setPerformance(performance, result); 41 | } 42 | } 43 | return performance; 44 | } 45 | 46 | public bool Run(string file, string arg, DataReceivedEventHandler outputHandler = default(DataReceivedEventHandler), DataReceivedEventHandler errorHandler = default(DataReceivedEventHandler)) 47 | { 48 | return processControl.CreateProcess(file, arg, outputHandler, errorHandler); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Miner-WPF/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using Contract; 2 | using Miner_WPF.Commons; 3 | using Miner_WPF.Controls; 4 | using System; 5 | using System.ComponentModel.Composition; 6 | using System.ComponentModel.Composition.Hosting; 7 | using System.IO; 8 | using System.Windows; 9 | 10 | namespace Miner_WPF 11 | { 12 | /// 13 | /// App.xaml 的交互逻辑 14 | /// 15 | public partial class App : Application 16 | { 17 | [Import] 18 | public IMiner Miner { set; get; } 19 | protected override void OnStartup(StartupEventArgs e) 20 | { 21 | NotifyWindow notifyWindow = new NotifyWindow(); 22 | notifyWindow.StartTask(() => 23 | { 24 | try 25 | { 26 | notifyWindow.SetMessage("正在加载程序组件..."); 27 | DirectoryCatalog directoryCatalog = new DirectoryCatalog(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins")); 28 | CompositionContainer compositionContainer = new CompositionContainer(directoryCatalog); 29 | compositionContainer.ComposeParts(this); 30 | Configuration.Init(Miner, notifyWindow.SetMessage); 31 | } 32 | catch (FileLoadException ex) 33 | { 34 | Configuration.DebugExceptionHandle(ex); 35 | Configuration.ShowErrMessage("校验文件完整性失败,程序即将退出!"); 36 | Environment.Exit(0); 37 | } 38 | catch (Exception ex) 39 | { 40 | Configuration.DebugExceptionHandle(ex); 41 | Configuration.ShowErrMessage("加载组件失败,程序即将退出!"); 42 | Environment.Exit(0); 43 | } 44 | }); 45 | notifyWindow.ShowDialog(); 46 | base.OnStartup(e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Miner-WPF/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("Ulord挖矿客户端")] 11 | [assembly: AssemblyDescription("Ulord CPU 挖矿客户端")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("Ulord Foundation Ltd.")] 14 | [assembly: AssemblyProduct("Ulord挖矿客户端")] 15 | [assembly: AssemblyCopyright("© Ulord Foundation Ltd. All rights reserved.")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // 将 ComVisible 设置为 false 会使此程序集中的类型 20 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请设置 25 | //.csproj 文件中的 CultureYouAreCodingWith 26 | //例如,如果您在源文件中使用的是美国英语, 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(未在页面中找到资源时使用, 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(未在页面中找到资源时使用, 40 | //、应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 52 | // 方法是按如下所示使用“*”: : 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.3")] 55 | [assembly: AssemblyFileVersion("1.0.3")] 56 | [assembly: NeutralResourcesLanguage("zh-CN")] 57 | 58 | -------------------------------------------------------------------------------- /Miner-WPF/Controls/NotifyWindow.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Contract/Contract.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {AB1F9FEF-BCE7-446E-9039-EB215501C773} 8 | Library 9 | Properties 10 | Contract 11 | Contract 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Miner-WPF/Controls/NoticeTextBox.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Media; 4 | 5 | namespace Miner_WPF.Controls 6 | { 7 | /// 8 | /// NoticeTextBox.xaml 的交互逻辑 9 | /// 10 | public partial class NoticeTextBox : UserControl 11 | { 12 | public string Text 13 | { 14 | get { return (string)GetValue(TextProperty); } 15 | set { SetValue(TextProperty, value); } 16 | } 17 | public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(NoticeTextBox), new PropertyMetadata(default(string))); 18 | 19 | public Brush TBorderBrush 20 | { 21 | get { return (Brush)GetValue(TBorderBrushProperty); } 22 | set { SetValue(TBorderBrushProperty, value); } 23 | } 24 | public static readonly DependencyProperty TBorderBrushProperty = DependencyProperty.Register("TBorderBrush", typeof(Brush), typeof(NoticeTextBox), new PropertyMetadata(Brushes.Black)); 25 | 26 | public string BText 27 | { 28 | get { return (string)GetValue(BTextProperty); } 29 | set { SetValue(BTextProperty, value); } 30 | } 31 | public static readonly DependencyProperty BTextProperty = DependencyProperty.Register("BText", typeof(string), typeof(NoticeTextBox), new PropertyMetadata(default(string))); 32 | 33 | public string UText 34 | { 35 | get { return (string)GetValue(UTextProperty); } 36 | set { SetValue(UTextProperty, value); } 37 | } 38 | public static readonly DependencyProperty UTextProperty = DependencyProperty.Register("UText", typeof(string), typeof(NoticeTextBox), new PropertyMetadata(default(string))); 39 | public Visibility UVisibility 40 | { 41 | get { return (Visibility)GetValue(UVisibilityProperty); } 42 | set { SetValue(UVisibilityProperty, value); } 43 | } 44 | public static readonly DependencyProperty UVisibilityProperty = DependencyProperty.Register("UVisibility", typeof(Visibility), typeof(NoticeTextBox), new PropertyMetadata(default(Visibility))); 45 | public NoticeTextBox() 46 | { 47 | InitializeComponent(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Common/Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {084B4296-6DA9-435A-B3F1-403268095A05} 8 | Library 9 | Properties 10 | Common 11 | Common 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /Miner-WPF/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Miner_WPF.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Miner_WPF.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 使用此强类型资源类,为所有资源查找 51 | /// 重写当前线程的 CurrentUICulture 属性。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 查找类似于 (图标) 的 System.Drawing.Icon 类型的本地化资源。 65 | /// 66 | internal static System.Drawing.Icon Ulord { 67 | get { 68 | object obj = ResourceManager.GetObject("Ulord", resourceCulture); 69 | return ((System.Drawing.Icon)(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Common/ProcessControl.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | using System.Linq; 4 | 5 | namespace Common 6 | { 7 | public class ProcessControl 8 | { 9 | private bool alive; 10 | public bool Alive => alive; 11 | #region Create process 12 | public bool CreateProcess(string file, string command, DataReceivedEventHandler outputHandler = default(DataReceivedEventHandler), DataReceivedEventHandler errorHandler = default(DataReceivedEventHandler)) 13 | { 14 | if (TerminateProcess(file)) 15 | { 16 | try 17 | { 18 | ProcessStartInfo processStartInfo = new ProcessStartInfo(file, command); 19 | processStartInfo.CreateNoWindow = true; 20 | processStartInfo.UseShellExecute = false; 21 | processStartInfo.RedirectStandardOutput = true; 22 | processStartInfo.RedirectStandardError = true; 23 | 24 | Process process = Process.Start(processStartInfo); 25 | process.OutputDataReceived += outputHandler; 26 | process.ErrorDataReceived += errorHandler; 27 | process.Exited += (s, e) => alive = false; 28 | process.EnableRaisingEvents = true; 29 | process.BeginOutputReadLine(); 30 | process.BeginErrorReadLine(); 31 | alive = true; 32 | return true; 33 | } 34 | catch 35 | { 36 | alive = false; 37 | return false; 38 | } 39 | } 40 | else 41 | { 42 | return false; 43 | } 44 | } 45 | #endregion 46 | #region Terminate process 47 | public bool TerminateProcess(string file) 48 | { 49 | bool isSuccess = true; 50 | foreach (Process item in GetProcesses(file)) 51 | { 52 | try 53 | { 54 | item.Kill(); 55 | } 56 | catch 57 | { 58 | if (ExistProcess(item.Id)) 59 | { 60 | isSuccess = false; 61 | } 62 | } 63 | } 64 | return isSuccess; 65 | } 66 | private bool ExistProcess(int processId) 67 | { 68 | try 69 | { 70 | return Process.GetProcessById(processId) != null; 71 | } 72 | catch 73 | { 74 | return false; 75 | } 76 | } 77 | private Process[] GetProcesses(string file) 78 | { 79 | try 80 | { 81 | return Process.GetProcessesByName(Path.GetFileNameWithoutExtension(file)).Where(p => p.MainModule.FileName == file).ToArray(); 82 | } 83 | catch 84 | { 85 | return new Process[0]; 86 | } 87 | } 88 | #endregion 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Ulord/Ulord.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F82039B3-5473-4536-8834-7BA7AC66F103} 8 | Library 9 | Properties 10 | Ulord 11 | Ulord 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | {084b4296-6da9-435a-b3f1-403268095a05} 51 | Common 52 | False 53 | 54 | 55 | {ab1f9fef-bce7-446e-9039-eb215501c773} 56 | Contract 57 | False 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | xcopy "$(TargetPath)" "$(SolutionDir)Miner-WPF\bin\Debug\plugins\" /Y 67 | xcopy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)Miner-WPF\bin\Debug\plugins\" /Y 68 | xcopy "$(TargetPath)" "$(SolutionDir)Test\bin\Debug\plugins\" /Y 69 | xcopy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)Test\bin\Debug\plugins\" /Y 70 | 71 | -------------------------------------------------------------------------------- /Test/Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {034CD5AF-F956-4FE4-B79F-EF907A653E89} 8 | Exe 9 | Test 10 | Test 11 | v4.6 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | false 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {084b4296-6da9-435a-b3f1-403268095a05} 61 | Common 62 | 63 | 64 | {ab1f9fef-bce7-446e-9039-eb215501c773} 65 | Contract 66 | 67 | 68 | 69 | 70 | echo f |xcopy "$(SolutionDir)Miner-WPF\UMiner.exe" "$(TargetDir)UMiner.exe" /Y 71 | 72 | -------------------------------------------------------------------------------- /Common/FileOperation.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.IO; 4 | using System.IO.IsolatedStorage; 5 | 6 | namespace Common 7 | { 8 | public class FileOperation 9 | { 10 | public static void SolatedStorageWrite(string file, T t) 11 | { 12 | SolatedStorageWrite(file, JsonConvert.SerializeObject(t)); 13 | } 14 | public static void SolatedStorageWrite(string file, string text) 15 | { 16 | using (IsolatedStorageFile isolatedStrorageFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null)) 17 | { 18 | if (!isolatedStrorageFile.FileExists(file)) 19 | { 20 | string dir = Path.GetDirectoryName(file); 21 | if (!string.IsNullOrEmpty(dir) && !isolatedStrorageFile.DirectoryExists(dir)) 22 | { 23 | isolatedStrorageFile.CreateDirectory(dir); 24 | } 25 | } 26 | using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(file, FileMode.Create, isolatedStrorageFile)) 27 | { 28 | using (StreamWriter streamWriter = new StreamWriter(isolatedStorageFileStream)) 29 | { 30 | streamWriter.Write(text); 31 | } 32 | } 33 | } 34 | } 35 | public static T SolatedStorageRead(string file) 36 | { 37 | return JsonConvert.DeserializeObject(SolatedStorageRead(file) ?? string.Empty); 38 | } 39 | public static string SolatedStorageRead(string file) 40 | { 41 | using (IsolatedStorageFile isolatedStrorageFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly, null, null)) 42 | { 43 | if (!isolatedStrorageFile.FileExists(file)) 44 | { 45 | return default(string); 46 | } 47 | using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(file, FileMode.Open, isolatedStrorageFile)) 48 | { 49 | using (StreamReader streamReader = new StreamReader(isolatedStorageFileStream)) 50 | { 51 | return streamReader.ReadToEnd(); 52 | } 53 | } 54 | } 55 | } 56 | public static void LocalWrite(string file, T t) 57 | { 58 | if (string.IsNullOrEmpty(Path.GetPathRoot(file))) 59 | { 60 | file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file); 61 | } 62 | string dir = Path.GetDirectoryName(file); 63 | if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) 64 | { 65 | Directory.CreateDirectory(dir); 66 | } 67 | File.WriteAllText(file, JsonConvert.SerializeObject(t)); 68 | } 69 | public static T LocalRead(string file) 70 | { 71 | if (string.IsNullOrEmpty(Path.GetPathRoot(file))) 72 | { 73 | file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file); 74 | } 75 | if (File.Exists(file)) 76 | { 77 | string json = File.ReadAllText(file); 78 | if (!string.IsNullOrEmpty(json)) 79 | { 80 | return JsonConvert.DeserializeObject(json); 81 | } 82 | } 83 | return default(T); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Miner-WPF/Controls/WPFNotifyIcon.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Miner_WPF.Controls 2 | { 3 | partial class WPFNotifyIcon 4 | { 5 | /// 6 | /// 必需的设计器变量。 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// 清理所有正在使用的资源。 12 | /// 13 | /// 如果应释放托管资源,为 true;否则为 false。 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region 组件设计器生成的代码 24 | 25 | /// 26 | /// 设计器支持所需的方法 - 不要修改 27 | /// 使用代码编辑器修改此方法的内容。 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); 33 | this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); 34 | this.打开ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 35 | this.开机启动ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.关于我们ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 37 | this.退出ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 38 | this.contextMenuStrip.SuspendLayout(); 39 | this.SuspendLayout(); 40 | // 41 | // notifyIcon 42 | // 43 | this.notifyIcon.ContextMenuStrip = this.contextMenuStrip; 44 | this.notifyIcon.Text = "notifyIcon"; 45 | this.notifyIcon.Visible = true; 46 | // 47 | // contextMenuStrip 48 | // 49 | this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 50 | this.打开ToolStripMenuItem, 51 | this.开机启动ToolStripMenuItem, 52 | this.关于我们ToolStripMenuItem, 53 | this.退出ToolStripMenuItem}); 54 | this.contextMenuStrip.Name = "contextMenuStrip1"; 55 | this.contextMenuStrip.Size = new System.Drawing.Size(125, 92); 56 | // 57 | // 打开ToolStripMenuItem 58 | // 59 | this.打开ToolStripMenuItem.Name = "打开ToolStripMenuItem"; 60 | this.打开ToolStripMenuItem.Size = new System.Drawing.Size(124, 22); 61 | this.打开ToolStripMenuItem.Text = "打开"; 62 | // 63 | // 开机启动ToolStripMenuItem 64 | // 65 | this.开机启动ToolStripMenuItem.Checked = true; 66 | this.开机启动ToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; 67 | this.开机启动ToolStripMenuItem.Name = "开机启动ToolStripMenuItem"; 68 | this.开机启动ToolStripMenuItem.Size = new System.Drawing.Size(124, 22); 69 | this.开机启动ToolStripMenuItem.Text = "开机启动"; 70 | // 71 | // 关于我们ToolStripMenuItem 72 | // 73 | this.关于我们ToolStripMenuItem.Name = "关于我们ToolStripMenuItem"; 74 | this.关于我们ToolStripMenuItem.Size = new System.Drawing.Size(124, 22); 75 | this.关于我们ToolStripMenuItem.Text = "关于我们"; 76 | // 77 | // 退出ToolStripMenuItem 78 | // 79 | this.退出ToolStripMenuItem.Name = "退出ToolStripMenuItem"; 80 | this.退出ToolStripMenuItem.Size = new System.Drawing.Size(124, 22); 81 | this.退出ToolStripMenuItem.Text = "退出"; 82 | this.contextMenuStrip.ResumeLayout(false); 83 | this.ResumeLayout(false); 84 | 85 | } 86 | 87 | #endregion 88 | 89 | public System.Windows.Forms.NotifyIcon notifyIcon; 90 | public System.Windows.Forms.ContextMenuStrip contextMenuStrip; 91 | public System.Windows.Forms.ToolStripMenuItem 打开ToolStripMenuItem; 92 | public System.Windows.Forms.ToolStripMenuItem 开机启动ToolStripMenuItem; 93 | public System.Windows.Forms.ToolStripMenuItem 关于我们ToolStripMenuItem; 94 | public System.Windows.Forms.ToolStripMenuItem 退出ToolStripMenuItem; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Miner-WPF/Commons/FileHelper.cs: -------------------------------------------------------------------------------- 1 | using Miner_WPF.Models; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Text; 8 | 9 | namespace Miner_WPF.Commons 10 | { 11 | public class FileHelper 12 | { 13 | public static void SaveString(string file, string text) 14 | { 15 | File.WriteAllBytes(file, Encoding.UTF8.GetBytes(text)); 16 | } 17 | public static string LoadString(string file) 18 | { 19 | return Encoding.UTF8.GetString(File.ReadAllBytes(file)); 20 | } 21 | public static AppInfo GetAppInfo(string url) 22 | { 23 | using (WebClient webClient = new WebClient() { Proxy = null, Encoding = Encoding.UTF8 }) 24 | { 25 | string json = webClient.DownloadString(url); 26 | return JsonConvert.DeserializeObject(json); 27 | } 28 | } 29 | public static void DownloadFile(string url, string path, Action action = default(Action)) 30 | { 31 | // Test address 32 | // url = "https://download.microsoft.com/download/6/7/4/674A281B-84BF-4B49-848C-14873B22F977/SQLManagementStudio_x64_ENU.exe"; 33 | using (WebResponse response = WebRequest.Create(url).GetResponse()) 34 | { 35 | long totalBytes = response.ContentLength; 36 | long receivedBytes = 0; 37 | int bufferSize = 1024 * 16; 38 | int chunkCount = 2; 39 | long chunkBytes = (int)Math.Ceiling(totalBytes * 1.0 / chunkCount); 40 | long lastChunkBytes = totalBytes - chunkBytes * (chunkCount - 1); 41 | Tuple[] chunkInfos = new Tuple[chunkCount]; 42 | for (int i = 0; i < chunkCount; i++) 43 | { 44 | if (i < chunkCount - 1) 45 | { 46 | chunkInfos[i] = new Tuple(chunkBytes * i, chunkBytes); 47 | } 48 | else 49 | { 50 | chunkInfos[i] = new Tuple(chunkBytes * i, lastChunkBytes); 51 | } 52 | } 53 | chunkInfos.AsParallel().ForAll(p => 54 | { 55 | DownloadFile(url, path, p.Item1, p.Item2, bufferSize, totalBytes, ref receivedBytes, action); 56 | }); 57 | } 58 | } 59 | private static void DownloadFile(string url, string path, long offset, long count, int bufferSize, long totalBytes, ref long receivedBytes, Action action = default(Action)) 60 | { 61 | HttpWebRequest httpWebRequest = WebRequest.Create(url) as HttpWebRequest; 62 | httpWebRequest.AddRange(offset, offset + count - 1); 63 | using (WebResponse response = httpWebRequest.GetResponse()) 64 | { 65 | byte[] bytes = new byte[bufferSize]; 66 | int length = 0; 67 | using (Stream stream = response.GetResponseStream()) 68 | { 69 | using (FileStream writer = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite, bufferSize, true)) 70 | { 71 | while ((length = stream.Read(bytes, 0, bytes.Length)) > 0) 72 | { 73 | writer.Seek(offset, SeekOrigin.Begin); 74 | writer.Write(bytes, 0, length); 75 | offset += length; 76 | receivedBytes += length; 77 | action?.Invoke($"更新进度: {(receivedBytes * 1.0 / totalBytes):P}"); 78 | } 79 | } 80 | } 81 | } 82 | httpWebRequest.Abort(); 83 | } 84 | public static string ComputeFileMD5(string path) 85 | { 86 | using (FileStream reader = new FileStream(path, FileMode.Open, FileAccess.Read)) 87 | { 88 | System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); 89 | byte[] bys = md5.ComputeHash(reader); 90 | StringBuilder sb = new StringBuilder(); 91 | foreach (byte item in bys) 92 | { 93 | sb.Append(item.ToString("X2")); 94 | } 95 | return sb.ToString(); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Miner-WPF/Controls/NoticeTextBox.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Miner-WPF/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Ulord.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | -------------------------------------------------------------------------------- /Miner-WPF/Controls/WPFNotifyIcon.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 55 122 | 123 | 124 | 128, 17 125 | 126 | 127 | False 128 | 129 | -------------------------------------------------------------------------------- /Miner-WPF/Commons/Win32Native.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace Miner_WPF.Commons 7 | { 8 | internal delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); 9 | 10 | internal class NativeMethods 11 | { 12 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 13 | public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc callback, IntPtr hMod, uint dwThreadId); 14 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 15 | public static extern bool UnhookWindowsHookEx(IntPtr hhk); 16 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 17 | public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); 18 | } 19 | 20 | internal enum HookType 21 | { 22 | WH_KEYBOARD = 2, 23 | WH_MOUSE = 7, 24 | WH_KEYBOARD_LL = 13, 25 | WH_MOUSE_LL = 14 26 | } 27 | 28 | internal enum MouseMessage 29 | { 30 | WM_MOUSEMOVE = 0x0200, 31 | WM_LBUTTONDOWN = 0x0201, 32 | WM_LBUTTONUP = 0x0202, 33 | WM_LBUTTONDBLCLK = 0x0203, 34 | WM_RBUTTONDOWN = 0x0204, 35 | WM_RBUTTONUP = 0x0205, 36 | WM_RBUTTONDBLCLK = 0x0206, 37 | WM_MBUTTONDOWN = 0x0207, 38 | WM_MBUTTONUP = 0x0208, 39 | WM_MBUTTONDBLCLK = 0x0209, 40 | 41 | WM_MOUSEWHEEL = 0x020A, 42 | WM_MOUSEHWHEEL = 0x020E, 43 | 44 | WM_NCMOUSEMOVE = 0x00A0, 45 | WM_NCLBUTTONDOWN = 0x00A1, 46 | WM_NCLBUTTONUP = 0x00A2, 47 | WM_NCLBUTTONDBLCLK = 0x00A3, 48 | WM_NCRBUTTONDOWN = 0x00A4, 49 | WM_NCRBUTTONUP = 0x00A5, 50 | WM_NCRBUTTONDBLCLK = 0x00A6, 51 | WM_NCMBUTTONDOWN = 0x00A7, 52 | WM_NCMBUTTONUP = 0x00A8, 53 | WM_NCMBUTTONDBLCLK = 0x00A9 54 | } 55 | 56 | public class Win32Native 57 | { 58 | [DllImport("User32.dll")] 59 | private static extern bool GetLastInputInfo(ref LASTINPUTINFO Dummy); 60 | [DllImport("User32.dll")] 61 | private static extern bool GetCursorPos(out POINT pt); 62 | [DllImport("User32.dll", SetLastError = true)] 63 | public static extern bool BringWindowToTop(IntPtr hWnd); 64 | internal struct LASTINPUTINFO 65 | { 66 | public uint cbSize; 67 | public uint dwTime; 68 | } 69 | internal struct POINT 70 | { 71 | public int X; 72 | public int Y; 73 | public POINT(int x, int y) 74 | { 75 | this.X = x; 76 | this.Y = y; 77 | } 78 | } 79 | public static uint GetIdleTime() 80 | { 81 | LASTINPUTINFO LastUserAction = new LASTINPUTINFO(); 82 | LastUserAction.cbSize = (uint)Marshal.SizeOf(LastUserAction); 83 | GetLastInputInfo(ref LastUserAction); 84 | uint idleTime = (uint)Environment.TickCount - LastUserAction.dwTime; 85 | return idleTime; 86 | } 87 | public static Tuple GetCursorPos() 88 | { 89 | POINT point; 90 | GetCursorPos(out point); 91 | return new Tuple(point.X, point.Y); 92 | } 93 | private static event EventHandler MouseEventHandler; 94 | 95 | private static IntPtr hGlobalLLMouseHook = IntPtr.Zero; 96 | private static HookProc globalLLMouseHookCallback = null; 97 | 98 | public static bool SetGlobalLLMouseHook(EventHandler handler) 99 | { 100 | MouseEventHandler += handler; 101 | // Create an instance of HookProc. 102 | globalLLMouseHookCallback = new HookProc(LowLevelMouseProc); 103 | 104 | hGlobalLLMouseHook = NativeMethods.SetWindowsHookEx( 105 | HookType.WH_MOUSE_LL, // Must be LL for the global hook 106 | globalLLMouseHookCallback, 107 | // Get the handle of the current module 108 | Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 109 | // The hook procedure is associated with all existing threads running 110 | // in the same desktop as the calling thread. 111 | 0); 112 | return hGlobalLLMouseHook != IntPtr.Zero; 113 | } 114 | 115 | public static bool RemoveGlobalLLMouseHook() 116 | { 117 | if (hGlobalLLMouseHook != IntPtr.Zero) 118 | { 119 | if (!NativeMethods.UnhookWindowsHookEx(hGlobalLLMouseHook)) 120 | return false; 121 | hGlobalLLMouseHook = IntPtr.Zero; 122 | } 123 | return true; 124 | } 125 | 126 | private static int LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam) 127 | { 128 | if (nCode >= 0) 129 | { 130 | MouseMessage wmMouse = (MouseMessage)wParam; 131 | if (wmMouse == MouseMessage.WM_LBUTTONDOWN || wmMouse == MouseMessage.WM_RBUTTONDOWN) 132 | { 133 | MouseEventHandler?.Invoke(default(object), default(EventArgs)); 134 | } 135 | } 136 | return NativeMethods.CallNextHookEx(hGlobalLLMouseHook, nCode, wParam, lParam); 137 | } 138 | 139 | public static void SetRegistryKey(string registryKeyPath, params RegistryKeyValue[] registryKeyValues) 140 | { 141 | using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(registryKeyPath, true)) 142 | { 143 | foreach (RegistryKeyValue item in registryKeyValues) 144 | { 145 | registryKey.SetValue(item.Key, item.Value, item.RegistryValueKind); 146 | } 147 | } 148 | } 149 | public static void DeleteRegistryKey(string registryKeyPath, params string[] keys) 150 | { 151 | using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(registryKeyPath, true)) 152 | { 153 | foreach (string key in keys) 154 | { 155 | registryKey.DeleteValue(key); 156 | } 157 | } 158 | } 159 | public static object GetRegistryValue(string registryKeyPath, string key) 160 | { 161 | using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(registryKeyPath)) 162 | { 163 | return registryKey.GetValue(key); 164 | } 165 | } 166 | } 167 | public class RegistryKeyValue 168 | { 169 | public RegistryKeyValue(string key, object value, RegistryValueKind registryValueKind) 170 | { 171 | Key = key; 172 | Value = value; 173 | RegistryValueKind = registryValueKind; 174 | } 175 | public RegistryKeyValue(string key, object value) : this(key, value, RegistryValueKind.Unknown) 176 | { 177 | } 178 | public string Key { set; get; } 179 | public object Value { set; get; } 180 | public RegistryValueKind RegistryValueKind { set; get; } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /Miner-WPF/Miner-WPF.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08} 8 | WinExe 9 | Miner_WPF 10 | UlordMiner 11 | v4.6 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | false 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Debug\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | Ulord.ico 39 | 40 | 41 | Miner_WPF.Program 42 | 43 | 44 | 45 | ..\packages\Microsoft.Expression.Drawing.3.0.0\lib\net45\Microsoft.Expression.Drawing.dll 46 | True 47 | 48 | 49 | ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 4.0 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | MSBuild:Compile 76 | Designer 77 | 78 | 79 | 80 | 81 | 82 | NoticeTextBox.xaml 83 | 84 | 85 | NotifyWindow.xaml 86 | 87 | 88 | Component 89 | 90 | 91 | WPFNotifyIcon.cs 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | True 107 | True 108 | Resources.resx 109 | 110 | 111 | WindowConfig.xaml 112 | 113 | 114 | Designer 115 | MSBuild:Compile 116 | 117 | 118 | Designer 119 | MSBuild:Compile 120 | 121 | 122 | Designer 123 | MSBuild:Compile 124 | 125 | 126 | MSBuild:Compile 127 | Designer 128 | 129 | 130 | App.xaml 131 | Code 132 | 133 | 134 | MainWindow.xaml 135 | Code 136 | 137 | 138 | Designer 139 | MSBuild:Compile 140 | 141 | 142 | 143 | 144 | Code 145 | 146 | 147 | True 148 | Settings.settings 149 | True 150 | 151 | 152 | WPFNotifyIcon.cs 153 | 154 | 155 | ResXFileCodeGenerator 156 | Resources.Designer.cs 157 | 158 | 159 | 160 | SettingsSingleFileGenerator 161 | Settings.Designer.cs 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | {084b4296-6da9-435a-b3f1-403268095a05} 174 | Common 175 | 176 | 177 | {ab1f9fef-bce7-446e-9039-eb215501c773} 178 | Contract 179 | 180 | 181 | 182 | 183 | Always 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | echo f |xcopy "$(ProjectDir)Ulord.ico" "$(TargetDir)Ulord.ico" /Y 196 | 197 | -------------------------------------------------------------------------------- /Test/Program.cs: -------------------------------------------------------------------------------- 1 | using Common; 2 | using Contract; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.ComponentModel.Composition; 6 | using System.ComponentModel.Composition.Hosting; 7 | using System.Diagnostics; 8 | using System.IO; 9 | using System.Net; 10 | using System.Runtime.InteropServices; 11 | using System.Threading; 12 | 13 | namespace Test 14 | { 15 | class Program 16 | { 17 | public delegate bool HandlerRoutine(int ctrlType); 18 | [DllImport("kernel32.dll")] 19 | private static extern bool SetConsoleCtrlHandler(HandlerRoutine handlerRoutine, bool Add); 20 | 21 | [Import] 22 | public IMiner Miner { set; get; } 23 | static void Main(string[] args) 24 | { 25 | Program program = new Program(); 26 | program.Inject(); 27 | program.Test(); 28 | } 29 | 30 | public void Inject() 31 | { 32 | Console.WriteLine("Load component..."); 33 | Console.ReadLine(); 34 | DirectoryCatalog directoryCatalog = new DirectoryCatalog(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins")); 35 | CompositionContainer compositionContainer = new CompositionContainer(directoryCatalog); 36 | try 37 | { 38 | compositionContainer.ComposeParts(this); 39 | } 40 | catch (ChangeRejectedException ex) 41 | { 42 | Console.WriteLine($"Exception: {ex.Message}"); 43 | } 44 | Console.WriteLine("Load component successed!"); 45 | Console.ReadLine(); 46 | } 47 | 48 | private void Test() 49 | { 50 | #region Initialize 51 | Console.WriteLine("Init component..."); 52 | Console.ReadLine(); 53 | string configFile = "config.json"; 54 | string request = "Results"; 55 | string file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UlordRig.exe"); 56 | Func format = c => $"-o \"stratum+tcp://{c.Url}\" -u \"{(string.IsNullOrEmpty(c.Id) ? c.User : $"{c.User}.{c.Id}")}\" -p \"{c.Pass}\" -t {c.Thread} --max-cpu-usage {c.CpuUsage}"/*+" -q"*/; 57 | #region Load config 58 | Console.WriteLine("Load last config..."); 59 | Console.ReadLine(); 60 | Config config = new Config(); 61 | Config lastConfig = LoadConfig(configFile); 62 | if (lastConfig != null) 63 | { 64 | config.Url = lastConfig.Url; 65 | config.Pass = lastConfig.Pass; 66 | config.User = lastConfig.User; 67 | config.Id = lastConfig.Id; 68 | config.Thread = lastConfig.Thread; 69 | config.CpuUsage = lastConfig.CpuUsage; 70 | config.Automatic = lastConfig.Automatic; 71 | Console.WriteLine($"Last config: {lastConfig.Url}"); 72 | } 73 | else 74 | { 75 | config.Url = "u2pool.org:7100"; 76 | config.Pass = "x"; 77 | config.User = "UQhw1PcMUg1TrodymTWWihed7ZonBdkgi6"; 78 | config.Id = "test"; 79 | config.Thread = 2; 80 | config.CpuUsage = 50; 81 | config.Automatic = false; 82 | } 83 | Console.WriteLine("Load last config successed!"); 84 | Console.ReadLine(); 85 | #endregion 86 | #region Performance 87 | Func fr = s => 88 | { 89 | s = s.Substring(s.IndexOf('H')).Replace("/ ", ":").Replace(" ", "").Replace("Hashrate", "{\"Hashrate\"").Replace("accept", ",\"Accept\"").Replace("total", ",\"Total\"") + "}"; 90 | return JsonConvert.DeserializeObject(s); 91 | }; 92 | Action rp = (p, r) => p.SetPerformance(r.Total, r.Accept, r.Hashrate, 0); 93 | #endregion 94 | DataReceivedEventHandler dataReceivedEventHandler = (s, e) => Debug.WriteLine(e.Data); 95 | Console.WriteLine("Init component successed!"); 96 | Console.ReadLine(); 97 | #endregion 98 | 99 | #region Function test 100 | Console.WriteLine("Start mining..."); 101 | Console.ReadLine(); 102 | bool isRun = Miner.Run(file, format(config), dataReceivedEventHandler, dataReceivedEventHandler); 103 | bool exit = false; 104 | HandlerRoutine handlerRoutine = (i) => 105 | { 106 | switch ((dwCtrlType)i) 107 | { 108 | case dwCtrlType.CTRL_C_EVENT: 109 | Console.WriteLine("Terminate mining..."); 110 | isRun = !Miner.Terminate(file); 111 | Console.WriteLine($"Terminate mining {(!isRun ? "successed" : "Failed")}!"); 112 | 113 | Console.WriteLine("Get mining status..."); 114 | isRun = Miner.Alive(file, format(config)); 115 | Console.WriteLine($"Mining status: {(isRun ? "Runing" : "Stopped")}"); 116 | 117 | Console.WriteLine("Save config..."); 118 | SaveConfig(configFile, config); 119 | Console.WriteLine("Save config successed!"); 120 | exit = true; 121 | return true; 122 | case dwCtrlType.CTRL_BREAK_EVENT: 123 | case dwCtrlType.CTRL_CLOSE_EVENT: 124 | case dwCtrlType.CTRL_LOGOFF_EVENT: 125 | case dwCtrlType.CTRL_SHUTDOWN_EVENT: 126 | default: 127 | return false; 128 | } 129 | }; 130 | Console.WriteLine($"Start mining {(isRun ? "successed" : "Failed")}!"); 131 | bool setSuccess = SetConsoleCtrlHandler(handlerRoutine, true); 132 | Console.WriteLine($"Inject Crtl+C event handler {(setSuccess ? "successed" : "failed")}"); 133 | Console.ReadLine(); 134 | 135 | Console.WriteLine("Get perfmon..."); 136 | Console.ReadLine(); 137 | while (true) 138 | { 139 | if (exit) 140 | { 141 | break; 142 | } 143 | IPerformance perfmon = Miner.GetPerformance(file, format(config), new IPEndPoint(IPAddress.Loopback, 8087), request, fr, rp, out isRun); 144 | Console.WriteLine($"Performance: {JsonConvert.SerializeObject(perfmon)}"); 145 | Thread.Sleep(1000); 146 | } 147 | #endregion 148 | 149 | Console.ReadLine(); 150 | } 151 | static void SaveConfig(string file, Config config, StorgaeType strorageType = StorgaeType.SolatedStorage) 152 | { 153 | if (strorageType == StorgaeType.LocalStorage) 154 | { 155 | FileOperation.LocalWrite(file, config); 156 | } 157 | else 158 | { 159 | string isolatedFile = $"Configuration/Mining/{file}"; 160 | FileOperation.SolatedStorageWrite(isolatedFile, config); 161 | } 162 | } 163 | static Config LoadConfig(string file, StorgaeType strorageType = StorgaeType.SolatedStorage) 164 | { 165 | if (strorageType == StorgaeType.LocalStorage) 166 | { 167 | return FileOperation.LocalRead(file); 168 | } 169 | else 170 | { 171 | string isolatedFile = $"Configuration/Mining/{file}"; 172 | return FileOperation.SolatedStorageRead(isolatedFile); 173 | } 174 | } 175 | } 176 | enum StorgaeType 177 | { 178 | LocalStorage, 179 | SolatedStorage 180 | } 181 | enum dwCtrlType 182 | { 183 | CTRL_C_EVENT = 0, 184 | //A CTRL+C signal was received, either from keyboard input or from a signal generated by the GenerateConsoleCtrlEvent function. 185 | CTRL_BREAK_EVENT = 1, 186 | //A CTRL+BREAK signal was received, either from keyboard input or from a signal generated by GenerateConsoleCtrlEvent. 187 | CTRL_CLOSE_EVENT = 2, 188 | //A signal that the system sends to all processes attached to a console when the user closes the console (either by clicking Close on the console window's window menu, or by clicking the End Task button command from Task Manager). 189 | CTRL_LOGOFF_EVENT = 5, 190 | //A signal that the system sends to all console processes when a user is logging off. This signal does not indicate which user is logging off, so no assumptions can be made. 191 | CTRL_SHUTDOWN_EVENT = 6 192 | //A signal that the system sends when the system is shutting down. Interactive applications are not present by the time the system sends this signal, therefore it can be received only be services in this situation. Services also have their own notification mechanism for shutdown events. For more information, see Handler. 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /Miner.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contract", "Contract\Contract.csproj", "{AB1F9FEF-BCE7-446E-9039-EB215501C773}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ulord", "Ulord\Ulord.csproj", "{F82039B3-5473-4536-8834-7BA7AC66F103}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{084B4296-6DA9-435A-B3F1-403268095A05}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{034CD5AF-F956-4FE4-B79F-EF907A653E89}" 13 | ProjectSection(ProjectDependencies) = postProject 14 | {F82039B3-5473-4536-8834-7BA7AC66F103} = {F82039B3-5473-4536-8834-7BA7AC66F103} 15 | EndProjectSection 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Miner-WPF", "Miner-WPF\Miner-WPF.csproj", "{83A50874-901B-4B77-B6B0-60AEEEA4CD08}" 18 | ProjectSection(ProjectDependencies) = postProject 19 | {F82039B3-5473-4536-8834-7BA7AC66F103} = {F82039B3-5473-4536-8834-7BA7AC66F103} 20 | EndProjectSection 21 | EndProject 22 | Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Installer", "Installer\Installer.vdproj", "{36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | Debug|ARM = Debug|ARM 28 | Debug|x64 = Debug|x64 29 | Debug|x86 = Debug|x86 30 | Release|Any CPU = Release|Any CPU 31 | Release|ARM = Release|ARM 32 | Release|x64 = Release|x64 33 | Release|x86 = Release|x86 34 | EndGlobalSection 35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 36 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Debug|ARM.ActiveCfg = Debug|Any CPU 39 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Debug|ARM.Build.0 = Debug|Any CPU 40 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Debug|x64.ActiveCfg = Debug|Any CPU 41 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Debug|x64.Build.0 = Debug|Any CPU 42 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Debug|x86.ActiveCfg = Debug|Any CPU 43 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Debug|x86.Build.0 = Debug|Any CPU 44 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Release|ARM.ActiveCfg = Release|Any CPU 47 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Release|ARM.Build.0 = Release|Any CPU 48 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Release|x64.ActiveCfg = Release|Any CPU 49 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Release|x64.Build.0 = Release|Any CPU 50 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Release|x86.ActiveCfg = Release|Any CPU 51 | {AB1F9FEF-BCE7-446E-9039-EB215501C773}.Release|x86.Build.0 = Release|Any CPU 52 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Debug|ARM.ActiveCfg = Debug|Any CPU 55 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Debug|ARM.Build.0 = Debug|Any CPU 56 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Debug|x64.ActiveCfg = Debug|Any CPU 57 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Debug|x64.Build.0 = Debug|Any CPU 58 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Debug|x86.ActiveCfg = Debug|Any CPU 59 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Debug|x86.Build.0 = Debug|Any CPU 60 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Release|ARM.ActiveCfg = Release|Any CPU 63 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Release|ARM.Build.0 = Release|Any CPU 64 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Release|x64.ActiveCfg = Release|Any CPU 65 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Release|x64.Build.0 = Release|Any CPU 66 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Release|x86.ActiveCfg = Release|Any CPU 67 | {F82039B3-5473-4536-8834-7BA7AC66F103}.Release|x86.Build.0 = Release|Any CPU 68 | {084B4296-6DA9-435A-B3F1-403268095A05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {084B4296-6DA9-435A-B3F1-403268095A05}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {084B4296-6DA9-435A-B3F1-403268095A05}.Debug|ARM.ActiveCfg = Debug|Any CPU 71 | {084B4296-6DA9-435A-B3F1-403268095A05}.Debug|ARM.Build.0 = Debug|Any CPU 72 | {084B4296-6DA9-435A-B3F1-403268095A05}.Debug|x64.ActiveCfg = Debug|Any CPU 73 | {084B4296-6DA9-435A-B3F1-403268095A05}.Debug|x64.Build.0 = Debug|Any CPU 74 | {084B4296-6DA9-435A-B3F1-403268095A05}.Debug|x86.ActiveCfg = Debug|Any CPU 75 | {084B4296-6DA9-435A-B3F1-403268095A05}.Debug|x86.Build.0 = Debug|Any CPU 76 | {084B4296-6DA9-435A-B3F1-403268095A05}.Release|Any CPU.ActiveCfg = Release|Any CPU 77 | {084B4296-6DA9-435A-B3F1-403268095A05}.Release|Any CPU.Build.0 = Release|Any CPU 78 | {084B4296-6DA9-435A-B3F1-403268095A05}.Release|ARM.ActiveCfg = Release|Any CPU 79 | {084B4296-6DA9-435A-B3F1-403268095A05}.Release|ARM.Build.0 = Release|Any CPU 80 | {084B4296-6DA9-435A-B3F1-403268095A05}.Release|x64.ActiveCfg = Release|Any CPU 81 | {084B4296-6DA9-435A-B3F1-403268095A05}.Release|x64.Build.0 = Release|Any CPU 82 | {084B4296-6DA9-435A-B3F1-403268095A05}.Release|x86.ActiveCfg = Release|Any CPU 83 | {084B4296-6DA9-435A-B3F1-403268095A05}.Release|x86.Build.0 = Release|Any CPU 84 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 85 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Debug|Any CPU.Build.0 = Debug|Any CPU 86 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Debug|ARM.ActiveCfg = Debug|Any CPU 87 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Debug|ARM.Build.0 = Debug|Any CPU 88 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Debug|x64.ActiveCfg = Debug|Any CPU 89 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Debug|x64.Build.0 = Debug|Any CPU 90 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Debug|x86.ActiveCfg = Debug|Any CPU 91 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Debug|x86.Build.0 = Debug|Any CPU 92 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Release|Any CPU.ActiveCfg = Release|Any CPU 93 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Release|Any CPU.Build.0 = Release|Any CPU 94 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Release|ARM.ActiveCfg = Release|Any CPU 95 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Release|ARM.Build.0 = Release|Any CPU 96 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Release|x64.ActiveCfg = Release|Any CPU 97 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Release|x64.Build.0 = Release|Any CPU 98 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Release|x86.ActiveCfg = Release|Any CPU 99 | {034CD5AF-F956-4FE4-B79F-EF907A653E89}.Release|x86.Build.0 = Release|Any CPU 100 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 101 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Debug|Any CPU.Build.0 = Debug|Any CPU 102 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Debug|ARM.ActiveCfg = Debug|Any CPU 103 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Debug|ARM.Build.0 = Debug|Any CPU 104 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Debug|x64.ActiveCfg = Debug|Any CPU 105 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Debug|x64.Build.0 = Debug|Any CPU 106 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Debug|x86.ActiveCfg = Debug|Any CPU 107 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Debug|x86.Build.0 = Debug|Any CPU 108 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Release|Any CPU.ActiveCfg = Release|Any CPU 109 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Release|Any CPU.Build.0 = Release|Any CPU 110 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Release|ARM.ActiveCfg = Release|Any CPU 111 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Release|ARM.Build.0 = Release|Any CPU 112 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Release|x64.ActiveCfg = Release|Any CPU 113 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Release|x64.Build.0 = Release|Any CPU 114 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Release|x86.ActiveCfg = Release|Any CPU 115 | {83A50874-901B-4B77-B6B0-60AEEEA4CD08}.Release|x86.Build.0 = Release|Any CPU 116 | {36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}.Debug|Any CPU.ActiveCfg = Debug 117 | {36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}.Debug|ARM.ActiveCfg = Debug 118 | {36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}.Debug|x64.ActiveCfg = Debug 119 | {36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}.Debug|x86.ActiveCfg = Debug 120 | {36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}.Release|Any CPU.ActiveCfg = Release 121 | {36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}.Release|ARM.ActiveCfg = Release 122 | {36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}.Release|x64.ActiveCfg = Release 123 | {36CF04D3-B58D-4FAC-BEEE-818FBF0EC555}.Release|x86.ActiveCfg = Release 124 | EndGlobalSection 125 | GlobalSection(SolutionProperties) = preSolution 126 | HideSolutionNode = FALSE 127 | EndGlobalSection 128 | GlobalSection(ExtensibilityGlobals) = postSolution 129 | SolutionGuid = {C1B6441F-AD71-4BB4-AF80-9962528896E3} 130 | EndGlobalSection 131 | EndGlobal 132 | -------------------------------------------------------------------------------- /Miner-WPF/Commons/Configuration.cs: -------------------------------------------------------------------------------- 1 | using Common; 2 | using Contract; 3 | using Miner_WPF.Models; 4 | using Newtonsoft.Json; 5 | using System; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Net; 9 | using System.Text.RegularExpressions; 10 | using System.Windows; 11 | 12 | namespace Miner_WPF.Commons 13 | { 14 | public class Configuration 15 | { 16 | private static object asyncConfigRoot = new object(); 17 | private static object asyncCounterRoot = new object(); 18 | private static readonly string CONFIGPATH = "config.json"; 19 | private static PerformanceCounter performanceCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); 20 | 21 | private static string file; 22 | private static IMiner miner; 23 | private static Config config; 24 | private static string request; 25 | private static IPEndPoint endPoint; 26 | private static Func format; 27 | 28 | private static Func parseResult; 29 | private static Action setPerformance; 30 | 31 | private static EventHandler exitHandler; 32 | private static DataReceivedEventHandler errorHandler; 33 | private static DataReceivedEventHandler outputHandler; 34 | 35 | private static string validateCode; 36 | 37 | internal static void Init(IMiner minerd, Action action = null) 38 | { 39 | file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UlordRig.exe"); 40 | string md5File = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.bin"); 41 | string fileMD5 = default(string); 42 | try 43 | { 44 | action?.Invoke("正在获取最新挖矿软件信息..."); 45 | AppInfo appInfo = FileHelper.GetAppInfo("http://backup.u1pool.com/api/rig_stats"); 46 | appInfo.Version = Regex.Match(appInfo.Version, "\\d[\\d\\.]+")?.Value; 47 | if (!File.Exists(file) || FileVersionInfo.GetVersionInfo(file).ProductVersion != appInfo.Version || FileHelper.ComputeFileMD5(file) != appInfo.MD5.ToUpper()) 48 | { 49 | action?.Invoke("正在更新挖矿软件..."); 50 | FileHelper.DownloadFile(appInfo.Address, file, action); 51 | } 52 | action?.Invoke("正在校验挖矿软件..."); 53 | validateCode = appInfo.MD5.ToUpper(); 54 | fileMD5 = FileHelper.ComputeFileMD5(file); 55 | } 56 | catch 57 | { 58 | validateCode = FileHelper.LoadString(md5File); 59 | fileMD5 = FileHelper.ComputeFileMD5(file); 60 | } 61 | if (fileMD5 != validateCode) 62 | { 63 | throw new FileLoadException(); 64 | } 65 | try 66 | { 67 | FileHelper.SaveString(md5File, validateCode); 68 | } 69 | catch 70 | { 71 | } 72 | 73 | miner = minerd; 74 | Load(); 75 | request = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getMinerParam\"}"; 76 | endPoint = new IPEndPoint(IPAddress.Loopback, 8087); 77 | format = c => $"-o \"stratum+tcp://{c.Url}\" -u \"{(string.IsNullOrEmpty(c.Id) ? c.User : $"{c.User}.{c.Id}")}\" -p \"{c.Pass}\" -t {c.Thread}"; 78 | 79 | parseResult = s => 80 | { 81 | s = s.Substring(s.IndexOf('H')).Replace("/ ", ":").Replace(" ", "").Replace("Hashrate", "{\"Hashrate\"").Replace("accept", ",\"Accept\"").Replace("total", ",\"Total\"") + "}"; 82 | return JsonConvert.DeserializeObject(s); 83 | }; 84 | setPerformance = (p, r) => p.SetPerformance(r.Total, r.Accept, r.Hashrate, 0); 85 | 86 | outputHandler += (s, e) => DebugMessageHandle(e.Data); 87 | errorHandler += (s, e) => DebugMessageHandle(e.Data); 88 | exitHandler += (s, e) => DebugMessageHandle($"Exited with {(s as Process).ExitCode}"); 89 | } 90 | #region Load & Save 91 | public static void Load() 92 | { 93 | config = new Config(); 94 | try 95 | { 96 | Config lastConfig = FileOperation.SolatedStorageRead(CONFIGPATH); 97 | if (lastConfig != null) 98 | { 99 | lock (asyncConfigRoot) 100 | { 101 | config.SetConfig(lastConfig); 102 | } 103 | } 104 | } 105 | catch (Exception ex) 106 | { 107 | DebugExceptionHandle(ex); 108 | } 109 | } 110 | public static void Save() 111 | { 112 | try 113 | { 114 | lock (asyncConfigRoot) 115 | { 116 | FileOperation.SolatedStorageWrite(CONFIGPATH, config); 117 | } 118 | } 119 | catch (Exception ex) 120 | { 121 | DebugExceptionHandle(ex); 122 | } 123 | } 124 | #endregion 125 | #region Notify information 126 | public static void ShowErrMessage(string message) 127 | { 128 | MessageBox.Show(message, "系统消息", MessageBoxButton.OK, MessageBoxImage.Error); 129 | } 130 | public static void DebugExceptionHandle(Exception ex) 131 | { 132 | DebugMessageHandle($"Exception: {ex}"); 133 | } 134 | public static void DebugMessageHandle(string message) 135 | { 136 | Debug.WriteLine($"{DateTime.Now}: {message}"); 137 | } 138 | #endregion 139 | #region Get perfmon & IsRun & Run & Terminate 140 | public static IPerformance GetPerfmon(out bool isRun) 141 | { 142 | return miner.GetPerformance(file, format(config), endPoint, request, parseResult, setPerformance, out isRun); 143 | } 144 | public static bool IsRun() 145 | { 146 | return miner.Alive(file, format(config)); 147 | } 148 | public static bool TryRun(Config newConfig) 149 | { 150 | try 151 | { 152 | if (FileHelper.ComputeFileMD5(file) != validateCode) 153 | { 154 | throw new FileLoadException(); 155 | } 156 | } 157 | catch 158 | { 159 | TryTerminate(); 160 | return false; 161 | } 162 | if (miner.Run(file, format(newConfig), outputHandler, errorHandler)) 163 | { 164 | lock (asyncConfigRoot) 165 | { 166 | config.SetConfig(newConfig); 167 | } 168 | return true; 169 | } 170 | return false; 171 | } 172 | public static bool TryTerminate() 173 | { 174 | if (miner.Terminate(file)) 175 | { 176 | return true; 177 | } 178 | return false; 179 | } 180 | #endregion 181 | #region Boot start 182 | public static bool IsBootStart() 183 | { 184 | return Process.GetCurrentProcess().MainModule.FileName.Equals(Win32Native.GetRegistryValue(@"Software\Microsoft\Windows\CurrentVersion\Run", "UlordMiner")); 185 | } 186 | public static bool BootStart(bool power, Action action = null) 187 | { 188 | try 189 | { 190 | if (power) 191 | { 192 | Win32Native.SetRegistryKey(@"Software\Microsoft\Windows\CurrentVersion\Run", new RegistryKeyValue("UlordMiner", Process.GetCurrentProcess().MainModule.FileName)); 193 | } 194 | else 195 | { 196 | Win32Native.DeleteRegistryKey(@"Software\Microsoft\Windows\CurrentVersion\Run", "UlordMiner"); 197 | } 198 | return true; 199 | } 200 | catch 201 | { 202 | action?.Invoke(power); 203 | return false; 204 | } 205 | } 206 | #endregion 207 | #region Automatic & Idle & CPU usage 208 | public static void SetAutomatic(bool automatic) 209 | { 210 | lock (asyncConfigRoot) 211 | { 212 | config.Automatic = automatic; 213 | } 214 | } 215 | public static bool GetAutomatic() 216 | { 217 | lock (asyncConfigRoot) 218 | { 219 | return config.Automatic; 220 | } 221 | } 222 | public static bool IsIdle() 223 | { 224 | return Win32Native.GetIdleTime() >= 2 * 60 * 1000; 225 | } 226 | public static Config GetConfig() 227 | { 228 | return config; 229 | } 230 | public static float GetCPUUsage(Action action = null) 231 | { 232 | try 233 | { 234 | lock (asyncCounterRoot) 235 | { 236 | return performanceCounter.NextValue(); 237 | } 238 | } 239 | catch (Exception ex) 240 | { 241 | action?.Invoke(ex); 242 | return default(float); 243 | } 244 | } 245 | #endregion 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /Miner-WPF/WindowConfig.xaml.cs: -------------------------------------------------------------------------------- 1 | using Contract; 2 | using Miner_WPF.Commons; 3 | using Miner_WPF.Models; 4 | using Miner_WPF.Models.ViewModels; 5 | using System; 6 | using System.Diagnostics; 7 | using System.Globalization; 8 | using System.Text.RegularExpressions; 9 | using System.Windows; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | 13 | namespace Miner_WPF 14 | { 15 | /// 16 | /// WindowConfig.xaml 的交互逻辑 17 | /// 18 | public partial class WindowConfig : Window 19 | { 20 | private readonly int MinThreadCount = (int)Math.Ceiling(Environment.ProcessorCount / 2.0); 21 | private ConfigWindowViewModel model; 22 | public WindowConfig() 23 | { 24 | InitializeComponent(); 25 | #region Binding events 26 | // Load 27 | this.Loaded += (s, e) => 28 | { 29 | int maximum = Environment.ProcessorCount; 30 | for (int i = 1; i <= maximum; i++) 31 | { 32 | comboBox_Thread.Items.Add(i); 33 | } 34 | Config config = Configuration.GetConfig(); 35 | config.Thread = config.Thread <= 0 ? MinThreadCount : config.Thread > maximum ? maximum : config.Thread; 36 | model = new ConfigWindowViewModel() { Config = config, IsAlive = false }; 37 | this.DataContext = model; 38 | }; 39 | // Drag 40 | this.MouseLeftButtonDown += (s, e) => { try { this.DragMove(); } catch { } }; 41 | // Close 42 | btn_Close.MouseDown += (s, e) => this.Close(); 43 | // Closing 44 | this.Closing += (s, e) => { this.Hide(); e.Cancel = true; }; 45 | // State changed 46 | this.StateChanged += (s, e) => 47 | { 48 | switch (this.WindowState) 49 | { 50 | case WindowState.Minimized: 51 | this.WindowState = WindowState.Normal; 52 | this.Hide(); 53 | break; 54 | case WindowState.Maximized: 55 | this.WindowState = WindowState.Normal; 56 | this.Show(); 57 | break; 58 | default: 59 | break; 60 | } 61 | }; 62 | // View incoming 63 | btn_Incoming.Click += (s, e) => 64 | { 65 | string urlFormate = "http://{0}/miners/{1}"; 66 | string url = "www.u1pool.com"; 67 | if (!string.IsNullOrEmpty(model.Config.Url)) 68 | { 69 | string address = model.Config.Url.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0]; 70 | if (address != "u1pool.com") 71 | { 72 | url = address; 73 | } 74 | } 75 | Process.Start(string.Format(urlFormate, url, model.Config.User)); 76 | }; 77 | // Mining 78 | btn_Mining.Click += Btn_Mining_Click; 79 | // Help 80 | btn_Help.MouseDown += (s, e) => 81 | { 82 | view_help.ScrollToTop(); 83 | grid_help.Visibility = Visibility.Visible; 84 | }; 85 | btn_return.MouseDown += (s, e) => grid_help.Visibility = Visibility.Hidden; 86 | #endregion 87 | } 88 | #region Set perfomance & Start mining, stop mining 89 | public void SetPerformance(bool isRun, IPerformance perfmon) 90 | { 91 | if (model != null) 92 | { 93 | model.IsAlive = isRun; 94 | model.SetPerformance(perfmon); 95 | } 96 | } 97 | public void StartMining() 98 | { 99 | if (model != null) 100 | { 101 | if (!TryFormatConfig()) 102 | { 103 | return; 104 | } 105 | else 106 | { 107 | if (Configuration.TryRun(model.Config)) 108 | { 109 | model.IsAlive = true; 110 | Configuration.Save(); 111 | } 112 | else 113 | { 114 | return; 115 | } 116 | } 117 | } 118 | } 119 | #endregion 120 | #region Start mining & Stop mining 121 | private void Btn_Mining_Click(object sender, RoutedEventArgs e) 122 | { 123 | if ("开始挖矿".Equals(btn_Mining.Content)) 124 | { 125 | if (TryFormatConfig()) 126 | { 127 | if (Configuration.TryRun(model.Config)) 128 | { 129 | model.IsAlive = true; 130 | Configuration.Save(); 131 | } 132 | else 133 | { 134 | Configuration.ShowErrMessage("启动挖矿程序失败!"); 135 | } 136 | } 137 | } 138 | else 139 | { 140 | if (Configuration.TryTerminate()) 141 | { 142 | model.IsAlive = false; 143 | model.Config.Automatic = false; 144 | Configuration.SetAutomatic(false); 145 | } 146 | else 147 | { 148 | Configuration.ShowErrMessage("结束挖矿程序失败!"); 149 | } 150 | } 151 | } 152 | #endregion 153 | #region Format input 154 | private bool TryFormatConfig(Action action = null) 155 | { 156 | if (string.IsNullOrEmpty(model.Config.Url)) 157 | { 158 | action?.Invoke("请输入地址!"); 159 | } 160 | else if (string.IsNullOrEmpty(model.Config.User) || !Regex.IsMatch(model.Config.User, "^[uU][a-zA-Z0-9]{33}$")) 161 | { 162 | action?.Invoke(@"账户只能为以u\U开头的34个字母和数字字符组合!"); 163 | } 164 | else if (!string.IsNullOrEmpty(model.Config.Id) && !Regex.IsMatch(model.Config.Id, "^[a-zA-Z0-9]{0,20}$")) 165 | { 166 | action?.Invoke("编号只能为不超过20位字符的数字和字母!"); 167 | } 168 | else if (model.Config.Thread < 0) 169 | { 170 | action?.Invoke("线程数输入错误!"); 171 | } 172 | else 173 | { 174 | model.Config.Url = model.Config.Url.Trim(); 175 | model.Config.User = model.Config.User.Trim(); 176 | return true; 177 | } 178 | return false; 179 | } 180 | #endregion 181 | #region Automatic 182 | private void CheckBox_Checked(object sender, RoutedEventArgs e) 183 | { 184 | if (!TryFormatConfig()) 185 | { 186 | check_Automatic.IsChecked = false; 187 | } 188 | else 189 | { 190 | Configuration.SetAutomatic(true); 191 | } 192 | } 193 | private void CheckBox_Unchecked(object sender, RoutedEventArgs e) 194 | { 195 | Configuration.TryTerminate(); 196 | Configuration.SetAutomatic(false); 197 | } 198 | #endregion 199 | 200 | private void Hyperlink_Click(object sender, RoutedEventArgs e) 201 | { 202 | Process.Start((sender as Hyperlink).NavigateUri.AbsoluteUri); 203 | } 204 | } 205 | #region Paramter value binding and converter 206 | public enum ValidateTypes 207 | { 208 | Url, 209 | User, 210 | Id 211 | } 212 | public class ValidateBinding : Binding 213 | { 214 | public ValidateBinding() : this(ValidateTypes.Url) 215 | { 216 | } 217 | public ValidateBinding(ValidateTypes validateTypes) : base("Text") 218 | { 219 | RelativeSource = RelativeSource.Self; 220 | Converter = new ValidateConverter(validateTypes); 221 | } 222 | } 223 | [ValueConversion(typeof(string), typeof(bool))] 224 | public class ValidateConverter : IValueConverter 225 | { 226 | private ValidateTypes validateType; 227 | public ValidateConverter(ValidateTypes validateType) 228 | { 229 | this.validateType = validateType; 230 | } 231 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 232 | { 233 | bool validate; 234 | string text = (string)value; 235 | switch (validateType) 236 | { 237 | case ValidateTypes.Url: 238 | validate = string.IsNullOrEmpty(text); 239 | break; 240 | case ValidateTypes.User: 241 | validate = string.IsNullOrEmpty(text) || !Regex.IsMatch(text, "^[uU][a-zA-Z0-9]{33}$"); 242 | break; 243 | case ValidateTypes.Id: 244 | validate = !string.IsNullOrEmpty(text) && !Regex.IsMatch(text, "^[a-zA-Z0-9]{0,20}$"); 245 | break; 246 | default: 247 | validate = false; 248 | break; 249 | } 250 | return validate; 251 | } 252 | 253 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 254 | { 255 | throw new NotImplementedException(); 256 | } 257 | } 258 | #endregion 259 | } 260 | -------------------------------------------------------------------------------- /Miner-WPF/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using Contract; 2 | using Miner_WPF.Commons; 3 | using Miner_WPF.Controls; 4 | using Miner_WPF.Models.ViewModels; 5 | using System; 6 | using System.Diagnostics; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | using System.Windows.Input; 11 | using System.Windows.Interop; 12 | using System.Windows.Media; 13 | 14 | namespace Miner_WPF 15 | { 16 | /// 17 | /// MainWindow.xaml 的交互逻辑 18 | /// 19 | public partial class MainWindow : Window 20 | { 21 | 22 | private bool isHidden = false; 23 | 24 | private WPFNotifyIcon notifyIcon = new WPFNotifyIcon(); 25 | private WindowConfig windowConfig = new WindowConfig() { Left = 0, Top = 0 }; 26 | private bool follow = true; 27 | private MainWindowViewModel model; 28 | public MainWindow() 29 | { 30 | InitializeComponent(); 31 | #region Binding events 32 | int automaticTimeout = 30 * 1000; 33 | int performanceTimeout = 1000; 34 | SolidColorBrush normBrush = (SolidColorBrush)FindResource("NormBrush"); 35 | SolidColorBrush warnBrush = (SolidColorBrush)FindResource("WarnBrush"); 36 | SolidColorBrush dangerBrush = (SolidColorBrush)FindResource("DangerBrush"); 37 | // Load 38 | this.Loaded += (s, e) => 39 | { 40 | model = new MainWindowViewModel(); 41 | this.DataContext = model; 42 | Win32Native.SetGlobalLLMouseHook(Mouse_Down); 43 | windowConfig.LocationChanged += WindowConfig_LocationChanged; 44 | windowConfig.Show(); 45 | }; 46 | // Close 47 | this.Closed += (s, e) => 48 | { 49 | Win32Native.RemoveGlobalLLMouseHook(); 50 | Configuration.TryTerminate(); 51 | notifyIcon.Dispose(); 52 | Environment.Exit(0); 53 | }; 54 | // Drag 55 | this.MouseLeftButtonDown += (s, e) => 56 | { 57 | try 58 | { 59 | this.DragMove(); 60 | } 61 | catch 62 | { 63 | } 64 | }; 65 | // Show config window 66 | this.MouseRightButtonDown += WindowConfig_Show; 67 | this.MouseDoubleClick += WindowConfig_Show; 68 | // State changed 69 | this.StateChanged += (s, e) => 70 | { 71 | switch (this.WindowState) 72 | { 73 | case WindowState.Normal: 74 | InitializeLocation(); 75 | break; 76 | case WindowState.Minimized: 77 | case WindowState.Maximized: 78 | this.WindowState = WindowState.Normal; 79 | break; 80 | default: 81 | break; 82 | } 83 | }; 84 | // Hidden window 85 | rec.MouseEnter += MainWindow_OnMouseEnter; 86 | rec.MouseLeave += MainWidow_OnMouseLeave; 87 | this.LocationChanged += MainWindow_LocationChanged; 88 | #endregion 89 | #region Performance 90 | Task.Factory.StartNew(() => 91 | { 92 | while (true) 93 | { 94 | try 95 | { 96 | bool isRun; 97 | IPerformance perfmon = Configuration.GetPerfmon(out isRun); 98 | model.ComputeAbility = perfmon.Hashrate; 99 | windowConfig.SetPerformance(isRun, perfmon); 100 | this.Dispatcher.Invoke(() => 101 | { 102 | if (isRun) 103 | { 104 | panel_Run.Visibility = Visibility.Visible; 105 | panel_Stop.Visibility = Visibility.Collapsed; 106 | } 107 | else 108 | { 109 | panel_Run.Visibility = Visibility.Collapsed; 110 | panel_Stop.Visibility = Visibility.Visible; 111 | } 112 | }); 113 | } 114 | catch 115 | { 116 | } 117 | Thread.Sleep(performanceTimeout); 118 | } 119 | }); 120 | #endregion 121 | #region CPU usage 122 | Task.Factory.StartNew(() => 123 | { 124 | while (true) 125 | { 126 | try 127 | { 128 | float usage = Configuration.GetCPUUsage(); 129 | double angle = usage * 3.6; 130 | SolidColorBrush solidColorBrush = usage >= 90 ? dangerBrush : usage >= 50 ? warnBrush : normBrush; 131 | this.Dispatcher.Invoke(() => 132 | { 133 | arc.EndAngle = angle; 134 | arc.Fill = solidColorBrush; 135 | }); 136 | } 137 | catch 138 | { 139 | } 140 | Thread.Sleep(performanceTimeout); 141 | } 142 | }); 143 | #endregion 144 | #region Automatic mining 145 | Task.Factory.StartNew(() => 146 | { 147 | while (true) 148 | { 149 | try 150 | { 151 | if (Configuration.GetAutomatic()) 152 | { 153 | if (!Configuration.IsRun()) 154 | { 155 | if (Configuration.IsIdle()) 156 | { 157 | windowConfig.StartMining(); 158 | } 159 | } 160 | } 161 | } 162 | catch 163 | { 164 | } 165 | Thread.Sleep(automaticTimeout); 166 | } 167 | }); 168 | #endregion 169 | InitializeNotifyIcon(); 170 | InitializeLocation(); 171 | } 172 | #region Hidden window 173 | private void InitializeLocation() 174 | { 175 | this.Top = SystemParameters.WorkArea.Height - this.Height; 176 | this.Left = SystemParameters.WorkArea.Width - this.Width; 177 | } 178 | private void MainWindow_OnMouseEnter(object sender, MouseEventArgs e) 179 | { 180 | if (isHidden) 181 | { 182 | Task.Factory.StartNew(() => 183 | { 184 | this.Dispatcher.Invoke(() => 185 | { 186 | if (this.Top < 0) 187 | { 188 | while (++this.Top < 0) 189 | { 190 | } 191 | isHidden = false; 192 | } 193 | if (this.Left < 0) 194 | { 195 | while (++this.Left < 0) 196 | { 197 | } 198 | isHidden = false; 199 | } 200 | if (this.Left > SystemParameters.WorkArea.Width - this.Width) 201 | { 202 | while (--this.Left > SystemParameters.WorkArea.Width - this.Width) 203 | { 204 | } 205 | isHidden = false; 206 | } 207 | }); 208 | }); 209 | } 210 | } 211 | 212 | private void MainWidow_OnMouseLeave(object sender, MouseEventArgs e) 213 | { 214 | if (!isHidden) 215 | { 216 | // Distance from the form to the boundary 217 | int windowDirection = 0; 218 | // Width or height displayed after the form is hidden 219 | int showWidthOrHeight = 10; 220 | if (this.Top <= 0) 221 | { 222 | Task.Factory.StartNew(() => 223 | { 224 | this.Dispatcher.Invoke(() => 225 | { 226 | if (windowConfig.Visibility == Visibility.Visible) 227 | { 228 | this.Top = 0; 229 | } 230 | else 231 | { 232 | while (this.Top >= -this.Height + showWidthOrHeight) 233 | { 234 | --this.Top; 235 | } 236 | isHidden = true; 237 | } 238 | }); 239 | }); 240 | } 241 | else if (this.Left <= windowDirection) 242 | { 243 | Task.Factory.StartNew(() => 244 | { 245 | this.Dispatcher.Invoke(() => 246 | { 247 | if (windowConfig.Visibility == Visibility.Visible) 248 | { 249 | this.Left = 0; 250 | } 251 | else 252 | { 253 | while (this.Left >= -this.Width + showWidthOrHeight) 254 | { 255 | --this.Left; 256 | } 257 | isHidden = true; 258 | } 259 | }); 260 | }); 261 | } 262 | else if (this.Left >= SystemParameters.WorkArea.Width - this.Width - windowDirection) 263 | { 264 | Task.Factory.StartNew(() => 265 | { 266 | this.Dispatcher.Invoke(() => 267 | { 268 | if (windowConfig.Visibility == Visibility.Visible) 269 | { 270 | this.Left = SystemParameters.WorkArea.Width - this.Width; 271 | } 272 | else 273 | { 274 | while (this.Left <= SystemParameters.WorkArea.Width - showWidthOrHeight) 275 | { 276 | ++this.Left; 277 | } 278 | isHidden = true; 279 | } 280 | }); 281 | }); 282 | } 283 | } 284 | } 285 | private bool PointInWindow(Window window, Tuple tuple) 286 | { 287 | if (window.Left <= tuple.Item1 && tuple.Item1 <= window.Left + window.Width && window.Top <= tuple.Item2 && tuple.Item2 <= window.Top + window.Height) 288 | { 289 | return true; 290 | } 291 | return false; 292 | } 293 | #endregion 294 | #region WindowConfig 295 | private void Mouse_Down(object sender, EventArgs e) 296 | { 297 | if (windowConfig != null && windowConfig.IsVisible) 298 | { 299 | if (!this.IsMouseOver && !windowConfig.IsMouseOver) 300 | { 301 | windowConfig.Hide(); 302 | } 303 | } 304 | } 305 | private void WindowConfig_Show(object sender, MouseButtonEventArgs e) 306 | { 307 | if (windowConfig.Visibility != Visibility.Visible) 308 | { 309 | follow = true; 310 | bool change = false; 311 | if (this.Top < 0) 312 | { 313 | this.Top = 0; 314 | change = true; 315 | } 316 | if (this.Left < 0) 317 | { 318 | this.Left = 0; 319 | change = true; 320 | } 321 | if (this.Left > SystemParameters.WorkArea.Width - this.Width) 322 | { 323 | this.Left = SystemParameters.WorkArea.Width - this.Width; 324 | change = true; 325 | } 326 | if (!change) 327 | { 328 | MainWindow_LocationChanged(default(object), default(EventArgs)); 329 | } 330 | windowConfig.grid_help.Visibility = Visibility.Hidden; 331 | windowConfig.Show(); 332 | } 333 | } 334 | private void WindowConfig_LocationChanged(object sender, EventArgs e) 335 | { 336 | bool bl = this.Left <= windowConfig.Left && windowConfig.Left <= this.Left + this.Width || windowConfig.Left <= this.Left && this.Left <= windowConfig.Left + windowConfig.Width; 337 | bool bt = this.Top <= windowConfig.Top && windowConfig.Top <= this.Top + this.Height || windowConfig.Top < this.Top && this.Top <= windowConfig.Top + windowConfig.Height; 338 | follow = bl && bt; 339 | } 340 | private void MainWindow_LocationChanged(object sender, EventArgs e) 341 | { 342 | // windows center point 343 | double centerML = this.Left + this.Width * 0.5; 344 | double centerMT = this.Top + this.Height * 0.5; 345 | double centerCL = windowConfig.Left + windowConfig.Width * 0.5; 346 | double centerCT = windowConfig.Top + windowConfig.Height * 0.5; 347 | // config window follow location 348 | double l = this.Left + 0.5 * this.Width - windowConfig.Width; 349 | double t = this.Top + 0.5 * this.Height - windowConfig.Height; 350 | double r = this.Left + 0.5 * this.Width; 351 | double b = this.Top + 0.5 * this.Height; 352 | // config window location range 353 | double minl = 0; 354 | double mint = 0; 355 | double maxl = SystemParameters.WorkArea.Width - windowConfig.Width; 356 | double maxt = SystemParameters.WorkArea.Height - windowConfig.Height; 357 | // config window really location 358 | double cl; 359 | double ct; 360 | if (!follow) 361 | { 362 | WindowConfig_LocationChanged(default(object), default(EventArgs)); 363 | } 364 | if (follow) 365 | { 366 | // calculate config window location 367 | if (centerML > centerCL) 368 | { 369 | // Left, Top 370 | if (centerMT > centerCT) 371 | { 372 | cl = l; 373 | ct = t; 374 | } 375 | // Left, Bottom 376 | else 377 | { 378 | cl = l; 379 | ct = b; 380 | } 381 | } 382 | else 383 | { 384 | // Right, Top 385 | if (centerMT > centerCT) 386 | { 387 | cl = r; 388 | ct = t; 389 | } 390 | // Right, Bottom 391 | else 392 | { 393 | cl = r; 394 | ct = b; 395 | } 396 | } 397 | // limit config window location 398 | if (cl < minl) 399 | { 400 | cl = r; 401 | } 402 | if (cl > maxl) 403 | { 404 | cl = l; 405 | } 406 | if (ct < mint) 407 | { 408 | ct = b; 409 | } 410 | if (ct > maxt) 411 | { 412 | ct = t; 413 | } 414 | windowConfig.Left = cl; 415 | windowConfig.Top = ct; 416 | } 417 | // limit main window top 418 | if (this.Top > SystemParameters.WorkArea.Height - this.Height) 419 | { 420 | this.Top = SystemParameters.WorkArea.Height - this.Height; 421 | } 422 | } 423 | #endregion 424 | #region Notify icon 425 | private void InitializeNotifyIcon() 426 | { 427 | notifyIcon.notifyIcon.Icon = Properties.Resources.Ulord; 428 | notifyIcon.notifyIcon.Text = "挖矿程序运行中..."; 429 | notifyIcon.打开ToolStripMenuItem.Click += (s, e) => 430 | { 431 | this.WindowState = WindowState.Normal; 432 | Win32Native.BringWindowToTop(new WindowInteropHelper(this).Handle); 433 | WindowConfig_Show(default(object), default(MouseButtonEventArgs)); 434 | }; 435 | notifyIcon.开机启动ToolStripMenuItem.Click += (s, e) => Configuration.BootStart(!notifyIcon.开机启动ToolStripMenuItem.Checked, f => Configuration.ShowErrMessage($"{(f ? "设置" : "禁止")}程序开机启动失败,需要管理员权限!")); 436 | notifyIcon.关于我们ToolStripMenuItem.Click += (s, e) => Process.Start("https://ulord.one/"); 437 | notifyIcon.退出ToolStripMenuItem.Click += (s, e) => this.Close(); 438 | notifyIcon.notifyIcon.MouseDoubleClick += (o, e) => notifyIcon.打开ToolStripMenuItem.PerformClick(); 439 | notifyIcon.contextMenuStrip.Opening += (s, e) => notifyIcon.开机启动ToolStripMenuItem.Checked = Configuration.IsBootStart(); 440 | notifyIcon.notifyIcon.Visible = true; 441 | } 442 | #endregion 443 | } 444 | } 445 | -------------------------------------------------------------------------------- /Miner-WPF/WindowConfig.xaml: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 24 | 25 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 92 | 124 | 125 | 134 | 167 | 168 | 200 | 201 | 231 | 232 | 240 | 241 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 284 | 285 | 286 | 287 | 288 | 289 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 |