diff --git a/PotatoNV-next.sln b/PotatoNV-next.sln index 944e891..9889836 100644 --- a/PotatoNV-next.sln +++ b/PotatoNV-next.sln @@ -8,13 +8,19 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2F103DCF-DFBA-48B0-BEA4-D4B845532A42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2F103DCF-DFBA-48B0-BEA4-D4B845532A42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F103DCF-DFBA-48B0-BEA4-D4B845532A42}.Debug|x64.ActiveCfg = Debug|x64 + {2F103DCF-DFBA-48B0-BEA4-D4B845532A42}.Debug|x64.Build.0 = Debug|x64 {2F103DCF-DFBA-48B0-BEA4-D4B845532A42}.Release|Any CPU.ActiveCfg = Release|Any CPU {2F103DCF-DFBA-48B0-BEA4-D4B845532A42}.Release|Any CPU.Build.0 = Release|Any CPU + {2F103DCF-DFBA-48B0-BEA4-D4B845532A42}.Release|x64.ActiveCfg = Release|x64 + {2F103DCF-DFBA-48B0-BEA4-D4B845532A42}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PotatoNV-next/Controls/AboutTab.xaml.cs b/PotatoNV-next/Controls/AboutTab.xaml.cs index 77e9987..f18294f 100644 --- a/PotatoNV-next/Controls/AboutTab.xaml.cs +++ b/PotatoNV-next/Controls/AboutTab.xaml.cs @@ -21,7 +21,7 @@ namespace PotatoNV_next.Controls private void TelegramButton_ButtonClicked(object sender, EventArgs e) { Log.Debug("Clicked to Telegram button!"); - Process.Start("https://t.me/RePotato"); + Process.Start("https://t.me/s/RePotato"); } } } diff --git a/PotatoNV-next/Controls/ImageButton.xaml.cs b/PotatoNV-next/Controls/ImageButton.xaml.cs index 9096167..e07830c 100644 --- a/PotatoNV-next/Controls/ImageButton.xaml.cs +++ b/PotatoNV-next/Controls/ImageButton.xaml.cs @@ -1,22 +1,7 @@ using PotatoNV_next.Utils; using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Interop; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace PotatoNV_next.Controls { diff --git a/PotatoNV-next/Controls/LogBox.xaml b/PotatoNV-next/Controls/LogBox.xaml index 328f3cf..d99325e 100644 --- a/PotatoNV-next/Controls/LogBox.xaml +++ b/PotatoNV-next/Controls/LogBox.xaml @@ -9,7 +9,7 @@ - + logBox.AppendText(e.Message)); + return; + } logBox.AppendText(e.Message); } public LogBox() { InitializeComponent(); + OnChanged(); #if DEBUG Log.PrintDebug = true; #endif diff --git a/PotatoNV-next/MainWindow.xaml.cs b/PotatoNV-next/MainWindow.xaml.cs index 5605c42..6ba7ed4 100644 --- a/PotatoNV-next/MainWindow.xaml.cs +++ b/PotatoNV-next/MainWindow.xaml.cs @@ -1,4 +1,5 @@ -using PotatoNV_next.Utils; +using Potato.Fastboot; +using PotatoNV_next.Utils; using System; using System.Collections.Generic; using System.Linq; @@ -18,10 +19,22 @@ namespace PotatoNV_next { public partial class MainWindow : Window { + private UsbController usbController = new UsbController(); + public MainWindow() { Icon = MediaConverter.ImageSourceFromBitmap(Properties.Resources.Fire.ToBitmap()); InitializeComponent(); + usbController.AddListener(HandleDevices); + usbController.StartWorker(); + } + + private void HandleDevices(UsbController.Device[] devices) + { + foreach (var device in devices) + { + Log.Debug($"{device.Mode} - {device.Description}"); + } } } } diff --git a/PotatoNV-next/PotatoNV-next.csproj b/PotatoNV-next/PotatoNV-next.csproj index b420989..d2b2a7e 100644 --- a/PotatoNV-next/PotatoNV-next.csproj +++ b/PotatoNV-next/PotatoNV-next.csproj @@ -55,6 +55,28 @@ Resources\fire.ico + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + MinimumRecommendedRules.ruleset + true + ..\packages\LibUsbDotNet.3.0.81-alpha\lib\net45\LibUsbDotNet.dll @@ -71,6 +93,7 @@ + ..\packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll @@ -108,6 +131,7 @@ + Designer MSBuild:Compile diff --git a/PotatoNV-next/Utils/UsbController.cs b/PotatoNV-next/Utils/UsbController.cs new file mode 100644 index 0000000..46ececc --- /dev/null +++ b/PotatoNV-next/Utils/UsbController.cs @@ -0,0 +1,149 @@ +using Potato.Fastboot; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Management; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace PotatoNV_next.Utils +{ + class UsbController + { + public struct Device + { + public enum DMode + { + DownloadVCOM, + Fastboot + } + + public Device(DMode mode, string description) + { + Mode = mode; + Description = description; + } + + public DMode Mode { get; } + public string Description { get; } + } + + #region USB watcher + private readonly BackgroundWorker usbWorker = new BackgroundWorker(); + private readonly Stopwatch watch = new Stopwatch(); + private long delta = 0; + + private void Watcher_EventArrived(object sender, EventArrivedEventArgs e) + { + if (watch.ElapsedMilliseconds - delta < 100) + { + return; + } + + delta = watch.ElapsedMilliseconds; + + Log.Debug("New USB event, calling listener..."); + + UpdateList(); + } + + private void UsbWorker_DoWork(object sender, DoWorkEventArgs e) + { + using (var watcher = new ManagementEventWatcher()) + { + var query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2 OR EventType = 3"); + watcher.EventArrived += Watcher_EventArrived; + watcher.Query = query; + watcher.Start(); + watcher.WaitForNextEvent(); + } + } + + public void StartWorker() + { + usbWorker.DoWork += UsbWorker_DoWork; + watch.Start(); + usbWorker.RunWorkerAsync(); + } + #endregion + + #region Device list + private const int VID = 0x12D1, PID = 0x3609; + private Device[] cachedDevices = null; + + private Device[] GetDownloadVCOMDevices() + { + var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE ClassGuid=\"{4d36e978-e325-11ce-bfc1-08002be10318}\""); + var list = searcher.Get(); + var devices = new List(); + + foreach (ManagementObject obj in list) + { + // Excepted format: USB\VID_12D1&PID_3609\6&127ABA2B&0&2 + var sdata = obj["DeviceID"].ToString().Split('\\'); + + if (sdata.Length < 2 || sdata[1] != string.Format("VID_{0:X4}&PID_{1:X4}", VID, PID)) + { + continue; + } + + var match = Regex.Match(obj["Name"].ToString(), @"COM\d+"); + + if (match.Success) + { + devices.Add(new Device( + Device.DMode.DownloadVCOM, + $"{match.Value}: {obj["Description"]}" + )); + } + } + return devices.ToArray(); + } + + private Device[] GetFastbootDevices() + { + return Fastboot.GetDevices() + .Select(x => new Device(Device.DMode.Fastboot, x)) + .ToArray(); + } + #endregion + + #region Caller + private List> listeners = new List>(); + + private void UpdateList() + { + try + { + var list = new List(); + list.AddRange(GetDownloadVCOMDevices()); + list.AddRange(GetFastbootDevices()); + } + catch (Exception ex) + { + Log.Error(ex.Message); + Log.Debug(ex.StackTrace); + } + + //if (!Enumerable.SequenceEqual(list, cachedDevices)) + //{ + // Log.Debug("Sequence equal"); + // return; + //} + + //foreach (var listener in listeners) + //{ + // listener?.Invoke(list.ToArray()); + //} + } + + public void AddListener(Action action) + { + listeners.Add(action); + } + #endregion + } +}