增加程序更新功能

Beta
凯 王 2022-06-14 23:02:55 +08:00
parent 433e03a448
commit 90e07b6f2f
35 changed files with 3331 additions and 48 deletions

View File

@ -3,9 +3,23 @@
<component name="AutoGeneratedRunConfigurationManager">
<projectFile>WinformGeneralDeveloperFrame.Start/Start.csproj</projectFile>
<projectFile>WinformGeneralPrimordialForm/PrimordialForm.csproj</projectFile>
<projectFile>Update/Update.csproj</projectFile>
</component>
<component name="ChangeListManager">
<list default="true" id="6ebc9dde-4dcc-424b-9663-06c3bf6f8c79" name="Changes" comment="" />
<list default="true" id="6ebc9dde-4dcc-424b-9663-06c3bf6f8c79" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.WinformGeneralDeveloperFrame/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.WinformGeneralDeveloperFrame/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.vs/WinformGeneralDeveloperFrame/v17/.suo" beforeDir="false" afterPath="$PROJECT_DIR$/.vs/WinformGeneralDeveloperFrame/v17/.suo" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.vs/WinformGeneralDeveloperFrame/v17/fileList.bin" beforeDir="false" afterPath="$PROJECT_DIR$/.vs/WinformGeneralDeveloperFrame/v17/fileList.bin" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Update/Class1.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Update/Properties/AssemblyInfo.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Update/Properties/AssemblyInfo.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Update/Update.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/Update/Update.csproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/WinformGeneralDeveloperFrame.Commons/GetDataTableUtils.cs" beforeDir="false" afterPath="$PROJECT_DIR$/WinformGeneralDeveloperFrame.Commons/GetDataTableUtils.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/WinformGeneralDeveloperFrame.Start/App.config" beforeDir="false" afterPath="$PROJECT_DIR$/WinformGeneralDeveloperFrame.Start/App.config" afterDir="false" />
<change beforePath="$PROJECT_DIR$/WinformGeneralDeveloperFrame.sln" beforeDir="false" afterPath="$PROJECT_DIR$/WinformGeneralDeveloperFrame.sln" afterDir="false" />
<change beforePath="$PROJECT_DIR$/WinformGeneralDeveloperFrame/DB.cs" beforeDir="false" afterPath="$PROJECT_DIR$/WinformGeneralDeveloperFrame/DB.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/WinformGeneralDeveloperFrame/DB/MESDB.cs" beforeDir="false" afterPath="$PROJECT_DIR$/WinformGeneralDeveloperFrame/DB/MESDB.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/WinformGeneralDeveloperFrame/LoginView.cs" beforeDir="false" afterPath="$PROJECT_DIR$/WinformGeneralDeveloperFrame/LoginView.cs" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@ -66,6 +80,24 @@
<option name="Build" />
</method>
</configuration>
<configuration name="Update" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/Update/Update.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="Console" />
<option name="PROJECT_TFM" value="" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
@ -77,6 +109,9 @@
<updated>1637673594984</updated>
<workItem from="1637673603163" duration="178000" />
<workItem from="1646484218854" duration="261000" />
<workItem from="1652186181534" duration="3660000" />
<workItem from="1653834391439" duration="828000" />
<workItem from="1654865714910" duration="1917000" />
</task>
<servers />
</component>

385
Update.Core/Downloader.cs Normal file
View File

@ -0,0 +1,385 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.ComponentModel;
using System.Xml.Serialization;
using System.IO;
using System.Threading;
using System.Collections.Specialized;
namespace Updater.Core
{
/// <summary>
/// 下载错误事件数据
/// </summary>
public class DownloadErrorEventArgs : EventArgs
{
public Exception Error { get; set; }
public Manifest Manifest { get; set; }
}
/// <summary>
/// 下载进度事件数据
/// </summary>
public class DownloadProgressEventArgs : ProgressChangedEventArgs
{
public DownloadProgressEventArgs(int progressPercentage, object userState)
: base(progressPercentage, userState)
{ }
/// <summary>
/// 当前下载的文件名
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 获取收到的字节数。
/// </summary>
public long BytesReceived { get; set; }
/// <summary>
/// 获取 System.Net.WebClient 数据下载操作中的字节总数。
/// </summary>
public long TotalBytesToReceive { get; set; }
}
/// <summary>
/// 下载完成事件数据
/// </summary>
public class DownloadCompleteEventArgs : AsyncCompletedEventArgs
{
public DownloadCompleteEventArgs(Exception error, bool cancelled, object userState)
: base(error, cancelled, userState)
{
}
public Manifest Manifest { get; set; }
}
/// <summary>
/// 服务器文件下载类
/// </summary>
public class DownloadClass : Component
{
#region 变量定义
private WebClient webClient = new WebClient();
private Manifest manifest;
private int fileCount = 0;
private bool cancel = false;
private string tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "temp");
private HybridDictionary userStateToLifetime = new HybridDictionary();
private object defaultTaskId = new object();
private delegate void WorkerEventHandler(AsyncOperation asyncOp);
private System.ComponentModel.Container components = null;
private SendOrPostCallback onProgressReportDelegate;
private SendOrPostCallback onCompletedDelegate;
private AsyncOperation current;
#endregion
#region 事件
/// <summary>
/// 下载进度
/// </summary>
public event EventHandler<DownloadProgressEventArgs> DownloadProgressChanged;
/// <summary>
/// 下载完成事件
/// </summary>
public event EventHandler<DownloadCompleteEventArgs> DownloadCompleted;
/// <summary>
/// 下载错误触发的事件
/// </summary>
public event EventHandler<DownloadErrorEventArgs> DownloadError;
#endregion
#region 构造及析构
public DownloadClass(IContainer container)
{
container.Add(this);
InitializeComponent();
InitializeDelegates();
}
public DownloadClass()
{
InitializeComponent();
InitializeDelegates();
}
/// <summary>
/// 初始化代理
/// </summary>
protected virtual void InitializeDelegates()
{
onProgressReportDelegate = new SendOrPostCallback(ReportProgress);
onCompletedDelegate = new SendOrPostCallback(DoDownloadCompleted);
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
#endregion
/// <summary>
/// 触发下载进度事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadProgressChanged(DownloadProgressEventArgs e)
{
if (DownloadProgressChanged != null)
{
DownloadProgressChanged(this, e);
}
}
/// <summary>
/// 触发下载完成事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadCompleted(DownloadCompleteEventArgs e)
{
if (DownloadCompleted != null)
{
DownloadCompleted(this, e);
}
}
/// <summary>
/// 触发下载错误事件
/// </summary>
/// <param name="e"></param>
protected virtual void OnDownloadError(DownloadErrorEventArgs e)
{
if (DownloadError != null)
{
DownloadError(this, e);
}
}
/// <summary>
/// 下载文字保存的临时目录
/// </summary>
public string TempPath
{
get
{
return tempPath;
}
set
{
tempPath = value;
}
}
/// <summary>
/// 同步下载
/// </summary>
/// <param name="manifest">文件下载清单</param>
public void Download(Manifest manifest)
{
Init(manifest);
foreach (var file in manifest.ManifestFiles.Files)
{
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
string clientFileName = Path.Combine(tempPath, file.Source);
Uri uri = new Uri(serverFileName);
if (!Directory.Exists(Path.GetDirectoryName(clientFileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
}
webClient.DownloadFile(uri, clientFileName);
}
}
/// <summary>
/// 异步下载
/// </summary>
/// <param name="manifest">文件下载清单</param>
public void DownloadAsync(Manifest manifest)
{
Init(manifest);
DownloadAsync(manifest, defaultTaskId);
}
/// <summary>
/// 异步下载并指定任务Id
/// </summary>
/// <param name="manifest">文件下载清单</param>
/// <param name="taskId">任务Id</param>
public void DownloadAsync(Manifest manifest, object taskId)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId);
lock (userStateToLifetime.SyncRoot)
{
if (userStateToLifetime.Contains(taskId))
{
throw new ArgumentException("参数taskId必须是唯一的", "taskId");
}
userStateToLifetime[taskId] = asyncOp;
}
WorkerEventHandler workerDelegate = new WorkerEventHandler(DownloadWorker);
workerDelegate.BeginInvoke(asyncOp, null, null);
}
private void Init(Manifest manifest)
{
this.manifest = manifest;
webClient.BaseAddress = manifest.ManifestFiles.BaseUrl;
webClient.Credentials = CredentialCache.DefaultCredentials;
webClient.Encoding = Encoding.UTF8;
}
/// <summary>
/// 异步下载方法
/// </summary>
/// <param name="asyncOp"></param>
private void DownloadWorker(AsyncOperation asyncOp)
{
current = asyncOp;
if (!TaskCanceled(asyncOp.UserSuppliedState))
{
try
{
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
foreach (var file in manifest.ManifestFiles.Files)
{
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
string clientFileName = Path.Combine(tempPath, file.Source);
Uri uri = new Uri(serverFileName);
if (!Directory.Exists(Path.GetDirectoryName(clientFileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
}
while (webClient.IsBusy)
{
//阻塞异步下载
}
if (!cancel)
{
webClient.DownloadFileAsync(uri, clientFileName, file.Source);
}
}
}
catch (Exception ex)
{
DownloadErrorEventArgs e = new DownloadErrorEventArgs();
e.Error = ex;
e.Manifest = manifest;
OnDownloadError(e);
}
}
}
/// <summary>
/// 异步完成方法
/// </summary>
/// <param name="exception">异常数据</param>
/// <param name="canceled">是否取消</param>
/// <param name="asyncOp"></param>
private void CompletionMethod(Exception exception, bool canceled, AsyncOperation asyncOp)
{
if (!canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
DownloadCompleteEventArgs e = new DownloadCompleteEventArgs(exception, canceled, asyncOp.UserSuppliedState);
e.Manifest = manifest;
asyncOp.PostOperationCompleted(onCompletedDelegate, e);
current = null;
}
/// <summary>
/// 异步下载进度事件(仅对于单个文件)
/// </summary>
void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
DownloadProgressEventArgs args = new DownloadProgressEventArgs(e.ProgressPercentage, e.UserState);
args.BytesReceived = e.BytesReceived;
args.FileName = e.UserState.ToString();
args.TotalBytesToReceive = e.TotalBytesToReceive;
if (current != null)
{
current.Post(onProgressReportDelegate, args);
}
}
/// <summary>
/// 异步下载完成事件(仅对于单个文件)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
fileCount++;
if (fileCount == manifest.ManifestFiles.Files.Length)
{
this.CompletionMethod(e.Error, TaskCanceled(current.UserSuppliedState), current);
}
}
/// <summary>
/// 取消异步下载
/// </summary>
public void CancelAsync()
{
CancelAsync(defaultTaskId);
}
/// <summary>
/// 取消异步下载
/// </summary>
public void CancelAsync(object taskId)
{
webClient.CancelAsync();
cancel = true;
current = null;
AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation;
if (asyncOp != null)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(taskId);
}
}
}
private bool TaskCanceled(object taskId)
{
return cancel || (userStateToLifetime[taskId] == null);
}
private void DoDownloadCompleted(object operationState)
{
DownloadCompleteEventArgs e = operationState as DownloadCompleteEventArgs;
OnDownloadCompleted(e);
}
private void ReportProgress(object state)
{
DownloadProgressEventArgs e = state as DownloadProgressEventArgs;
OnDownloadProgressChanged(e);
}
}
}

