From c0643c40e9c83022ea044a625612ede38b4efa96 Mon Sep 17 00:00:00 2001 From: "DESKTOP-3BO4HSG\\ksat" Date: Thu, 12 Jan 2023 17:53:48 +0800 Subject: [PATCH] feat: add updater by https://github.com/Planshit/Tai --- STranslate.sln | 6 + STranslate/Helper/Processhelper.cs | 36 ++++ STranslate/Properties/AssemblyInfo.cs | 4 +- STranslate/STranslate.csproj | 1 + STranslate/View/MainWindow.xaml.cs | 65 ++++++- Updater/App.config | 6 + Updater/App.xaml | 9 + Updater/App.xaml.cs | 61 ++++++ Updater/GithubRelease.cs | 111 +++++++++++ Updater/MainViewModel.cs | 37 ++++ Updater/MainWindow.xaml | 56 ++++++ Updater/MainWindow.xaml.cs | 238 +++++++++++++++++++++++ Updater/Properties/AssemblyInfo.cs | 56 ++++++ Updater/Properties/Resources.Designer.cs | 63 ++++++ Updater/Properties/Resources.resx | 117 +++++++++++ Updater/Properties/Settings.Designer.cs | 26 +++ Updater/Properties/Settings.settings | 7 + Updater/Unzip.cs | 85 ++++++++ Updater/Updater.csproj | 113 +++++++++++ Updater/packages.config | 4 + 20 files changed, 1096 insertions(+), 5 deletions(-) create mode 100644 STranslate/Helper/Processhelper.cs create mode 100644 Updater/App.config create mode 100644 Updater/App.xaml create mode 100644 Updater/App.xaml.cs create mode 100644 Updater/GithubRelease.cs create mode 100644 Updater/MainViewModel.cs create mode 100644 Updater/MainWindow.xaml create mode 100644 Updater/MainWindow.xaml.cs create mode 100644 Updater/Properties/AssemblyInfo.cs create mode 100644 Updater/Properties/Resources.Designer.cs create mode 100644 Updater/Properties/Resources.resx create mode 100644 Updater/Properties/Settings.Designer.cs create mode 100644 Updater/Properties/Settings.settings create mode 100644 Updater/Unzip.cs create mode 100644 Updater/Updater.csproj create mode 100644 Updater/packages.config diff --git a/STranslate.sln b/STranslate.sln index 44fbab2..ce58a49 100644 --- a/STranslate.sln +++ b/STranslate.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.31702.278 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STranslate", "STranslate\STranslate.csproj", "{2597B480-185C-4D6D-94EC-8641BB6777F5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Updater", "Updater\Updater.csproj", "{A49C9514-81CA-4FB6-A586-17477E4F28A8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {2597B480-185C-4D6D-94EC-8641BB6777F5}.Debug|Any CPU.Build.0 = Debug|Any CPU {2597B480-185C-4D6D-94EC-8641BB6777F5}.Release|Any CPU.ActiveCfg = Release|Any CPU {2597B480-185C-4D6D-94EC-8641BB6777F5}.Release|Any CPU.Build.0 = Release|Any CPU + {A49C9514-81CA-4FB6-A586-17477E4F28A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A49C9514-81CA-4FB6-A586-17477E4F28A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A49C9514-81CA-4FB6-A586-17477E4F28A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A49C9514-81CA-4FB6-A586-17477E4F28A8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/STranslate/Helper/Processhelper.cs b/STranslate/Helper/Processhelper.cs new file mode 100644 index 0000000..c691c4a --- /dev/null +++ b/STranslate/Helper/Processhelper.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace STranslate.Helper +{ + public class ProcessHelper + { + public static bool Run(string filename, string[] args) + { + try + { + string arguments = ""; + foreach (string arg in args) + { + arguments += $"\"{arg}\" "; + } + arguments = arguments.Trim(); + Process process = new Process(); + ProcessStartInfo startInfo = new ProcessStartInfo(filename, arguments); + process.StartInfo = startInfo; + process.Start(); + return true; + } + catch (Exception) + { + //Logger.Error(ex.ToString()); + return false; + } + + } + } +} diff --git a/STranslate/Properties/AssemblyInfo.cs b/STranslate/Properties/AssemblyInfo.cs index a94600f..c7abf66 100644 --- a/STranslate/Properties/AssemblyInfo.cs +++ b/STranslate/Properties/AssemblyInfo.cs @@ -47,6 +47,6 @@ using System.Windows; //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //通过使用 "*",如下所示: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.6.0")] -[assembly: AssemblyFileVersion("0.1.6.0")] +[assembly: AssemblyVersion("0.1.7.0")] +[assembly: AssemblyFileVersion("0.1.7.0")] [assembly: Guid("CE252DD8-179F-4544-9989-453F5DEA378D")] \ No newline at end of file diff --git a/STranslate/STranslate.csproj b/STranslate/STranslate.csproj index 2ce6377..c3dde3d 100644 --- a/STranslate/STranslate.csproj +++ b/STranslate/STranslate.csproj @@ -94,6 +94,7 @@ + diff --git a/STranslate/View/MainWindow.xaml.cs b/STranslate/View/MainWindow.xaml.cs index a9a71d3..b0d52cd 100644 --- a/STranslate/View/MainWindow.xaml.cs +++ b/STranslate/View/MainWindow.xaml.cs @@ -1,6 +1,7 @@ using STranslate.Helper; using STranslate.ViewModel; using System; +using System.IO; using System.Windows; namespace STranslate.View @@ -57,14 +58,17 @@ namespace STranslate.View private MainVM vm = MainVM.Instance; + private string _version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); + + public System.Windows.Forms.NotifyIcon NotifyIcon = new System.Windows.Forms.NotifyIcon(); #region TrayIcon private void InitialTray() { - var app = System.IO.Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location); - var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); - NotifyIcon.Text = $"{app} {version.Substring(0, version.Length - 2)}"; + _version = HandleVersion(_version); + var app = Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location); + NotifyIcon.Text = $"{app} {_version}"; NotifyIcon.Icon = new System.Drawing.Icon(Application.GetResourceStream(new Uri("Images/translate.ico", UriKind.Relative)).Stream); NotifyIcon.Visible = true; NotifyIcon.BalloonTipText = $"{app} already started..."; @@ -86,6 +90,9 @@ namespace STranslate.View System.Windows.Forms.MenuItem OpenMainWinBTN = new System.Windows.Forms.MenuItem("显示主界面"); OpenMainWinBTN.Click += new EventHandler(OpenMainWin_Click); + System.Windows.Forms.MenuItem CheckUpdateBTN = new System.Windows.Forms.MenuItem("检查更新"); + CheckUpdateBTN.Click += CheckUpdateBTN_Click; + System.Windows.Forms.MenuItem AutoStartBTN = new System.Windows.Forms.MenuItem("开机自启"); AutoStartBTN.Click += new EventHandler(AutoStart_Click); @@ -99,12 +106,64 @@ namespace STranslate.View ScreenshotTranslateMenuItemBTN, CrossWordTranslateMenuItemBTN, OpenMainWinBTN, + CheckUpdateBTN, AutoStartBTN, ExitBTN, }; NotifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen); } + private string HandleVersion(string version) + { + var ret = string.Empty; + ret = version.Substring(0, version.Length - 2); + var location = ret.LastIndexOf('.'); + ret = ret.Remove(location, 1); + return ret; + } + + /// + /// 检查更新 + /// + /// + /// + private void CheckUpdateBTN_Click(object sender, EventArgs e) + { + try + { + string updaterExePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, + "Updater.exe"); + string updaterCacheExePath = Path.Combine( + AppDomain.CurrentDomain.BaseDirectory, + "Updater", + "Updater.exe"); + string updateDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Updater"); + if (!Directory.Exists(updateDirPath)) + { + Directory.CreateDirectory(updateDirPath); + } + + if (!File.Exists(updaterExePath)) + { + MessageBox.Show("升级程序似乎已被删除,请手动前往发布页查看新版本"); + return; + } + File.Copy(updaterExePath, updaterCacheExePath, true); + + File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Newtonsoft.Json.dll"), Path.Combine( + AppDomain.CurrentDomain.BaseDirectory, + "Updater", + "Newtonsoft.Json.dll"), true); + + ProcessHelper.Run(updaterCacheExePath, new string[] { _version }); + } + catch (Exception ex) + { + + MessageBox.Show($"无法正确启动检查更新程序\n{ex.Message}"); + } + } + private void ScreenshotTranslateMenuItem_Click(object sender, EventArgs e) { vm.ScreenShotTranslate(); diff --git a/Updater/App.config b/Updater/App.config new file mode 100644 index 0000000..4bfa005 --- /dev/null +++ b/Updater/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/Updater/App.xaml b/Updater/App.xaml new file mode 100644 index 0000000..3a8b079 --- /dev/null +++ b/Updater/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/Updater/App.xaml.cs b/Updater/App.xaml.cs new file mode 100644 index 0000000..8c548fe --- /dev/null +++ b/Updater/App.xaml.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace Updater +{ + /// + /// App.xaml 的交互逻辑 + /// + public partial class App : Application + { + private System.Threading.Mutex mutex; + + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + // 阻止多开和用户主动启动 + if (e.Args.Length == 0 || IsRuned()) + { + Shutdown(); + } + + Activated += (s, e2) => + { + var mainWindow = App.Current.MainWindow; + if (mainWindow.DataContext != null) + { + var mainViewModel = mainWindow.DataContext as MainViewModel; + if (string.IsNullOrEmpty(mainViewModel.Version)) + { + mainViewModel.Version = e.Args[0]; + } + } + }; + } + + + + + + #region 获取当前程序是否已运行 + /// + /// 获取当前程序是否已运行 + /// + private bool IsRuned() + { + bool ret; + mutex = new System.Threading.Mutex(true, System.Reflection.Assembly.GetEntryAssembly().ManifestModule.Name, out ret); + if (!ret) + { + return true; + } + return false; + } + #endregion + } +} diff --git a/Updater/GithubRelease.cs b/Updater/GithubRelease.cs new file mode 100644 index 0000000..9e97e1d --- /dev/null +++ b/Updater/GithubRelease.cs @@ -0,0 +1,111 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Updater +{ + public class GithubRelease + { + public class VersionInfo + { + /// + /// 版本标题 + /// + public string Title { get; set; } + /// + /// 版本号 + /// + public string Version { get; set; } + /// + /// 是否是预览版本 + /// + public bool IsPre { get; set; } + /// + /// 下载路径 + /// + public string DownloadUrl { get; set; } + /// + /// 版本更新内容网页链接 + /// + public string HtmlUrl { get; set; } + } + public class GithubModel + { + public string tag_name { get; set; } + public string html_url { get; set; } + public string name { get; set; } + public bool prerelease { get; set; } + + public List assets { get; set; } + } + public class GithubAssetsModel + { + public string browser_download_url { get; set; } + } + private string githubUrl; + private string nowVersion; + public VersionInfo Info { get; set; } + + //public event UpdaterEventHandler RequestCompleteEvent; + //public event UpdaterEventHandler RequestErrorEvent; + //public delegate void UpdaterEventHandler(object sender, object value); + public GithubRelease(string githubUrl, string nowVersion) + { + this.githubUrl = githubUrl; + this.nowVersion = nowVersion; + Info = new VersionInfo(); + } + public bool IsCanUpdate() + { + return !(nowVersion == Info.Version); + } + public async Task GetRequest() + { + var result = await Task.Run(() => + { + HttpWebResponse httpWebRespones = null; + try + { + System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + HttpWebRequest httpWebRequest = WebRequest.Create(githubUrl) as HttpWebRequest; + httpWebRequest.Timeout = 60 * 1000; + httpWebRequest.ReadWriteTimeout = 60000; + httpWebRequest.AllowAutoRedirect = true; + httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"; + httpWebRespones = (HttpWebResponse)httpWebRequest.GetResponse(); + + + using (Stream stream = httpWebRespones.GetResponseStream()) + { + List lst = new List(); + int nRead = 0; + while ((nRead = stream.ReadByte()) != -1) lst.Add((byte)nRead); + byte[] bodyBytes = lst.ToArray(); + + string body = Encoding.UTF8.GetString(bodyBytes, 0, bodyBytes.Length); + + var data = JsonConvert.DeserializeObject(body); + Info.IsPre = data.prerelease; + Info.Title = data.name; + Info.Version = data.tag_name; + Info.DownloadUrl = data.assets[0].browser_download_url; + Info.HtmlUrl = data.html_url; + return Info; + } + + } + catch (Exception) + { + return null; + } + + }); + return result; + } + } +} diff --git a/Updater/MainViewModel.cs b/Updater/MainViewModel.cs new file mode 100644 index 0000000..8473c5f --- /dev/null +++ b/Updater/MainViewModel.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Updater +{ + public class MainViewModel : INotifyPropertyChanged + { + + private double _processValue; + public double ProcessValue { get => _processValue; set => UpdateProperty(ref _processValue, value); } + + private string _version; + public string Version { get => _version; set => UpdateProperty(ref _version, value); } + + #region notifychanged + public event PropertyChangedEventHandler PropertyChanged; + + protected void UpdateProperty(ref T properValue, T newValue, [CallerMemberName] string properName = "") + { + if (object.Equals(properValue, newValue)) + return; + properValue = newValue; + NotifyPropertyChanged(properName); + } + + public void NotifyPropertyChanged([CallerMemberName] string propertyName = null) + { + this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + #endregion + } +} diff --git a/Updater/MainWindow.xaml b/Updater/MainWindow.xaml new file mode 100644 index 0000000..ec30920 --- /dev/null +++ b/Updater/MainWindow.xaml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + 版本号 + + + + + + + + + + 查看详细更新内容 + + + + + + + + + + 当前版本号: + + + + diff --git a/Updater/MainWindow.xaml.cs b/Updater/MainWindow.xaml.cs new file mode 100644 index 0000000..fb467c9 --- /dev/null +++ b/Updater/MainWindow.xaml.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +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.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Updater +{ + /// + /// MainWindow.xaml 的交互逻辑 + /// + public partial class MainWindow : Window + { + GithubRelease githubRelease; + + /// + /// 新版本保存目录路径 + /// + private string SaveDir = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory); + /// + /// 新版本保存名字 + /// + private string SaveName = "update.zip"; + /// + /// 新版本下载路径 + /// + private string NewVersionZipURL; + /// + /// 新版本发布页路径 + /// + private string NewVersionURL; + private MainViewModel _mainViewModel; + public MainWindow() + { + InitializeComponent(); + + _mainViewModel = new MainViewModel(); + + DataContext = _mainViewModel; + + _mainViewModel.PropertyChanged += MainViewModel_PropertyChanged; + } + + private void MainViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(_mainViewModel.Version)) + { + githubRelease = new GithubRelease("https://api.github.com/repos/zggsong/stranslate/releases/latest", _mainViewModel.Version); + + Check(); + } + } + private async void Download() + { + SetStatus("正在下载新版本文件...", false); + + UpdateBtn.Visibility = Visibility.Collapsed; + ReCheckBtn.Visibility = Visibility.Collapsed; + ProgressBar.Visibility = Visibility.Visible; + _mainViewModel.ProcessValue = 0; + + var res = await Task.Run(() => + { + try + { + // 确认保存目录 + if (!Directory.Exists(SaveDir)) + { + Directory.CreateDirectory(SaveDir); + } + + Uri uri = new Uri(NewVersionZipURL); + HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri); + httpWebRequest.Timeout = 120 * 1000; + HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + + + long totalBytes = httpWebResponse.ContentLength; + + Stream st = httpWebResponse.GetResponseStream(); + Stream so = new FileStream(System.IO.Path.Combine(SaveDir, SaveName), FileMode.Create); + + long totalDownloadedByte = 0; + byte[] by = new byte[1024]; + int osize = st.Read(by, 0, (int)by.Length); + while (osize > 0) + { + + totalDownloadedByte = osize + totalDownloadedByte; + so.Write(by, 0, osize); + + osize = st.Read(by, 0, (int)by.Length); + + //进度计算 + double process = double.Parse(String.Format("{0:F}", + ((double)totalDownloadedByte / (double)totalBytes * 100))); + _mainViewModel.ProcessValue = process; + //Debug.WriteLine(ProcessValue); + } + //关闭资源 + httpWebResponse.Close(); + so.Close(); + st.Close(); + + return true; + + } + catch (Exception) + { + return false; + } + }); + + if (res) + { + // 准备更新 + var process = Process.GetProcessesByName("STranslate"); + if (process != null && process.Length > 0) + { + process[0].Kill(); + } + + SetStatus("下载完成,正在解压请勿关闭此窗口..."); + + string unpath = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.FullName; + + var unresult = await Task.Run(async () => + { + await Task.Delay(3000); + return Unzip.ExtractZipFile(System.IO.Path.Combine(SaveDir, SaveName), unpath); + }); + if (unresult) + { + SetStatus("更新完成!", false); + Process tai = new Process(); + ProcessStartInfo startInfo = new ProcessStartInfo(System.IO.Path.Combine(unpath, "Tai.exe")); + tai.StartInfo = startInfo; + tai.Start(); + } + else + { + SetStatus("解压文件时发生异常,请重试!通常情况可能是因为Tai主程序尚未退出。", false); + UpdateBtn.Visibility = Visibility.Visible; + + } + } + else + { + //下载发生异常 + SetStatus("下载时发生异常,请重试。", false); + UpdateBtn.Visibility = Visibility.Visible; + } + } + + + private async void Check() + { + NewVersionSP.Visibility = Visibility.Collapsed; + PreTag.Visibility = Visibility.Collapsed; + + SetStatus("正在检查更新"); + UpdateBtn.Visibility = Visibility.Collapsed; + ReCheckBtn.IsEnabled = false; + + var info = await githubRelease.GetRequest(); + + if (info != null) + { + if (githubRelease.IsCanUpdate()) + { + UpdateBtn.Visibility = Visibility.Visible; + + NewVersionSP.Visibility = Visibility.Visible; + Version.Text = info.Version; + VersionTitle.Text = info.Title; + NewVersionZipURL = info.DownloadUrl; + NewVersionURL = info.HtmlUrl; + if (info.IsPre) + { + PreTag.Visibility = Visibility.Visible; + } + SetStatus("检测到新的版本!", false); + } + else + { + SetStatus("目前没有可用的更新。", false); + } + } + else + { + SetStatus("无法获取版本信息,请检查代理或网络。", false); + } + ReCheckBtn.IsEnabled = true; + + } + + private void SetStatus(string statusText, bool isLoading = true) + { + StatusLabel.Text = statusText; + ProgressBar.IsIndeterminate = isLoading; + if (isLoading) + { + ProgressBar.Visibility = Visibility.Visible; + } + else + { + ProgressBar.Visibility = Visibility.Collapsed; + } + } + + private void ReCheckBtn_Click(object sender, RoutedEventArgs e) + { + Check(); + } + + private void UpdateBtn_Click(object sender, RoutedEventArgs e) + { + Download(); + } + + private void Hyperlink_Click(object sender, RoutedEventArgs e) + { + Process.Start(new ProcessStartInfo(NewVersionURL)); + } + } +} diff --git a/Updater/Properties/AssemblyInfo.cs b/Updater/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f122cb0 --- /dev/null +++ b/Updater/Properties/AssemblyInfo.cs @@ -0,0 +1,56 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("Updater")] +[assembly: AssemblyDescription("A ready to use and ready to go translation tool")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("ZGGSONG")] +[assembly: AssemblyProduct("Updater")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("ZGGSONG")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +//若要开始生成可本地化的应用程序,请设置 +//.csproj 文件中的 CultureYouAreCodingWith +//例如,如果您在源文件中使用的是美国英语, +//使用的是美国英语,请将 设置为 en-US。 然后取消 +//对以下 NeutralResourceLanguage 特性的注释。 更新 +//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //主题特定资源词典所处位置 + //(未在页面中找到资源时使用, + //或应用程序资源字典中找到时使用) + ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 + //(未在页面中找到资源时使用, + //、应用程序或任何主题专用资源字典中找到时使用) +)] + + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: Guid("54EA0FD9-3908-4A27-8AF7-B98EDCE7804E")] diff --git a/Updater/Properties/Resources.Designer.cs b/Updater/Properties/Resources.Designer.cs new file mode 100644 index 0000000..9564639 --- /dev/null +++ b/Updater/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Updater.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Updater.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Updater/Properties/Resources.resx b/Updater/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Updater/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Updater/Properties/Settings.Designer.cs b/Updater/Properties/Settings.Designer.cs new file mode 100644 index 0000000..dfcd23b --- /dev/null +++ b/Updater/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Updater.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Updater/Properties/Settings.settings b/Updater/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/Updater/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Updater/Unzip.cs b/Updater/Unzip.cs new file mode 100644 index 0000000..53c5438 --- /dev/null +++ b/Updater/Unzip.cs @@ -0,0 +1,85 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; + +namespace Updater +{ + public class Unzip + { + /// + /// 忽略的文件列表 + /// + static readonly string[] IgnoreFiles = { }; + public static bool ExtractZipFile(string zipPath, string extractPath) + { + try + { + if (!extractPath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) + extractPath += Path.DirectorySeparatorChar; + + using (ZipArchive archive = ZipFile.OpenRead(zipPath)) + { + foreach (ZipArchiveEntry entry in archive.Entries) + { + + if (!IsIgnoreFile(entry.FullName)) + { + // Gets the full path to ensure that relative segments are removed. + string destinationPath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName)); + if (!IsDir(destinationPath)) + { + // 判断路径是否存在 + string dir = Path.GetDirectoryName(destinationPath); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + + if (File.Exists(destinationPath)) + { + File.Delete(destinationPath); + } + // Ordinal match is safest, case-sensitive volumes can be mounted within volumes that + // are case-insensitive. + Debug.WriteLine($"抽取:{destinationPath}"); + if (destinationPath.StartsWith(extractPath, StringComparison.Ordinal)) + entry.ExtractToFile(destinationPath); + } + else + { + //创建目录 + Directory.CreateDirectory(destinationPath); + } + } + } + return true; + } + } + catch + { + return false; + } + } + + /// + /// 指示文件是否是忽略的 + /// + /// + /// + static bool IsIgnoreFile(string fileName) + { + return (Array.IndexOf(IgnoreFiles, fileName) != -1); + } + /// + /// 指示路径是否是目录 + /// + /// + /// + static bool IsDir(string path) + { + return path.Last() == '\\'; + } + } +} diff --git a/Updater/Updater.csproj b/Updater/Updater.csproj new file mode 100644 index 0000000..e1f6b28 --- /dev/null +++ b/Updater/Updater.csproj @@ -0,0 +1,113 @@ + + + + + Debug + AnyCPU + {A49C9514-81CA-4FB6-A586-17477E4F28A8} + WinExe + Updater + Updater + v4.8 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + +     +    .allowedextension +   + AnyCPU + none + true + bin\Release\ + TRACE + prompt + 4 + false + + + + ..\packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + \ No newline at end of file diff --git a/Updater/packages.config b/Updater/packages.config new file mode 100644 index 0000000..4de699c --- /dev/null +++ b/Updater/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file