using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using Install.Core.Common;
namespace Install.Core
{
public class InstallWizard : INotifyPropertyChanged
{
public string Msg { get; private set; }
///
/// 进度 100% 满
///
public double Progress { get; private set; }
///
/// 总安装列表
///
[PropertyChanged.DoNotNotify]
public InstallPackCollection InstallPacks { get; private set; }
///
/// 需要再选择安装的软件列表
///
[PropertyChanged.DoNotNotify]
public List ToInstall { get; } = new List();
///
/// //已经安装的软件列表
///
[PropertyChanged.DoNotNotify]
public List HasInstalled { get; } = new List();
///
/// 图标列表
///
public Dictionary Icons { get; } = new Dictionary();
///
/// 有更加新的安装包
///
public bool HasNewestInstallZip { get; private set; }
///
/// 从网络检测信息中
///
public bool IsCheckingNetwork { get; private set; }
///
/// 最新的安装包版本
///
public string NewestInstallZipVersion { get; private set; }
///
/// 当前的安装包版本
///
public string CurrentInstallZipVersion { get; private set; }
public NewestInstallZipVersionInfo NewestInstallZipVersionInfo { get; private set; }
#region 下载包
public double DownloadInfo_Progress => DownloadInfo_TotalSize > 0 ? 1.0 * DownloadInfo_CurrSize / DownloadInfo_TotalSize : 0;
public long DownloadInfo_TotalSize { get; private set; }
public long DownloadInfo_CurrSize { get; private set; }
public string DownloadInfo_TotalSizeStr => fileSize2Str(DownloadInfo_TotalSize);
public string DownloadInfo_CurrSizeStr => fileSize2Str(DownloadInfo_CurrSize);
public string DownloadInfo_SpeedStr { get; private set; }
public string DownloadInfo_ElapsedTimeStr { get; private set; }
public string DownloadInfo_RemainingTimeStr { get; private set; }
public string DownloadInfo_ErrMsg { get; private set; }
#endregion
public event PropertyChangedEventHandler PropertyChanged;
CancellationTokenSource cancellation;
List updateScripts = new List();
public InstallWizard()
{
}
void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public bool Init()
{
if(!LoadInstallPacks())
return false;
UpdateHasInstalled();
UpdateToInstall();
UpdateIcons();
DownloadNewestInstallZipInfo();
return true;
}
///
/// 下载最新的安装包信息
///
void DownloadNewestInstallZipInfo()
{
IsCheckingNetwork = true;
//新建线程
Task.Factory.StartNew(() =>
{
var bytes = HttpExt.HttpDownload(InstallPacks.NewestInstallZipVersionInfoPath);
if (bytes == null)
return;
//bytes 转 string
string json = System.Text.Encoding.UTF8.GetString(bytes);
NewestInstallZipVersionInfo = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
NewestInstallZipVersion = NewestInstallZipVersionInfo.InstallZipVersion;
int ret = VerExt.VersionCompare(InstallPacks.InstallZipVersion, NewestInstallZipVersionInfo.InstallZipVersion);
IsCheckingNetwork = false;
HasNewestInstallZip = (ret < 0);
});
}
string fileSize2Str(long fileSizeByte)
{
double fileSize = fileSizeByte;
int i = 0;
while (fileSize > 1024)
{
i++;
fileSize /= 1024;
if (i >= 2)
break;
}
switch (i) {
case 0:
return $"{fileSize:F0}B";
case 1:
return $"{fileSize:F3}KB";
default://case 2:
return $"{fileSize:F3}MB";
}
}
string fileSpeed2Str(long fileSpeedBytePerSec)
{
double fileSpeed = fileSpeedBytePerSec;
int i = 0;
while (fileSpeed > 1024)
{
i++;
fileSpeed /= 1024;
if (i >= 2)
break;
}
switch (i)
{
case 0:
return $"{ fileSpeed:F0}B/s";
case 1:
return $"{ fileSpeed:F1}KB/s";
default://case 2:
return $"{ fileSpeed:F1}MB/s";
}
}
string sec2Str(int sec)
{
if (sec > 60)
return $"{(int)(sec / 60)}分 {sec % 60}秒";
else
return $"{sec % 60}秒";
}
public string NewestInstallZipPath { get; private set; }
///
/// 下载最新的安装包
///
public async Task DownloadNewestInstallZip()
{
//新建线程
var ret = await Task.Factory.StartNew(() =>
{
string path;
if (string.IsNullOrEmpty(InstallPacks.DefaultNewestInstallZipPath))
{
//下载到当前 exe 的上级目录
path = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
path = Path.GetDirectoryName(path);
path = Path.GetDirectoryName(path);
}
else
{
path = InstallPacks.DefaultNewestInstallZipPath;
}
path = Path.Combine(path, NewestInstallZipVersionInfo.InstallZipName);
NewestInstallZipPath = path;
try
{
HttpExt.BreakpointDownload(
NewestInstallZipVersionInfo.InstallZipUrl,
NewestInstallZipPath+".7z",
false,
(totalSize) => DownloadInfo_TotalSize = totalSize,
(currSize) => DownloadInfo_CurrSize = currSize,
(speed) => DownloadInfo_SpeedStr = fileSpeed2Str(speed),
(sec) => DownloadInfo_ElapsedTimeStr = sec2Str(sec),
(sec) => DownloadInfo_RemainingTimeStr = sec2Str(sec));
DownloadInfo_ErrMsg = null;
return true;
}
catch (Exception e)
{
DownloadInfo_ErrMsg = e.Message;
return false;
}
});
return ret;
}
///
/// 加载安装包
///
bool LoadInstallPacks()
{
string installpack_path = "install.json";
InstallPackCollection installPackCollection;
try
{
Msg = $"加载 {installpack_path}";
string json = File.ReadAllText(installpack_path);
installPackCollection = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
}
catch
{
Msg = $"加载 {installpack_path} 失败";
return false;
}
string rootpath = Path.GetDirectoryName(installpack_path);
List invalids = new List();
//读取exe 版本
foreach (var installPack in installPackCollection.Items)
{
string path="";
if (!string.IsNullOrEmpty(rootpath))
path = $@"{rootpath}\";
path+=$@"{installPack.PackPath}\{installPack.Exe}";
if (!File.Exists(path))//配置文件写了,但在安装包路径找不到
{
invalids.Add(installPack);
continue;
}
FileVersionInfo fileVerInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(path);
//版本号显示为“主版本号.次版本号.内部版本号.专用部件号”。
string version = String.Format("{0}.{1}.{2}.{3}", fileVerInfo.FileMajorPart, fileVerInfo.FileMinorPart, fileVerInfo.FileBuildPart, fileVerInfo.FilePrivatePart);
installPack.Version = version;
}
//删除不存在的安装包信息
foreach (var installPack in invalids)
installPackCollection.Items.Remove(installPack);
if (installPackCollection.Items.Count == 0)
{
Msg = $"加载 {installpack_path} 失败!! 没有任何安装包信息";
return false;
}
InstallPacks = installPackCollection;
NotifyPropertyChanged(nameof(InstallPacks));
CurrentInstallZipVersion = InstallPacks.InstallZipVersion;
return true;
}
///
/// 更新还没安装的程序列表
///
void UpdateToInstall()
{
ToInstall.Clear();
if (HasInstalled.Count == 0)
{
ToInstall.AddRange(InstallPacks.Items);
NotifyPropertyChanged(nameof(ToInstall));
return;
}
var items = from item in InstallPacks.Items
where !HasInstalled.Any(installinfo => installinfo.ProcessName == item.ProcessName)
select item;
ToInstall.AddRange(items);
NotifyPropertyChanged(nameof(ToInstall));
}
///
/// 更新已经安装的软件
///
void UpdateHasInstalled()
{
HasInstalled.Clear();
var installInfos = InstallInfoHelper.GetInstallInfos();
if (installInfos.Count() > 0)
{
HasInstalled.AddRange(installInfos);
}
//之前不是安装的,是直接复制到D盘运行的
installInfos = InstallInfoHelper.GetInstallInfosFromPath(InstallPacks);
if (installInfos.Count() > 0)
{
//一样的不复制进去
foreach (var installInfo in installInfos)
{
if (HasInstalled.Exists(ii => ii.InstallPath == installInfo.InstallPath))
continue;
HasInstalled.Add(installInfo);
}
}
//安装包有的,更新 最新版本号
foreach (var installInfo in HasInstalled)
{
var item = InstallPacks.Items.Find(_item => installInfo.ProcessName == _item.ProcessName);
if (item != null) {
installInfo.NewestVersion = item.Version;
if (installInfo.NewestVersion != installInfo.Version) {
installInfo.NeedToUpdate = true;
}
}
}
NotifyPropertyChanged(nameof(HasInstalled));
}
///
/// 更新在 安装包中的 图标列表
///
void UpdateIcons()
{
Icons.Clear();
foreach (var installPack in InstallPacks.Items)
{
string exePath = $@"{installPack.PackPath }\{installPack.Exe }";
var bitmapSource = IconExt.GetIcon(exePath);
if (bitmapSource != null)
{
Icons.Add(installPack.ProcessName, bitmapSource);
}
}
}
InstallInfo Map(InstallPack installPack, string installBasePath)
{
string installPath = $@"{installBasePath}\{installPack.ProcessName}";
return new InstallInfo()
{
InstallPath = installPath,
Exe = installPack.Exe,
Name = installPack.Name,
IsAutoRun = installPack.IsAutoRun,
Version = installPack.Version
};
}
double updateProgress(double subProgress, int subStep,int stepCnt)
{
return subProgress * 1.0 / stepCnt + subStep * 1.0 / stepCnt;
}
string progressMsg()
{
return $"{Progress * 100:F0}% :";
}
bool kill(string processName, out bool isRunning)
{
Process[] processes = Process.GetProcessesByName(processName);
if (processes.Count() > 0)
{
Msg = $"{progressMsg()} 关闭正在运行的 {processName}";
isRunning = true;
foreach (var p in processes)
p.Kill();
bool isDoubleCheckClose = true;
int checkCnt = 0;
while (isDoubleCheckClose)//检查是否关闭了
{
checkCnt++;
if (checkCnt > 3)
{
// 检查次数太多,异常
Msg = $"{progressMsg()} 异常!!!!多次关闭 {processName} 失败";
return false;
}
Task.Delay(3000).Wait();
//检查关闭了没?
processes = Process.GetProcessesByName(processName);
if (processes.Count() == 0)
{
//终于关闭了
isDoubleCheckClose = false;
}
}
}
else
{
isRunning = false;
}
return true;
}
///
/// 安装程序
///
///
///
///
public async Task Install(string installBasePath, IEnumerable installPacks)
{
cancellation = new CancellationTokenSource();
return await Task.Factory.StartNew(() =>
{
Progress = 0;
int stepCnt = installPacks.Count();
int subStep = 0;
foreach (InstallPack installPack in installPacks)
{
if (cancellation.IsCancellationRequested)
return false;
Progress = updateProgress(0, subStep, stepCnt);
Msg = $"{progressMsg()} 安装 {installPack.Name}";
//检查
//根据 安装信息, 先关闭正在运行的 安装信息.exe,
if (!kill(installPack.ProcessName, out bool isRunning))
{
return false;
}
string installPath = $@"{installBasePath}\{installPack.ProcessName}";
if (Directory.Exists(installPath))
{
Progress = updateProgress(0.1, subStep, stepCnt);
Msg = $"{progressMsg()} 删除 {installPath}";
Directory.Delete(installPath, true);
}
//复制到目标目录
Progress = updateProgress(0.2, subStep, stepCnt);
Msg = $"{progressMsg()} 复制到 {installPath}";
string srcPath = installPack.PackPath;
CopyExt.Copy(srcPath, installPath);
//创建快捷方式
Progress = updateProgress(0.6, subStep, stepCnt);
Msg = $"{progressMsg()} 创建快捷方式 {installPack.Name}";
string exePath = $@"{installPath}\{installPack.Exe}";
ShortcutCreator.CreateShortcut(installPath, installPack.Name, exePath);
//创建桌面快捷方式
Progress = updateProgress(0.7, subStep, stepCnt);
Msg = $"{progressMsg()} 创建桌面快捷方式 {installPack.Name}";
ShortcutCreator.CreateShortcutOnDesktop(installPack.Name, exePath);
//把安装信息写入到注册表
Progress = updateProgress(0.8, subStep, stepCnt);
Msg = $"{progressMsg()} 把安装信息写入到注册表";
var installinfo = Map(installPack, installBasePath);
InstallInfoHelper.SetInstallInfo(Map(installPack, installBasePath));
//设置开机启动
if (installinfo.IsAutoRun)
InstallInfoHelper.SetAutoRun(installinfo);
else
InstallInfoHelper.RemoveAutoRun(installinfo);
subStep++;
}
//最后, 把
Progress = 1;
Msg = $"{progressMsg()} 安装完成";
return true;
}, cancellation.Token);
}
///
/// 升级程序
///
///
public async Task Update(IEnumerable installInfos)
{
cancellation = new CancellationTokenSource();
return await Task.Factory.StartNew(() =>
{
Progress = 0;
int stepCnt = installInfos.Count() + 1;
int subStep = 0;
Progress = updateProgress(0, subStep, stepCnt);
//先把全部软件停止了,再复制
foreach (var installInfo in installInfos)
{
//检查
//根据 安装信息, 先关闭正在运行的 安装信息.exe,
if (!kill(installInfo.ProcessName, out bool isRunning))
{
Msg = $"{progressMsg()} 无法关闭 {installInfo.Name}";
return false;
}
}
foreach (var installInfo in installInfos)
{
if (cancellation.IsCancellationRequested)
return false;
Progress = updateProgress(0, subStep, stepCnt);
Msg = $"{progressMsg()} 安装 {installInfo.Name}";
var installPack = InstallPacks.Items.Find(item => item.ProcessName == installInfo.ProcessName);
if (installPack == null)
{
Msg = $"{progressMsg()} 找不到 {installInfo.ProcessName} 安装包资料";
return false;
}
string installPath = installInfo.InstallPath;
string srcPath = installPack.PackPath;
Progress = updateProgress(0.2, subStep, stepCnt);
if (!string.IsNullOrEmpty(installPack.UpdateScript))
{
if (!File.Exists(installPack.UpdateScript))
{
Msg = $"{progressMsg()} {installPack.UpdateScript}升级脚本不存在";
return false;
}
if (string.IsNullOrEmpty(installPack.ScriptTypeFullName))
{
Msg = $"{progressMsg()} {installPack.UpdateScript} 没有正确的 脚本类全名";
return false;
}
IUpdateScript updateScript;
var _usi = updateScripts.Find(usi => usi.Dll == installPack.UpdateScript && usi.TypeFullName == installPack.ScriptTypeFullName);
if (_usi == null)
{
string dll = installPack.UpdateScript;
Assembly assembly = Assembly.LoadFrom(dll);
var scriptType = assembly.GetType(installPack.ScriptTypeFullName);
updateScript = (IUpdateScript)System.Activator.CreateInstance(scriptType);
updateScripts.Add(new UpdateScriptInfo()
{
Dll = dll,
TypeFullName = installPack.ScriptTypeFullName,
updateScript = updateScript
});
}
else {
updateScript = _usi.updateScript;
}
bool ret = updateScript.Update(installPack, installInfo.Version, installInfo.InstallPath, (msg) =>
{
Msg = $"{progressMsg()} " + msg;
});
if (ret == false)
return false;
}
else
{
Msg = $"{progressMsg()} 删除 {installPath} 内的全部 *.exe / *.dll / x64文件夹 /x86文件夹";
DirectoryInfo directoryInfo = new DirectoryInfo(installPath);
if (directoryInfo.Exists)
{
var fileinfos = directoryInfo.GetFiles("*.exe");
foreach (var fileinfo in fileinfos)
File.Delete(fileinfo.FullName);
fileinfos = directoryInfo.GetFiles("*.dll");
foreach (var fileinfo in fileinfos)
File.Delete(fileinfo.FullName);
string path = $@"{installPath}\x64";
if (Directory.Exists(path))
Directory.Delete(path, true);
path = $@"{installPath}\x86";
if (Directory.Exists(path))
Directory.Delete(path, true);
}
//复制到目标目录
//找出安装包
Progress = updateProgress(0.3, subStep, stepCnt);
Msg = $"{progressMsg()} 复制到 {installPath} 内的全部 *.exe 与 *.dll";
if (!CopyExt.Copy(srcPath, installPath, new string[] { ".exe", ".dll" }))
{
Msg = CopyExt.Error.ToString();
Msg = "文件写入失败, 请先关闭正在执行的程序,再重试。";
return false;
}
//---------------------------------------------------------------------------------
if (Directory.Exists($@"{srcPath}\x64"))
{
Msg = $@"复制到 {installPath}\x64";
if (!CopyExt.Copy($@"{srcPath}\x64", $@"{installPath}\x64"))
{
Msg = CopyExt.Error.ToString();
Msg = "文件写入失败, 请先关闭正在执行的程序,再重试。";
return false;
}
}
//---------------------------------------------------------------------------------
if (Directory.Exists($@"{srcPath}\x86"))
{
Msg = $@"复制到 {installPath}\x86";
if (!CopyExt.Copy($@"{srcPath}\x86", $@"{installPath}\x86"))
{
Msg = CopyExt.Error.ToString();
Msg = "文件写入失败, 请先关闭正在执行的程序,再重试。";
return false;
}
}
//复制其它文件
if (installPack.Others != null && installPack.Others.Count() > 0)
{
Progress = updateProgress(0.5, subStep, stepCnt);
Msg = $"{progressMsg()} 复制其它文件到 {installPath}";
foreach (var other in installPack.Others)
{
if (!CopyExt.CopyFileOrDirectory($@"{srcPath}\{other}", $@"{installPath}\{other}"))
{
Msg = CopyExt.Error.ToString();
Msg = "文件写入失败, 请先关闭正在执行的程序,再重试。";
return false;
}
}
}
}
//创建快捷方式
Progress = updateProgress(0.6, subStep, stepCnt);
Msg = $"{progressMsg()} 创建快捷方式 {installInfo.Name}";
string exePath = $@"{installPath}\{installInfo.Exe}";
ShortcutCreator.CreateShortcut(installPath, installInfo.Name, exePath);
//创建桌面快捷方式
Progress = updateProgress(0.7, subStep, stepCnt);
Msg = $"{progressMsg()} 创建桌面快捷方式 {installInfo.Name}";
ShortcutCreator.CreateShortcutOnDesktop(installInfo.Name, exePath);
//把安装信息写入到注册表
Progress = updateProgress(0.8, subStep, stepCnt);
Msg = $"{progressMsg()} 把安装信息写入到注册表";
InstallInfoHelper.SetInstallInfo(installInfo);
//设置开机启动
if (installInfo.IsAutoRun)
InstallInfoHelper.SetAutoRun(installInfo);
else
InstallInfoHelper.RemoveAutoRun(installInfo);
subStep++;
}
Progress = 1;
Msg = $"{progressMsg()} 完成";
return true;
}, cancellation.Token);
}
///
/// 设置开机启动项 & 启动项
///
///
///
public async Task SetAutoRun(IEnumerable installInfos)
{
cancellation = new CancellationTokenSource();
return await Task.Factory.StartNew(() =>
{
Progress = 0;
int stepCnt = installInfos.Count();
int subStep = 0;
foreach (InstallInfo installInfo in installInfos)
{
if (cancellation.IsCancellationRequested)
return false;
Progress = updateProgress(0, subStep, stepCnt);
//创建桌面快捷方式
Msg = $"{progressMsg()} 创建桌面快捷方式 {installInfo.Name}";
ShortcutCreator.CreateShortcutOnDesktop(installInfo.Name, installInfo.ExePath);
Msg = $"{progressMsg()} 设置 {installInfo.Name} 开机启动项";
//设置开机启动
if (installInfo.IsAutoRun)
InstallInfoHelper.SetAutoRun(installInfo);
else
InstallInfoHelper.RemoveAutoRun(installInfo);
subStep++;
}
Progress = 1;
Msg = $"{progressMsg()} 完成";
return true;
}, cancellation.Token);
}
///
/// 删除软件
///
///
///
public async Task Remove(IEnumerable installInfos)
{
cancellation = new CancellationTokenSource();
return await Task.Factory.StartNew(() =>
{
Progress = 0;
int stepCnt = installInfos.Count();
int subStep = 0;
foreach (InstallInfo installInfo in installInfos)
{
if (cancellation.IsCancellationRequested)
return false;
//检查
//根据 安装信息, 先关闭正在运行的 安装信息.exe,
Progress = updateProgress(0, subStep, stepCnt);
if (!kill(installInfo.ProcessName, out bool isRunning))
{
return false;
}
Progress = updateProgress(0.1, subStep, stepCnt);
Msg = $"{progressMsg()} 删除 {installInfo.Name} 硬盘数据";
Directory.Delete(installInfo.InstallPath, true);
Msg = $"{progressMsg()} 删除 {installInfo.Name} 注册表信息";
InstallInfoHelper.RemoveInstallInfo(installInfo);
InstallInfoHelper.RemoveAutoRun(installInfo);
Msg = $"{progressMsg()} 删除 {installInfo.Name} 桌面快捷方式";
System.IO.File.Delete(
System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), installInfo.Name + ".lnk"));
subStep++;
}
Progress = 1;
Msg = $"{progressMsg()} 完成";
return true;
}, cancellation.Token);
}
///
/// 中断操作
///
public void Abort()
{
if (cancellation != null && !cancellation.IsCancellationRequested)
cancellation.Cancel();
}
}
public class UpdateScriptInfo
{
public string Dll;
public string TypeFullName;
public IUpdateScript updateScript;
}
}