View File

@ -0,0 +1,411 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Threading;
using System.Collections.Specialized;
using System.Collections;
using System.IO;
namespace Updater.Core
{
/// <summary>
/// 文件复制进度报告事件参数
/// </summary>
public class FileCopyProgressChangedEventArgs : ProgressChangedEventArgs
{
public FileCopyProgressChangedEventArgs(int progressPercentage, object userState)
: base(progressPercentage, userState)
{
}
/// <summary>
/// 当前复制的字节数
/// </summary>
public double BytesToCopy { get; set; }
/// <summary>
/// 当前复制操作中的字节总数
/// </summary>
public double TotalBytesToCopy { get; set; }
/// <summary>
/// 当前复制的源文件名
/// </summary>
public string SourceFileName { get; set; }
/// <summary>
/// 当前复制的目标文件名
/// </summary>
public string TargetFileName { get; set; }
public Manifest Manifest { get; set; }
}
/// <summary>
/// 文件复制完成事件参数
/// </summary>
public class FileCopyCompletedEventArgs : AsyncCompletedEventArgs
{
public FileCopyCompletedEventArgs(Exception error, bool cancelled, object userState)
: base(error, cancelled, userState)
{
}
public Manifest Manifest { get; set; }
}
/// <summary>
/// 文件复制错误事件参数
/// </summary>
public class FileCopyErrorEventArgs : EventArgs
{
public Exception Error { get; set; }
public Manifest Manifest { get; set; }
}
/// <summary>
/// 文件复制组件类
/// </summary>
public class FileCopyClass : Component
{
#region 变量定义
private object defaultTaskId = new object();
private int writeFileLength = 1024 * 64;
private delegate void WorkerEventHandler(Manifest manifest, string sourcePath, AsyncOperation asyncOp);
private SendOrPostCallback onProgressReportDelegate;
private SendOrPostCallback onCompletedDelegate;
private HybridDictionary userStateToLifetime = new HybridDictionary();
private System.ComponentModel.Container components = null;
#endregion
#region 事件
/// <summary>
/// 文件复制进度事件
/// </summary>
public event EventHandler<FileCopyProgressChangedEventArgs> FileCopyProgressChanged;
/// <summary>
/// 文件复制完成事件
/// </summary>
public event EventHandler<FileCopyCompletedEventArgs> FileCopyCompleted;
/// <summary>
/// 文件复制错误事件
/// </summary>
public event EventHandler<FileCopyErrorEventArgs> FileCopyError;
#endregion
#region 构造及析构
public FileCopyClass(IContainer container)
{
container.Add(this);
InitializeComponent();
InitializeDelegates();
}
public FileCopyClass()
{
InitializeComponent();
InitializeDelegates();
}
protected virtual void InitializeDelegates()
{
onProgressReportDelegate = new SendOrPostCallback(ReportProgress);
onCompletedDelegate = new SendOrPostCallback(CopyCompleted);
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
#endregion
#region 实现
public int WriteFileLength
{
set
{
writeFileLength = value;
}
}
public void Copy(Manifest manifest, string sourcePath)
{
string[] sourceFiles = null;
string[] targetFiles = null;
GetFiles(manifest, sourcePath, out sourceFiles, out targetFiles);
for (int i = 0; i < sourceFiles.Length; i++)
{
if (!Directory.Exists(Path.GetDirectoryName(targetFiles[i])))
{
Directory.CreateDirectory(Path.GetDirectoryName(targetFiles[i]));
}
File.Copy(sourceFiles[i], targetFiles[i], true);
}
}
public void CopyAsync(Manifest manifest, string sourcePath)
{
CopyAsync(manifest, sourcePath, defaultTaskId);
}
public void CopyAsync(Manifest manifest, string sourcePath, object taskId)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId);
lock (userStateToLifetime.SyncRoot)
{
if (userStateToLifetime.Contains(taskId))
{
throw new ArgumentException("参数taskId必须是唯一的", "taskId");
}
userStateToLifetime[taskId] = asyncOp;
}
WorkerEventHandler workerDelegate = new WorkerEventHandler(FileCopyWorker);
workerDelegate.BeginInvoke(manifest, sourcePath, asyncOp, null, null);
}
private bool TaskCanceled(object taskId)
{
return (userStateToLifetime[taskId] == null);
}
public void CancelAsync()
{
CancelAsync(defaultTaskId);
}
public void CancelAsync(object taskId)
{
AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation;
if (asyncOp != null)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(taskId);
}
}
}
private void FileCopyWorker(Manifest manifest, string sourcePath, AsyncOperation asyncOp)
{
Exception exception = null;
FileCopyProgressChangedEventArgs e = null;
Stream rStream = null;
Stream wStream = null;
double writeBytes = 0;
string[] sourceFiles = null;
string[] targetFiles = null;
GetFiles(manifest, sourcePath, out sourceFiles, out targetFiles);
if (!TaskCanceled(asyncOp.UserSuppliedState))
{
try
{
double totalBytes = GetFileLength(sourceFiles);
byte[] buffer = new byte[writeFileLength];
int len = 0;
int offset = 0;
for (int i = 0; i < sourceFiles.Length; i++)
{
try
{
if (!Directory.Exists(Path.GetDirectoryName(targetFiles[i])))
{
Directory.CreateDirectory(Path.GetDirectoryName(targetFiles[i]));
}
rStream = new FileStream(sourceFiles[i], FileMode.Open, FileAccess.Read, FileShare.None);
wStream = new FileStream(targetFiles[i], FileMode.Create, FileAccess.Write, FileShare.None);
while ((len = rStream.Read(buffer, offset, writeFileLength)) > 0)
{
wStream.Write(buffer, offset, len);
writeBytes += len;
e = new FileCopyProgressChangedEventArgs((int)(writeBytes / totalBytes * 100), asyncOp.UserSuppliedState);
e.SourceFileName = sourceFiles[i];
e.TargetFileName = targetFiles[i];
e.TotalBytesToCopy = totalBytes;
e.BytesToCopy = len;
e.Manifest = manifest;
asyncOp.Post(this.onProgressReportDelegate, e);
Thread.Sleep(1);
}
}
finally
{
DisposeStream(wStream);
DisposeStream(rStream);
}
}
}
catch (Exception ex)
{
exception = ex;
OnFileCopyError(new FileCopyErrorEventArgs() { Error = ex, Manifest = manifest });
}
}
this.CompletionMethod(manifest, exception, TaskCanceled(asyncOp.UserSuppliedState), asyncOp);
//如果文件是压缩文件,则解压这些文件
ZipFiles(e.Manifest);
}
private void GetFiles(Manifest manifest, string sourcePath, out string[] sourceFiles, out string[] targetFiles)
{
sourceFiles = new string[manifest.ManifestFiles.Files.Length];
targetFiles = new string[manifest.ManifestFiles.Files.Length];
string path = Path.GetFullPath(manifest.MyApplication.Location);
for (int i = 0; i < manifest.ManifestFiles.Files.Length; i++)
{
sourceFiles[i] = Path.Combine(sourcePath, manifest.ManifestFiles.Files[i].Source);
targetFiles[i] = Path.Combine(path, manifest.ManifestFiles.Files[i].Source);
}
}
private void DisposeStream(Stream stream)
{
if (stream != null)
{
stream.Flush();
stream.Close();
stream.Dispose();
}
}
private double GetFileLength(string[] sourceFiles)
{
double bytes = 0;
foreach (var file in sourceFiles)
{
FileInfo fileInfo = new FileInfo(file);
bytes += fileInfo.Length;
}
return bytes;
}
private void CopyCompleted(object operationState)
{
FileCopyCompletedEventArgs e = operationState as FileCopyCompletedEventArgs;
OnFileCopyCompleted(e);
}
private void ReportProgress(object state)
{
FileCopyProgressChangedEventArgs e = state as FileCopyProgressChangedEventArgs;
OnProgressChanged(e);
}
protected void OnFileCopyCompleted(FileCopyCompletedEventArgs e)
{
if (FileCopyCompleted != null)
{
FileCopyCompleted(this, e);
}
}
/// <summary>
/// 如果文件是压缩文件,则解压这些文件
/// </summary>
/// <param name="manifest"></param>
private void ZipFiles(Manifest manifest)
{
if (manifest != null)
{
string path = Path.GetFullPath(manifest.MyApplication.Location);
foreach (ManifestFile file in manifest.ManifestFiles.Files)
{
bool unzip = false;
bool.TryParse(file.Unzip, out unzip);
if (file.Source.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) && unzip)
{
string zipFile = Path.Combine(path, file.Source);
try
{
ZipUtility.UnZipFiles(zipFile, path, null, true);
}
catch (Exception ex)
{
WriteLine(ex.ToString());
}
}
}
}
}
public static void WriteLine(string message)
{
string temp = DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss] ") + message + "\r\n\r\n";
string fileName = DateTime.Now.ToString("yyyyMMdd") + ".log";
try
{
File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName), temp, Encoding.GetEncoding("GB2312"));
}
catch
{
}
}
protected void OnProgressChanged(FileCopyProgressChangedEventArgs e)
{
if (FileCopyProgressChanged != null)
{
FileCopyProgressChanged(this, e);
}
}
protected void OnFileCopyError(FileCopyErrorEventArgs e)
{
if (FileCopyError != null)
{
FileCopyError(this, e);
}
}
private void CompletionMethod(Manifest manifest, Exception exception, bool canceled, AsyncOperation asyncOp)
{
if (!canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
FileCopyCompletedEventArgs e = new FileCopyCompletedEventArgs(exception, canceled, asyncOp.UserSuppliedState);
e.Manifest = manifest;
asyncOp.PostOperationCompleted(onCompletedDelegate, e);
}
#endregion
}
}

655
Update.Core/GZip.cs Normal file
View File

@ -0,0 +1,655 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;
using System.IO.Compression;
namespace Updater.Core
{
/// <summary>
/// 压缩文件类
/// </summary>
public class GZip
{
#region MyRegion
/*
//Compress三个参数分别是“要压缩的目标目录”“保存压缩文件的目录”压缩文件名
GZip.Compress(@"E:\much\", @"E:\much\", "ziptest");
//Decompress三个参数分别是"压缩包所在目录","要解压到的目录",“压缩包名”
//如果压缩包所在目录不存在则解压不会成功
GZip.Decompress(@"E:\much\zip\", @"E:\much\zip\", "ziptest");
*/
#endregion
/// <summary>
/// Compress
/// </summary>
/// <param name="lpSourceFolder">The location of the files to include in the zip file, all files including files in subfolders will be included.</param>
/// <param name="lpDestFolder">Folder to write the zip file into</param>
/// <param name="zipFileName">Name of the zip file to write</param>
public static GZipResult Compress(string lpSourceFolder, string lpDestFolder, string zipFileName)
{
return Compress(lpSourceFolder, "*.*", SearchOption.AllDirectories, lpDestFolder, zipFileName, true);
}
/// <summary>
/// Compress
/// </summary>
/// <param name="lpSourceFolder">The location of the files to include in the zip file</param>
/// <param name="searchPattern">Search pattern (ie "*.*" or "*.txt" or "*.gif") to idendify what files in lpSourceFolder to include in the zip file</param>
/// <param name="searchOption">Only files in lpSourceFolder or include files in subfolders also</param>
/// <param name="lpDestFolder">Folder to write the zip file into</param>
/// <param name="zipFileName">Name of the zip file to write</param>
/// <param name="deleteTempFile">Boolean, true deleted the intermediate temp file, false leaves the temp file in lpDestFolder (for debugging)</param>
public static GZipResult Compress(string lpSourceFolder, string searchPattern, SearchOption searchOption, string lpDestFolder, string zipFileName, bool deleteTempFile)
{
DirectoryInfo di = new DirectoryInfo(lpSourceFolder);
FileInfo[] files = di.GetFiles("*.*", searchOption);
return Compress(files, lpSourceFolder, lpDestFolder, zipFileName, deleteTempFile);
}
/// <summary>
/// Compress
/// </summary>
/// <param name="files">Array of FileInfo objects to be included in the zip file</param>
/// <param name="lpBaseFolder">Base folder to use when creating relative paths for the files
/// stored in the zip file. For example, if lpBaseFolder is 'C:\zipTest\Files\', and there is a file
/// 'C:\zipTest\Files\folder1\sample.txt' in the 'files' array, the relative path for sample.txt
/// will be 'folder1/sample.txt'</param>
/// <param name="lpDestFolder">Folder to write the zip file into</param>
/// <param name="zipFileName">Name of the zip file to write</param>
public static GZipResult Compress(FileInfo[] files, string lpBaseFolder, string lpDestFolder, string zipFileName)
{
return Compress(files, lpBaseFolder, lpDestFolder, zipFileName, true);
}
/// <summary>
/// Compress
/// </summary>
/// <param name="files">Array of FileInfo objects to be included in the zip file</param>
/// <param name="lpBaseFolder">Base folder to use when creating relative paths for the files
/// stored in the zip file. For example, if lpBaseFolder is 'C:\zipTest\Files\', and there is a file
/// 'C:\zipTest\Files\folder1\sample.txt' in the 'files' array, the relative path for sample.txt
/// will be 'folder1/sample.txt'</param>
/// <param name="lpDestFolder">Folder to write the zip file into</param>
/// <param name="zipFileName">Name of the zip file to write</param>
/// <param name="deleteTempFile">Boolean, true deleted the intermediate temp file, false leaves the temp file in lpDestFolder (for debugging)</param>
public static GZipResult Compress(FileInfo[] files, string lpBaseFolder, string lpDestFolder, string zipFileName, bool deleteTempFile)
{
GZipResult result = new GZipResult();
try
{
if (!lpDestFolder.EndsWith("\\"))
{
lpDestFolder += "\\";
}
string lpTempFile = lpDestFolder + zipFileName + ".tmp";
string lpZipFile = lpDestFolder + zipFileName;
result.TempFile = lpTempFile;
result.ZipFile = lpZipFile;
if (files != null && files.Length > 0)
{
CreateTempFile(files, lpBaseFolder, lpTempFile, result);
if (result.FileCount > 0)
{
CreateZipFile(lpTempFile, lpZipFile, result);
}
// delete the temp file
if (deleteTempFile)
{
File.Delete(lpTempFile);
result.TempFileDeleted = true;
}
}
}
catch //(Exception ex4)
{
result.Errors = true;
}
return result;
}
private static void CreateZipFile(string lpSourceFile, string lpZipFile, GZipResult result)
{
byte[] buffer;
int count = 0;
FileStream fsOut = null;
FileStream fsIn = null;
GZipStream gzip = null;
// compress the file into the zip file
try
{
fsOut = new FileStream(lpZipFile, FileMode.Create, FileAccess.Write, FileShare.None);
gzip = new GZipStream(fsOut, CompressionMode.Compress, true);
fsIn = new FileStream(lpSourceFile, FileMode.Open, FileAccess.Read, FileShare.Read);
buffer = new byte[fsIn.Length];
count = fsIn.Read(buffer, 0, buffer.Length);
fsIn.Close();
fsIn = null;
// compress to the zip file
gzip.Write(buffer, 0, buffer.Length);
result.ZipFileSize = fsOut.Length;
result.CompressionPercent = GetCompressionPercent(result.TempFileSize, result.ZipFileSize);
}
catch //(Exception ex1)
{
result.Errors = true;
}
finally
{
if (gzip != null)
{
gzip.Close();
gzip = null;
}
if (fsOut != null)
{
fsOut.Close();
fsOut = null;
}
if (fsIn != null)
{
fsIn.Close();
fsIn = null;
}
}
}
private static void CreateTempFile(FileInfo[] files, string lpBaseFolder, string lpTempFile, GZipResult result)
{
byte[] buffer;
int count = 0;
byte[] header;
string fileHeader = null;
string fileModDate = null;
string lpFolder = null;
int fileIndex = 0;
string lpSourceFile = null;
string vpSourceFile = null;
GZipFileInfo gzf = null;
FileStream fsOut = null;
FileStream fsIn = null;
if (files != null && files.Length > 0)
{
try
{
result.Files = new GZipFileInfo[files.Length];
// open the temp file for writing
fsOut = new FileStream(lpTempFile, FileMode.Create, FileAccess.Write, FileShare.None);
foreach (FileInfo fi in files)
{
lpFolder = fi.DirectoryName + "\\";
try
{
gzf = new GZipFileInfo();
gzf.Index = fileIndex;
// read the source file, get its virtual path within the source folder
lpSourceFile = fi.FullName;
gzf.LocalPath = lpSourceFile;
vpSourceFile = lpSourceFile.Replace(lpBaseFolder, string.Empty);
vpSourceFile = vpSourceFile.Replace("\\", "/");
gzf.RelativePath = vpSourceFile;
fsIn = new FileStream(lpSourceFile, FileMode.Open, FileAccess.Read, FileShare.Read);
buffer = new byte[fsIn.Length];
count = fsIn.Read(buffer, 0, buffer.Length);
fsIn.Close();
fsIn = null;
fileModDate = fi.LastWriteTimeUtc.ToString();
gzf.ModifiedDate = fi.LastWriteTimeUtc;
gzf.Length = buffer.Length;
fileHeader = fileIndex.ToString() + "," + vpSourceFile + "," + fileModDate + "," + buffer.Length.ToString() + "\n";
header = Encoding.Default.GetBytes(fileHeader);
fsOut.Write(header, 0, header.Length);
fsOut.Write(buffer, 0, buffer.Length);
fsOut.WriteByte(10); // linefeed
gzf.AddedToTempFile = true;
// update the result object
result.Files[fileIndex] = gzf;
// increment the fileIndex
fileIndex++;
}
catch //(Exception ex1)
{
result.Errors = true;
}
finally
{
if (fsIn != null)
{
fsIn.Close();
fsIn = null;
}
}
if (fsOut != null)
{
result.TempFileSize = fsOut.Length;
}
}
}
catch //(Exception ex2)
{
result.Errors = true;
}
finally
{
if (fsOut != null)
{
fsOut.Close();
fsOut = null;
}
}
}
result.FileCount = fileIndex;
}
public static GZipResult Decompress(string lpSourceFolder, string lpDestFolder, string zipFileName)
{
return Decompress(lpSourceFolder, lpDestFolder, zipFileName, true, true, null, null, 4096);
}
public static GZipResult Decompress(string lpSourceFolder, string lpDestFolder, string zipFileName, bool writeFiles, string addExtension)
{
return Decompress(lpSourceFolder, lpDestFolder, zipFileName, true, writeFiles, addExtension, null, 4096);
}
public static GZipResult Decompress(string lpSrcFolder, string lpDestFolder, string zipFileName,
bool deleteTempFile, bool writeFiles, string addExtension, Hashtable htFiles, int bufferSize)
{
GZipResult result = new GZipResult();
if (!lpDestFolder.EndsWith("\\"))
{
lpDestFolder += "\\";
}
string lpTempFile = lpSrcFolder + zipFileName + ".tmp";
string lpZipFile = lpSrcFolder + zipFileName;
result.TempFile = lpTempFile;
result.ZipFile = lpZipFile;
string line = null;
string lpFilePath = null;
string lpFolder = null;
GZipFileInfo gzf = null;
FileStream fsTemp = null;
ArrayList gzfs = new ArrayList();
bool write = false;
if (string.IsNullOrEmpty(addExtension))
{
addExtension = string.Empty;
}
else if (!addExtension.StartsWith("."))
{
addExtension = "." + addExtension;
}
// extract the files from the temp file
try
{
fsTemp = UnzipToTempFile(lpZipFile, lpTempFile, result);
if (fsTemp != null)
{
while (fsTemp.Position != fsTemp.Length)
{
line = null;
while (string.IsNullOrEmpty(line) && fsTemp.Position != fsTemp.Length)
{
line = ReadLine(fsTemp);
}
if (!string.IsNullOrEmpty(line))
{
gzf = new GZipFileInfo();
if (gzf.ParseFileInfo(line) && gzf.Length > 0)
{
gzfs.Add(gzf);
lpFilePath = lpDestFolder + gzf.RelativePath;
lpFolder = GetFolder(lpFilePath);
gzf.LocalPath = lpFilePath;
write = false;
if (htFiles == null || htFiles.ContainsKey(gzf.RelativePath))
{
gzf.RestoreRequested = true;
write = writeFiles;
}
if (write)
{
// make sure the folder exists
if (!Directory.Exists(lpFolder))
{
Directory.CreateDirectory(lpFolder);
}
// read from fsTemp and write out the file
gzf.Restored = WriteFile(fsTemp, gzf.Length, lpFilePath + addExtension, bufferSize);
}
else
{
// need to advance fsTemp
fsTemp.Position += gzf.Length;
}
}
}
}
}
}
catch //(Exception ex3)
{
result.Errors = true;
}
finally
{
if (fsTemp != null)
{
fsTemp.Close();
fsTemp = null;
}
}
// delete the temp file
try
{
if (deleteTempFile)
{
File.Delete(lpTempFile);
result.TempFileDeleted = true;
}
}
catch //(Exception ex4)
{
result.Errors = true;
}
result.FileCount = gzfs.Count;
result.Files = new GZipFileInfo[gzfs.Count];
gzfs.CopyTo(result.Files);
return result;
}
private static string ReadLine(FileStream fs)
{
string line = string.Empty;
const int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
byte b = 0;
byte lf = 10;
int i = 0;
while (b != lf)
{
b = (byte)fs.ReadByte();
buffer[i] = b;
i++;
}
line = System.Text.Encoding.Default.GetString(buffer, 0, i - 1);
return line;
}
private static bool WriteFile(FileStream fs, int fileLength, string lpFile, int bufferSize)
{
bool success = false;
FileStream fsFile = null;
if (bufferSize == 0 || fileLength < bufferSize)
{
bufferSize = fileLength;
}
int count = 0;
int remaining = fileLength;
int readSize = 0;
try
{
byte[] buffer = new byte[bufferSize];
fsFile = new FileStream(lpFile, FileMode.Create, FileAccess.Write, FileShare.None);
while (remaining > 0)
{
if (remaining > bufferSize)
{
readSize = bufferSize;
}
else
{
readSize = remaining;
}
count = fs.Read(buffer, 0, readSize);
remaining -= count;
if (count == 0)
{
break;
}
fsFile.Write(buffer, 0, count);
fsFile.Flush();
}
fsFile.Flush();
fsFile.Close();
fsFile = null;
success = true;
}
catch //(Exception ex2)
{
success = false;
}
finally
{
if (fsFile != null)
{
fsFile.Flush();
fsFile.Close();
fsFile = null;
}
}
return success;
}
private static string GetFolder(string lpFilePath)
{
string lpFolder = lpFilePath;
int index = lpFolder.LastIndexOf("\\");
if (index != -1)
{
lpFolder = lpFolder.Substring(0, index + 1);
}
return lpFolder;
}
private static FileStream UnzipToTempFile(string lpZipFile, string lpTempFile, GZipResult result)
{
FileStream fsIn = null;
GZipStream gzip = null;
FileStream fsOut = null;
FileStream fsTemp = null;
const int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int count = 0;
try
{
fsIn = new FileStream(lpZipFile, FileMode.Open, FileAccess.Read, FileShare.Read);
result.ZipFileSize = fsIn.Length;
fsOut = new FileStream(lpTempFile, FileMode.Create, FileAccess.Write, FileShare.None);
gzip = new GZipStream(fsIn, CompressionMode.Decompress, true);
while (true)
{
count = gzip.Read(buffer, 0, bufferSize);
if (count != 0)
{
fsOut.Write(buffer, 0, count);
}
if (count != bufferSize)
{
break;
}
}
}
catch (Exception ex1)
{
result.Errors = true;
}
finally
{
if (gzip != null)
{
gzip.Close();
gzip = null;
}
if (fsOut != null)
{
fsOut.Close();
fsOut = null;
}
if (fsIn != null)
{
fsIn.Close();
fsIn = null;
}
}
fsTemp = new FileStream(lpTempFile, FileMode.Open, FileAccess.Read, FileShare.None);
if (fsTemp != null)
{
result.TempFileSize = fsTemp.Length;
}
return fsTemp;
}
private static int GetCompressionPercent(long tempLen, long zipLen)
{
double tmp = (double)tempLen;
double zip = (double)zipLen;
double hundred = 100;
double ratio = (tmp - zip) / tmp;
double pcnt = ratio * hundred;
return (int)pcnt;
}
}
/// <summary>
/// 要压缩的文件信息
/// </summary>
public class GZipFileInfo
{
/// <summary>
/// 文件索引
/// </summary>
public int Index = 0;
/// <summary>
/// 文件相对路径,'/'
/// </summary>
public string RelativePath = null;
public DateTime ModifiedDate;
/// <summary>
/// 文件内容长度
/// </summary>
public int Length = 0;
public bool AddedToTempFile = false;
public bool RestoreRequested = false;
public bool Restored = false;
/// <summary>
/// 文件绝对路径,'\'
/// </summary>
public string LocalPath = null;
public string Folder = null;
public bool ParseFileInfo(string fileInfo)
{
bool success = false;
try
{
if (!string.IsNullOrEmpty(fileInfo))
{
// get the file information
string[] info = fileInfo.Split(',');
if (info != null && info.Length == 4)
{
this.Index = Convert.ToInt32(info[0]);
this.RelativePath = info[1].Replace("/", "\\");
this.ModifiedDate = Convert.ToDateTime(info[2]);
this.Length = Convert.ToInt32(info[3]);
success = true;
}
}
}
catch
{
success = false;
}
return success;
}
}
/// <summary>
/// 文件压缩后的压缩包类
/// </summary>
public class GZipResult
{
/// <summary>
/// 压缩包中包含的所有文件,包括子目录下的文件
/// </summary>
public GZipFileInfo[] Files = null;
/// <summary>
/// 要压缩的文件数
/// </summary>
public int FileCount = 0;
public long TempFileSize = 0;
public long ZipFileSize = 0;
/// <summary>
/// 压缩百分比
/// </summary>
public int CompressionPercent = 0;
/// <summary>
/// 临时文件
/// </summary>
public string TempFile = null;
/// <summary>
/// 压缩文件
/// </summary>
public string ZipFile = null;
/// <summary>
/// 是否删除临时文件
/// </summary>
public bool TempFileDeleted = false;
public bool Errors = false;
}
}

184
Update.Core/Model.cs Normal file
View File

@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
namespace Updater.Core
{
/// <summary>
/// 文件清单对象
/// </summary>
[XmlRoot("manifest")]
public class Manifest
{
[XmlElement("version")]
public string Version { get; set; }
[XmlElement("description")]
public string Description { get; set; }
[XmlElement("fileBytes")]
public long FileBytes { get; set; }
[XmlElement("myapplication")]
public MyApplication MyApplication { get; set; }
[XmlElement("files")]
public ManifestFiles ManifestFiles { get; set; }
}
/// <summary>
/// 更新的文件列表
/// </summary>
public class ManifestFiles
{
[XmlElement("file")]
public ManifestFile[] Files { get; set; }
[XmlAttribute("base")]
public string BaseUrl { get; set; }
}
/// <summary>
/// 更新的单个文件对象
/// </summary>
public class ManifestFile
{
[XmlAttribute("source")]
public string Source
{
get;
set;
}
[XmlAttribute("hash")]
public string Hash
{
get;
set;
}
[XmlAttribute("unzip")]
public string Unzip
{
get;
set;
}
}
/// <summary>
/// 更新的程序对象
/// </summary>
public class MyApplication
{
[XmlAttribute("applicationId")]
public string ApplicationId { get; set; }
[XmlElement("location")]
public string Location { get; set; }
[XmlElement("entryPoint")]
public EntryPoint EntryPoint { get; set; }
}
/// <summary>
/// 程序启动对象
/// </summary>
public class EntryPoint
{
[XmlAttribute("file")]
public string File { get; set; }
[XmlAttribute("parameters")]
public string Parameters { get; set; }
}
/// <summary>
/// 客户端配置文件对象
/// </summary>
public class UpdaterConfigurationView
{
private static XmlDocument document = new XmlDocument();
private static readonly string xmlFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "updateconfiguration.config");
static UpdaterConfigurationView()
{
document.Load(xmlFileName);
}
/// <summary>
/// 刷新配置文件信息
/// </summary>
public void Refresh()
{
document.RemoveAll();
document.Load(xmlFileName);
}
/// <summary>
/// 程序版本
/// </summary>
public string Version
{
get
{
return document.SelectSingleNode("applicationUpdater").Attributes["version"].Value;
}
set
{
document.SelectSingleNode("applicationUpdater").Attributes["version"].Value = value;
document.Save(xmlFileName);
}
}
/// <summary>
/// 应用程序唯一标识
/// </summary>
public string ApplicationId
{
get
{
return document.SelectSingleNode("applicationUpdater").Attributes["applicationId"].Value;
}
set
{
document.SelectSingleNode("applicationUpdater").Attributes["applicationId"].Value = value;
document.Save(xmlFileName);
}
}
/// <summary>
/// 远程更新文件的清单路径
/// </summary>
public string ManifestUri
{
get
{
return document.SelectSingleNode("applicationUpdater").Attributes["manifestUri"].Value;
}
set
{
document.SelectSingleNode("applicationUpdater").Attributes["manifestUri"].Value = value;
document.Save(xmlFileName);
}
}
/// <summary>
/// 程序名称
/// </summary>
public string Title
{
get
{
return document.SelectSingleNode("applicationUpdater").Attributes["title"].Value;
}
set
{
document.SelectSingleNode("applicationUpdater").Attributes["title"].Value = value;
document.Save(xmlFileName);
}
}
}
}

View File

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

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4903D5F5-FF01-426D-B5BB-AADF7C4232FA}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Update.Core</RootNamespace>
<AssemblyName>Update.Core</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="ICSharpCode.SharpZipLib, Version=1.3.3.11, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Downloader.cs" />
<Compile Include="FileCopyClass.cs" />
<Compile Include="GZip.cs" />
<Compile Include="Model.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UpdateClass.cs" />
<Compile Include="ZipUtility.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

386
Update.Core/UpdateClass.cs Normal file
View File

@ -0,0 +1,386 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System.ComponentModel;
namespace Updater.Core
{
/// <summary>
/// 程序更新事件参数
/// </summary>
public class ManifestEventArgs : EventArgs
{
public Manifest Manifest { get; set; }
}
/// <summary>
/// 激活安装开始事件参数
/// </summary>
public class ActivationStartedEventArgs : EventArgs
{
public Manifest Manifest { get; set; }
public bool Cancel { get; set; }
}
/// <summary>
/// 安装完成事件参数
/// </summary>
public class ActivationCompletedEventArgs : AsyncCompletedEventArgs
{
public ActivationCompletedEventArgs(Exception error, bool cancelled, object userState)
: base(error, cancelled, userState)
{
}
public Manifest Manifest { get; set; }
}
/// <summary>
/// 程序自动更新操作类,封装了文件下载、文件复制、文件解压等操作
/// </summary>
public class UpdateClass
{
#region 变量属性
private DownloadClass downloader = new DownloadClass();
private FileCopyClass fileCopyer = new FileCopyClass();
private UpdaterConfigurationView updateCfgView = new UpdaterConfigurationView();
private string backupFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "backup");
/// <summary>
/// 封装的文件下载操作类
/// </summary>
public DownloadClass Downloader
{
get
{
return downloader;
}
}
/// <summary>
/// 封装的文件复制操作类
/// </summary>
public FileCopyClass FileCopyer
{
get
{
return fileCopyer;
}
}
#endregion
#region 事件
/// <summary>
/// 下载进度
/// </summary>
public event EventHandler<DownloadProgressEventArgs> DownloadProgressChanged;
/// <summary>
/// 下载完成事件
/// </summary>
public event EventHandler<DownloadCompleteEventArgs> DownloadCompleted;
/// <summary>
/// 下载错误触发的事件
/// </summary>
public event EventHandler<DownloadErrorEventArgs> DownloadError;
public event EventHandler<ManifestEventArgs> ActivationInitializing;
public event EventHandler<ActivationCompletedEventArgs> ActivationCompleted;
public event EventHandler<ActivationStartedEventArgs> ActivationStarted;
public event EventHandler<FileCopyProgressChangedEventArgs> ActivationProgressChanged;
public event EventHandler<FileCopyErrorEventArgs> ActivationError;
#endregion
#region 下载更新实现
public UpdateClass()
{
downloader.DownloadCompleted += new EventHandler<DownloadCompleteEventArgs>(downloader_DownloadCompleted);
downloader.DownloadError += new EventHandler<DownloadErrorEventArgs>(downloader_DownloadError);
downloader.DownloadProgressChanged += new EventHandler<DownloadProgressEventArgs>(downloader_DownloadProgressChanged);
fileCopyer.FileCopyError += new EventHandler<FileCopyErrorEventArgs>(fileCopyer_FileCopyError);
fileCopyer.FileCopyCompleted += new EventHandler<FileCopyCompletedEventArgs>(fileCopyer_FileCopyCompleted);
fileCopyer.FileCopyProgressChanged += new EventHandler<FileCopyProgressChangedEventArgs>(fileCopyer_FileCopyProgressChanged);
}
/// <summary>
/// 是否有最新的版本
/// </summary>
public bool HasNewVersion
{
get
{
var m = CheckForUpdates();
return m.Length > 0;
}
}
/// <summary>
/// 检查更新,返回更新清单列表
/// </summary>
/// <returns></returns>
public Manifest[] CheckForUpdates()
{
updateCfgView.Refresh();
Uri uri = new Uri(updateCfgView.ManifestUri);
string doc = DownLoadFile(uri);
XmlSerializer xser = new XmlSerializer(typeof(Manifest));
var manifest = xser.Deserialize(new XmlTextReader(doc, XmlNodeType.Document, null)) as Manifest;
if (manifest == null ||
manifest.Version == updateCfgView.Version ||
manifest.MyApplication.ApplicationId != updateCfgView.ApplicationId)
{
return new Manifest[0];
}
return new Manifest[] { manifest };
}
/// <summary>
/// 用于远程下载文件清单
/// </summary>
/// <param name="uri">文件清单网络路径</param>
/// <returns></returns>
private string DownLoadFile(Uri uri)
{
WebRequest request = WebRequest.Create(uri);
request.Credentials = CredentialCache.DefaultCredentials;
string response = String.Empty;
using (WebResponse res = request.GetResponse())
{
using (StreamReader reader = new StreamReader(res.GetResponseStream(), true))
{
response = reader.ReadToEnd();
}
}
return response;
}
/// <summary>
/// 同步下载文件清单中的文件
/// </summary>
/// <param name="manifests">下载文件清单</param>
public void Download(Manifest[] manifests)
{
foreach (var m in manifests)
{
downloader.Download(m);
}
}
/// <summary>
/// 异步下载文件清单中的文件
/// </summary>
/// <param name="manifests">下载文件清单</param>
public void DownloadAsync(Manifest[] manifests)
{
foreach (var m in manifests)
{
downloader.DownloadAsync(m);
}
}
/// <summary>
/// 下载完毕后执行的启动操作
/// </summary>
/// <param name="manifests"></param>
public void Activate(Manifest[] manifests)
{
foreach (var m in manifests)
{
OnActivationInitializing(new ManifestEventArgs() { Manifest = m });
Backup(m);
ActivationStartedEventArgs e = new ActivationStartedEventArgs() { Manifest = m };
OnActivationStarted(e);
if (e.Cancel)
{
Clear();
break;
}
else
{
fileCopyer.CopyAsync(m, downloader.TempPath);
}
}
}
/// <summary>
/// 备份操作
/// </summary>
/// <param name="manifest">文件清单</param>
private void Backup(Manifest manifest)
{
try
{
string sourcePath = Path.GetFullPath(manifest.MyApplication.Location);
string s_filename = string.Empty;
string t_filename = string.Empty;
if (!Directory.Exists(backupFilePath))
{
Directory.CreateDirectory(backupFilePath);
}
foreach (var file in manifest.ManifestFiles.Files)
{
t_filename = Path.Combine(backupFilePath, file.Source);
s_filename = Path.Combine(sourcePath, file.Source);
if (File.Exists(s_filename))
{
File.Copy(s_filename, t_filename, true);
}
}
}
catch
{
}
}
/// <summary>
/// 回滚文件下载内容
/// </summary>
/// <param name="manifest"></param>
public void Rollback(Manifest manifest)
{
try
{
string filename = string.Empty;
foreach (var file in manifest.ManifestFiles.Files)
{
filename = Path.Combine(backupFilePath, file.Source);
File.Copy(filename, Path.Combine(Path.GetFullPath(manifest.MyApplication.Location), file.Source));
}
Directory.Delete(backupFilePath, true);
}
catch
{
}
}
/// <summary>
/// 清除临时文件
/// </summary>
private void Clear()
{
try
{
Directory.Delete(backupFilePath, true);
Directory.Delete(downloader.TempPath, true);
}
catch
{ }
}
#endregion
#region 事件处理
private void fileCopyer_FileCopyError(object sender, FileCopyErrorEventArgs e)
{
OnActivationError(e);
}
private void fileCopyer_FileCopyProgressChanged(object sender, FileCopyProgressChangedEventArgs e)
{
if (ActivationProgressChanged != null)
{
ActivationProgressChanged(sender, e);
}
}
private void fileCopyer_FileCopyCompleted(object sender, FileCopyCompletedEventArgs e)
{
Clear();
try
{
updateCfgView.Version = e.Manifest.Version;
}
catch
{ }
if (ActivationCompleted != null)
{
ActivationCompletedEventArgs evt = new ActivationCompletedEventArgs(e.Error, e.Cancelled, e.UserState);
evt.Manifest = e.Manifest;
OnActivationCompleted(evt);
}
}
private void downloader_DownloadProgressChanged(object sender, DownloadProgressEventArgs e)
{
if (DownloadProgressChanged != null)
{
DownloadProgressChanged(sender, e);
}
}
private void downloader_DownloadError(object sender, DownloadErrorEventArgs e)
{
if (DownloadError != null)
{
DownloadError(sender, e);
}
}
private void downloader_DownloadCompleted(object sender, DownloadCompleteEventArgs e)
{
if (DownloadCompleted != null)
{
DownloadCompleted(sender, e);
}
}
private void OnActivationInitializing(ManifestEventArgs e)
{
if (ActivationInitializing != null)
{
ActivationInitializing(this, e);
}
}
private void OnActivationStarted(ActivationStartedEventArgs e)
{
if (ActivationStarted != null)
{
ActivationStarted(this, e);
}
}
private void OnActivationCompleted(ActivationCompletedEventArgs e)
{
if (ActivationCompleted != null)
{
ActivationCompleted(this, e);
}
}
private void OnActivationError(FileCopyErrorEventArgs e)
{
if (ActivationError != null)
{
ActivationError(this, e);
}
}
private void OnActivationProgressChanged(FileCopyProgressChangedEventArgs e)
{
if (ActivationProgressChanged != null)
{
ActivationProgressChanged(this, e);
}
}
#endregion
}
}

153
Update.Core/ZipUtility.cs Normal file
View File

@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
namespace Updater.Core
{
public static class ZipUtility
{
/// <summary>
/// 压缩文件中的文件,可设置密码
/// </summary>
/// <param name="inputFolderPath">输入的文件夹</param>
/// <param name="outputPathAndFile">输出的压缩文件全名</param>
/// <param name="password">压缩密码</param>
public static void ZipFiles(string inputFolderPath, string outputPathAndFile, string password)
{
ArrayList ar = GenerateFileList(inputFolderPath);
int TrimLength = (Directory.GetParent(inputFolderPath)).ToString().Length;
// find number of chars to remove // from orginal file path
TrimLength += 1; //remove '\'
FileStream ostream;
byte[] obuffer;
string outPath = inputFolderPath + @"\" + outputPathAndFile;
ZipOutputStream oZipStream = new ZipOutputStream(File.Create(outPath));
if (!string.IsNullOrEmpty(password))
{
oZipStream.Password = password;
}
oZipStream.SetLevel(9); // 设置最大压缩率
ZipEntry oZipEntry;
foreach (string Fil in ar)
{
oZipEntry = new ZipEntry(Fil.Remove(0, TrimLength));
oZipStream.PutNextEntry(oZipEntry);
if (!Fil.EndsWith(@"/")) // 如果文件以 '/' 结束,则是目录
{
ostream = File.OpenRead(Fil);
obuffer = new byte[ostream.Length];
ostream.Read(obuffer, 0, obuffer.Length);
oZipStream.Write(obuffer, 0, obuffer.Length);
}
}
oZipStream.Finish();
oZipStream.Close();
}
/// <summary>
/// 根据文件夹生成文件列表
/// </summary>
/// <param name="Dir"></param>
/// <returns></returns>
private static ArrayList GenerateFileList(string Dir)
{
ArrayList fils = new ArrayList();
bool Empty = true;
foreach (string file in Directory.GetFiles(Dir))
{
fils.Add(file);
Empty = false;
}
if (Empty)
{
//加入完全为空的目录
if (Directory.GetDirectories(Dir).Length == 0)
{
fils.Add(Dir + @"/");
}
}
foreach (string dirs in Directory.GetDirectories(Dir)) // 递归目录
{
foreach (object obj in GenerateFileList(dirs))
{
fils.Add(obj);
}
}
return fils;
}
/// <summary>
/// 解压文件到指定的目录,可设置密码、删除原文件等
/// </summary>
/// <param name="zipPathAndFile">压缩文件全名</param>
/// <param name="outputFolder">解压输出文件目录</param>
/// <param name="password">解压密码</param>
/// <param name="deleteZipFile">是否删除原文件(压缩文件)</param>
public static void UnZipFiles(string zipPathAndFile, string outputFolder, string password, bool deleteZipFile)
{
using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipPathAndFile)))
{
if (password != null && password != String.Empty)
{
s.Password = password;
}
ZipEntry theEntry;
string tmpEntry = String.Empty;
while ((theEntry = s.GetNextEntry()) != null)
{
#region 遍历每个Entry对象进行解压处理
string directoryName = outputFolder;
string fileName = Path.GetFileName(theEntry.Name);
if (directoryName != "")
{
Directory.CreateDirectory(directoryName);
}
if (fileName != String.Empty)
{
if (theEntry.Name.IndexOf(".ini") < 0)
{
string fullPath = directoryName + "\\" + theEntry.Name;
fullPath = fullPath.Replace("\\ ", "\\");
string fullDirPath = Path.GetDirectoryName(fullPath);
if (!Directory.Exists(fullDirPath)) Directory.CreateDirectory(fullDirPath);
using (FileStream streamWriter = File.Create(fullPath))
{
#region 写入文件流
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
#endregion
}
}
}
#endregion
}
}
if (deleteZipFile)
{
File.Delete(zipPathAndFile);
}
}
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="SharpZipLib" version="1.3.3" targetFramework="net48" />
</packages>

6
Update/App.config Normal file
View File

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

View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Update
{
public class Class1
{
}
}

118
Update/Form1.Designer.cs generated Normal file
View File

@ -0,0 +1,118 @@
namespace Update
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.progressBarControl1 = new DevExpress.XtraEditors.ProgressBarControl();
this.lab_percent = new DevExpress.XtraEditors.LabelControl();
this.lab_filename = new System.Windows.Forms.Label();
this.lab_fileinfo = new System.Windows.Forms.Label();
this.lblUpdateLog = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.progressBarControl1.Properties)).BeginInit();
this.SuspendLayout();
//
// progressBarControl1
//
this.progressBarControl1.Location = new System.Drawing.Point(25, 63);
this.progressBarControl1.Name = "progressBarControl1";
this.progressBarControl1.Properties.Step = 1;
this.progressBarControl1.Size = new System.Drawing.Size(438, 35);
this.progressBarControl1.TabIndex = 0;
//
// lab_percent
//
this.lab_percent.Location = new System.Drawing.Point(469, 74);
this.lab_percent.Name = "lab_percent";
this.lab_percent.Size = new System.Drawing.Size(18, 15);
this.lab_percent.TabIndex = 1;
this.lab_percent.Text = "0%";
//
// lab_filename
//
this.lab_filename.BackColor = System.Drawing.Color.Transparent;
this.lab_filename.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lab_filename.ForeColor = System.Drawing.SystemColors.ActiveCaptionText;
this.lab_filename.Location = new System.Drawing.Point(31, 31);
this.lab_filename.Name = "lab_filename";
this.lab_filename.Size = new System.Drawing.Size(410, 19);
this.lab_filename.TabIndex = 3;
this.lab_filename.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lab_fileinfo
//
this.lab_fileinfo.BackColor = System.Drawing.Color.Transparent;
this.lab_fileinfo.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lab_fileinfo.ForeColor = System.Drawing.SystemColors.ActiveCaptionText;
this.lab_fileinfo.Location = new System.Drawing.Point(23, 114);
this.lab_fileinfo.Name = "lab_fileinfo";
this.lab_fileinfo.Size = new System.Drawing.Size(410, 19);
this.lab_fileinfo.TabIndex = 4;
this.lab_fileinfo.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lblUpdateLog
//
this.lblUpdateLog.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.lblUpdateLog.ForeColor = System.Drawing.SystemColors.ActiveCaptionText;
this.lblUpdateLog.Location = new System.Drawing.Point(23, 133);
this.lblUpdateLog.Name = "lblUpdateLog";
this.lblUpdateLog.Size = new System.Drawing.Size(440, 85);
this.lblUpdateLog.TabIndex = 6;
this.lblUpdateLog.Text = "更新说明:(无)";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(515, 233);
this.Controls.Add(this.lblUpdateLog);
this.Controls.Add(this.lab_fileinfo);
this.Controls.Add(this.lab_filename);
this.Controls.Add(this.lab_percent);
this.Controls.Add(this.progressBarControl1);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "版本更新";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.progressBarControl1.Properties)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private DevExpress.XtraEditors.ProgressBarControl progressBarControl1;
private DevExpress.XtraEditors.LabelControl lab_percent;
private System.Windows.Forms.Label lab_filename;
private System.Windows.Forms.Label lab_fileinfo;
private System.Windows.Forms.Label lblUpdateLog;
}
}

336
Update/Form1.cs Normal file
View File

@ -0,0 +1,336 @@
using DevExpress.XtraEditors;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Updater.Core;
namespace Update
{
public partial class Form1 : DevExpress.XtraEditors.XtraForm
{
//主程序传入的参数,系统标示 是否需要重新启动主程序
private string[] args;
//表示主程序打开时传入的参数
private readonly static string OPEN_FLAG = "121";
private bool isComplete = true;
private UpdateClass updater;
private List<Manifest> mList = new List<Manifest>();
private int mLen = 0;
public Form1()
{
InitializeComponent();
}
private void simpleButton1_Click(object sender, EventArgs e)
{
}
private void simpleButton1_Click_1(object sender, EventArgs e)
{
for (int i = 0; i <= 100; i++)
{
System.Threading.Thread.Sleep(10);
//progressBarControl1.PerformStep();
progressBarControl1.Position = i;
lab_percent.Text = i + "%";
//progressBarControl1.EditValue = i + 1;
//处理当前消息队列中的所有windows消息,不然进度条会不同步
System.Windows.Forms.Application.DoEvents();
}
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
updater = new UpdateClass();
updater.ActivationCompleted += new EventHandler<ActivationCompletedEventArgs>(ActivationCompleted);
updater.ActivationError += new EventHandler<FileCopyErrorEventArgs>(ActivationError);
updater.ActivationInitializing += new EventHandler<ManifestEventArgs>(ActivationInitializing);
updater.ActivationProgressChanged += new EventHandler<FileCopyProgressChangedEventArgs>(ActivationProgressChanged);
updater.ActivationStarted += new EventHandler<ActivationStartedEventArgs>(ActivationStarted);
updater.DownloadCompleted += new EventHandler<DownloadCompleteEventArgs>(DownloadCompleted);
updater.DownloadError += new EventHandler<DownloadErrorEventArgs>(DownloadError);
updater.DownloadProgressChanged += new EventHandler<DownloadProgressEventArgs>(DownloadProgressChanged);
InitUpdater();
}
catch (Exception ex)
{
Log.Write("更新错误:" + ex.Message);
XtraMessageBox.Show("更新错误", "系统提示");
}
}
void ActivationCompleted(object sender, ActivationCompletedEventArgs e)
{
//安装完成
isComplete = true;
lab_filename.Text = "安装完成";
lab_percent.Text = "100%";
if (progressBarControl1.Position != 100)
{
progressBarControl1.Position = 100;
}
if (e.Error != null)
{
lab_filename.Text += ",但出现错误";
lab_filename.Update();
}
else
{
lab_filename.Update();
System.Threading.Thread.Sleep(3000);
string filename = GetFileName(e.Manifest.MyApplication.Location, e.Manifest.MyApplication.EntryPoint.File);
Startup(filename, e.Manifest.MyApplication.EntryPoint.Parameters);
//if (args != null && args.Length > 0)
{
Exit();
}
}
}
private string GetFileName(string location, string file)
{
return Path.Combine(Path.GetFullPath(location), file);
}
void ActivationError(object sender, FileCopyErrorEventArgs e)
{
Log.Write("安装过程中出现错误,错误描述:" + e.Error.Message + System.Environment.NewLine + "Version:" + e.Manifest.Version);
XtraMessageBox.Show(this, "安装错误:" + e.Error.Message, "系统提示");
lab_filename.Text = "系统正在回滚";
updater.Rollback(e.Manifest);
}
void ActivationInitializing(object sender, ManifestEventArgs e)
{
lab_filename.Text = "正在初始化安装,请稍后......";
lab_filename.Update();
lab_percent.Text = "0%";
lab_percent.Update();
lab_fileinfo.Text = "";
lab_fileinfo.Update();
//progressBar1.Value = 0;
}
void ActivationProgressChanged(object sender, FileCopyProgressChangedEventArgs e)
{
progressBarControl1.Position = e.ProgressPercentage;
lab_percent.Text = e.ProgressPercentage.ToString() + "%";
lab_percent.Update();
lab_fileinfo.Text = string.Format("字节数:{0}/{1}", e.BytesToCopy, e.TotalBytesToCopy);
lab_fileinfo.Update();
lab_filename.Text = "正在安装:" + e.SourceFileName;
lab_filename.Update();
}
void ActivationStarted(object sender, ActivationStartedEventArgs e)
{
lab_filename.Text = "开始安装,请稍后......";
lab_filename.Update();
e.Cancel = CheckActivation();
if (e.Cancel)
{
lab_filename.Text = "安装已被取消";
isComplete = true;
}
}
private bool CheckActivation()
{
bool cancel = false;
//检查主程序(进程名称)是否打开,如果打开则提示
string[] processName = { "Client", "Server" };
foreach (string name in processName)
{
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(name);
if (processes != null && processes.Length != 0)
{
if (XtraMessageBox.Show(string.Format("进程{0}正在运行中,请关闭后重试。", name), "系统提示",
MessageBoxButtons.RetryCancel, MessageBoxIcon.Information) == System.Windows.Forms.DialogResult.Cancel)
{
cancel = true;
break;
}
else
{
return CheckActivation();
}
}
}
return cancel;
}
/// <summary>
/// 文件下载完毕执行的操作
/// </summary>
void DownloadCompleted(object sender, DownloadCompleteEventArgs e)
{
mList.Add(e.Manifest);
if (mList.Count == mLen)
{
updater.Activate(mList.ToArray());
mList.Clear();
}
}
void DownloadError(object sender, DownloadErrorEventArgs e)
{
Log.Write("下载过程中出现错误,错误描述:" + e.Error.Message + System.Environment.NewLine + "Version:" + e.Manifest.Version);
XtraMessageBox.Show("下载出错:" + e.Error.Message, "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
void DownloadProgressChanged(object sender, DownloadProgressEventArgs e)
{
progressBarControl1.Position = e.ProgressPercentage;
lab_percent.Text = e.ProgressPercentage.ToString() + "%";
lab_percent.Update();
lab_fileinfo.Text = string.Format("字节数:{0}/{1}", e.BytesReceived, e.TotalBytesToReceive);
lab_fileinfo.Update();
lab_filename.Text = "正在下载文件:" + e.FileName;
lab_filename.Update();
}
private void InitUpdater()
{
//从配置文件动态设置更新标题
UpdaterConfigurationView updateCfgView = new UpdaterConfigurationView();
var manifests = updater.CheckForUpdates();
mLen = manifests.Length;
if (updater.HasNewVersion)
{
//显示本次更新内容
string updateDescription = manifests[0].Description;
this.lblUpdateLog.Text = string.Format("更新说明:{0}", updateDescription);
if (args != null && args.Length > 0)
{
#region 关闭主程序
try
{
string entryPoint = manifests[0].MyApplication.EntryPoint.File;
KillProcessDos(entryPoint);
}
catch (Exception ex)
{
Log.Write(ex.ToString());
}
#endregion
}
isComplete = false;
updater.DownloadAsync(manifests);
}
else
{
lab_filename.Text = "";
XtraMessageBox.Show("您当前的版本已经是最新,不需要更新。", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
Exit();
}
}
/// <summary>
/// 使用DOS关闭进程
/// </summary>
/// <param name="processName">进程名称</param>
private void KillProcessDos(string processName)
{
RunCmd("taskkill /im " + processName + " /f ");
}
/// <summary>
/// 系统退出
/// </summary>
private void Exit()
{
this.Close();
Environment.Exit(0);
}
/// <summary>
/// 带参数启动指定的应用程序
/// </summary>
/// <param name="entryPoint">入口的应用程序</param>
/// <param name="parameters">程序启动参数</param>
private void Startup(string entryPoint, string parameters)
{
try
{
// if (args != null && args.Length > 0)
{
// if (args[0] == OPEN_FLAG)
{
//关闭主程序
ExeCommand("taskkill /im " + Path.GetFileName(entryPoint) + " /f ");
//启动主程序
System.Threading.Thread.Sleep(1000);
System.Diagnostics.Process.Start(entryPoint, parameters);
}
}
}
catch (Exception ex)
{
Log.Write(ex);
}
}
/// <summary>
/// DOS命令运行函数
/// </summary>
/// <param name="commandText"></param>
private void ExeCommand(string commandText)
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
try
{
p.Start();
p.StandardInput.WriteLine(commandText);
p.StandardInput.WriteLine("exit");
//p.StandardOutput.ReadToEnd();
}
catch
{
}
}
/// <summary>
/// 运行DOS命令
/// DOS关闭进程命令(ntsd -c q -p PID )PID为进程的ID
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
private void RunCmd(string command)
{
//實例一個Process類啟動一個獨立進程
System.Diagnostics.Process p = new System.Diagnostics.Process();
//Process類有一個StartInfo屬性這個是ProcessStartInfo類包括了一些屬性和方法下面我們用到了他的幾個屬性
p.StartInfo.FileName = "cmd.exe"; //設定程序名
p.StartInfo.Arguments = "/c " + command; //設定程式執行參數
p.StartInfo.UseShellExecute = false; //關閉Shell的使用
p.StartInfo.RedirectStandardInput = true; //重定向標準輸入
p.StartInfo.RedirectStandardOutput = true; //重定向標準輸出
p.StartInfo.RedirectStandardError = true; //重定向錯誤輸出
p.StartInfo.CreateNoWindow = true; //設置不顯示窗口
p.Start(); //啟動
//p.StandardInput.WriteLine(command); //也可以用這種方式輸入要執行的命令
//p.StandardInput.WriteLine("exit"); //不過要記得加上Exit要不然下一行程式執行的時候會當機
p.StandardOutput.ReadToEnd(); //從輸出流取得命令執行結果
while (!p.HasExited)
{
p.WaitForExit(1000);
}
}
}
}

120
Update/Form1.resx Normal file
View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

22
Update/Program.cs Normal file
View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Update
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

View File

@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Update")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("295218b6-0c7e-4d1b-ad85-ab0636a83323")]
[assembly: Guid("40fb5be4-89be-4717-9378-e85de86d56dd")]
// 程序集的版本信息由下列四个值组成:
//

71
Update/Properties/Resources.Designer.cs generated Normal file
View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Update.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.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()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Update.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

30
Update/Properties/Settings.Designer.cs generated Normal file
View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Update.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.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;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -1,19 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>295218b6-0c7e-4d1b-ad85-ab0636a83323</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<ProjectGuid>{40FB5BE4-89BE-4717-9378-E85DE86D56DD}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Update</RootNamespace>
<AssemblyName>Update</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
@ -23,6 +24,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
@ -31,24 +33,70 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System"/>
<Reference Include="System.Core"/>
<Reference Include="System.Xml.Linq"/>
<Reference Include="System.Data.DataSetExtensions"/>
<Reference Include="Microsoft.CSharp"/>
<Reference Include="System.Data"/>
<Reference Include="System.Net.Http"/>
<Reference Include="System.Xml"/>
<Reference Include="DevExpress.Data.v19.2, Version=19.2.7.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\Program Files (x86)\DevExpress 19.2\Components\Bin\Framework\DevExpress.Data.v19.2.dll</HintPath>
</Reference>
<Reference Include="DevExpress.Utils.v19.2, Version=19.2.7.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.XtraEditors.v19.2, Version=19.2.7.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\Program Files (x86)\DevExpress 19.2\Components\Bin\Framework\DevExpress.XtraEditors.v19.2.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UpdateLog.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<None Include="updateconfiguration.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Update.Core\Update.Core.csproj">
<Project>{4903D5F5-FF01-426D-B5BB-AADF7C4232FA}</Project>
<Name>Update.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>

50
Update/UpdateLog.cs Normal file
View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace Update
{
/// <summary>
/// 记录操作过程的信息
/// </summary>
public class Log
{
public static void Write(string msg)
{
Write(msg, true);
}
public static void Write(string msg, bool isAppend)
{
try
{
string filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update.txt");
if (!Directory.Exists(Path.GetDirectoryName(filename)))
{
Directory.CreateDirectory(Path.GetDirectoryName(filename));
}
using (FileStream stream = new FileStream(filename, isAppend ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.None))
{
StreamWriter writer = new StreamWriter(stream);
writer.WriteLine(msg);
writer.Close();
stream.Close();
}
}
catch
{
}
}
public static void Write(Exception ex)
{
string msg = DateTime.Now + System.Environment.NewLine
+ ex.Message + System.Environment.NewLine
+ ex.Source + System.Environment.NewLine
+ ex.StackTrace + System.Environment.NewLine
+ ex.TargetSite.Name;
Write(msg);
}
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<applicationUpdater applicationId="c3e35ff1-fc03-4c08-87fb-1ee8f3d38987"
manifestUri="http://121.4.95.243:8888/update.xml"
version="1.0"
title="测试软件-版本更新">
</applicationUpdater>

View File

@ -17,8 +17,8 @@ namespace WinformGeneralDeveloperFrame.Commons
public static DataTable SqlTable(string name)
{
string connstring = EncodeHelper.AES_Decrypt(ConfigurationManager.ConnectionStrings["DB"].ConnectionString);
// string connstring=ConfigurationManager.ConnectionStrings["DB"].ConnectionString;
//string connstring = EncodeHelper.AES_Decrypt(ConfigurationManager.ConnectionStrings["DB"].ConnectionString);
string connstring=ConfigurationManager.ConnectionStrings["DB"].ConnectionString;
string sql = "";
string url = "";
DataTable dt1 = new DataTable();

View File

@ -51,7 +51,7 @@
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
<connectionStrings>
<add name="DB" connectionString="SB16Jt39MD21ugTdYbOTj5/d7+MqcDuVilvBLoJ8OAEXPbuSrV6hZrXx67xblmuQ7fKaMYG+dVdcpDz7biJQmcsuIgxY2UbQm9Be5Kg6Gt/XgxyNiyyQ/Ua7WcUFxGOhUup+z1uyRwL8WU5Gb0o6R8+flGQhYRk/O1O4dns2+sU=" providerName="System.Data.SqlClient"/>
<add name="DB" connectionString="data source=.;initial catalog=winformdevfarme;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient"/>
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">

View File

@ -76,6 +76,14 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Update.Core\Update.Core.csproj">
<Project>{4903d5f5-ff01-426d-b5bb-aadf7c4232fa}</Project>
<Name>Update.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Update\Update.csproj">
<Project>{40fb5be4-89be-4717-9378-e85de86d56dd}</Project>
<Name>Update</Name>
</ProjectReference>
<ProjectReference Include="..\WinformGeneralDeveloperFrame.Commons\Commons.csproj">
<Project>{6f2b061d-6116-45a4-9649-49ae4981c496}</Project>
<Name>Commons</Name>

View File

@ -15,12 +15,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrimordialForm", "WinformGe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entity", "Entity\Entity.csproj", "{524A09B1-52EE-49C6-ACD2-CEC2AEB8D2F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Update", "Update\Update.csproj", "{295218B6-0C7E-4D1B-AD85-AB0636A83323}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeGeneration", "CodeGeneration\CodeGeneration.csproj", "{D7D32522-8FA4-4B12-ADB1-72A74F0B3964}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Business", "Business\Business.csproj", "{3A1FD334-A7FD-4815-A745-ACC07A7C367F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Update.Core", "Update.Core\Update.Core.csproj", "{4903D5F5-FF01-426D-B5BB-AADF7C4232FA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Update", "Update\Update.csproj", "{40FB5BE4-89BE-4717-9378-E85DE86D56DD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -51,10 +53,6 @@ Global
{524A09B1-52EE-49C6-ACD2-CEC2AEB8D2F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{524A09B1-52EE-49C6-ACD2-CEC2AEB8D2F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{524A09B1-52EE-49C6-ACD2-CEC2AEB8D2F6}.Release|Any CPU.Build.0 = Release|Any CPU
{295218B6-0C7E-4D1B-AD85-AB0636A83323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{295218B6-0C7E-4D1B-AD85-AB0636A83323}.Debug|Any CPU.Build.0 = Debug|Any CPU
{295218B6-0C7E-4D1B-AD85-AB0636A83323}.Release|Any CPU.ActiveCfg = Release|Any CPU
{295218B6-0C7E-4D1B-AD85-AB0636A83323}.Release|Any CPU.Build.0 = Release|Any CPU
{D7D32522-8FA4-4B12-ADB1-72A74F0B3964}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7D32522-8FA4-4B12-ADB1-72A74F0B3964}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7D32522-8FA4-4B12-ADB1-72A74F0B3964}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -63,6 +61,14 @@ Global
{3A1FD334-A7FD-4815-A745-ACC07A7C367F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A1FD334-A7FD-4815-A745-ACC07A7C367F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A1FD334-A7FD-4815-A745-ACC07A7C367F}.Release|Any CPU.Build.0 = Release|Any CPU
{4903D5F5-FF01-426D-B5BB-AADF7C4232FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4903D5F5-FF01-426D-B5BB-AADF7C4232FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4903D5F5-FF01-426D-B5BB-AADF7C4232FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4903D5F5-FF01-426D-B5BB-AADF7C4232FA}.Release|Any CPU.Build.0 = Release|Any CPU
{40FB5BE4-89BE-4717-9378-E85DE86D56DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{40FB5BE4-89BE-4717-9378-E85DE86D56DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40FB5BE4-89BE-4717-9378-E85DE86D56DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40FB5BE4-89BE-4717-9378-E85DE86D56DD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/Environment/Hierarchy/EntityFrameworkOptions/IsAlreadyNotifiedAboutEntityFramework/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -13,7 +13,8 @@ namespace WinformGeneralDeveloperFrame
public partial class DB : DbContext
{
public DB()
: base(EncodeHelper.AES_Decrypt(ConfigurationManager.ConnectionStrings["DB"].ConnectionString))
:base("DB")
//: base(EncodeHelper.AES_Decrypt(ConfigurationManager.ConnectionStrings["DB"].ConnectionString))
{
}

View File

@ -11,8 +11,8 @@ namespace MES
public partial class MESDB : DbContext
{
public MESDB()
//: base("name=DB")
: base(EncodeHelper.AES_Decrypt(ConfigurationManager.ConnectionStrings["DB"].ConnectionString))
: base("name=DB")
//: base(EncodeHelper.AES_Decrypt(ConfigurationManager.ConnectionStrings["DB"].ConnectionString))
{
}
public virtual DbSet<stockDataInfo> stockDataInfo { get; set; }

View File

@ -742,6 +742,14 @@
<None Include="Resources\102.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Update.Core\Update.Core.csproj">
<Project>{4903D5F5-FF01-426D-B5BB-AADF7C4232FA}</Project>
<Name>Update.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Update\Update.csproj">
<Project>{40FB5BE4-89BE-4717-9378-E85DE86D56DD}</Project>
<Name>Update</Name>
</ProjectReference>
<ProjectReference Include="..\WinformGeneralDeveloperFrame.Commons\Commons.csproj">
<Project>{6f2b061d-6116-45a4-9649-49ae4981c496}</Project>
<Name>Commons</Name>

View File

@ -10,11 +10,18 @@ using System.Text;
using System.Windows.Forms;
using MES.Entity;
using WinformGeneralDeveloperFrame.Commons;
using Updater.Core;
using System.Diagnostics;
using System.IO;
using DevExpress.Utils;
using DevExpress.XtraEditors;
using Update;
namespace Login
{
public partial class LoginView : DevExpress.XtraEditors.XtraForm
{
private BackgroundWorker updateWorker;
public bool bLogin = false; //判断用户是否登录
public LoginView()
{
@ -45,8 +52,32 @@ namespace Login
private void LoginView_Load(object sender, EventArgs e)
{
updateWorker = new BackgroundWorker();
updateWorker.DoWork += new DoWorkEventHandler(updateWorker_DoWork);
updateWorker.RunWorkerAsync();
}
private void updateWorker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
UpdateClass update = new UpdateClass();
bool newVersion = update.HasNewVersion;
if (newVersion)
{
//if (MessageUtil.ShowYesNoAndTips(Portal.gc.DicLag["Version"].Where(p => p.Name == Portal.gc.Language).First().Value) == DialogResult.Yes)
{
//Thread.Sleep(1500);
Process.Start(Path.Combine(Application.StartupPath, "Update.exe"), "121");
Application.Exit();
}
}
}
catch (Exception ex)
{
XtraMessageBox.Show(ex.Message);
}
}
private void User_MouseEnter(object sender, EventArgs e)
{
skinPanel2.BackColor = Color.FromArgb(69, 159, 176);