来自 InstallShield Suite Installer 的安装进度状态消息
Installation progress status messages from InstallShield Suite Installer
我有自己的 Updater.exe 可以启动 InstallShield Suite 安装程序(嵌入了另外两个 InstallShield MSI)。我想从 Suite Installer 获取安装进度状态消息并显示在我的 Updater.exe UI 中。
安装程序是否可以poll/ping获取安装状态消息? (如暂存、安装msi1、安装msi2、配置、安装完成)。
我在我的安装程序中使用 .NET Framework 4.5+ 作为先决条件,Installshield 2016 版,用于自定义操作的 wiX 工具集。
InstallShield 2016 没有任何开箱即用的功能来在安装过程中获取状态消息。
我最终编写了自己的工具来监视使用调试日志参数生成的调试日志中的 installshield 属性 值。
InstallShield 安装程序调试日志:
syntax: Installer.exe /debuglog"logfilepath"
example: installer.exe /debuglog"c:\users\test.user\desktop\debuglog.log"
InstallShield 设置三种不同的状态类型,即; 'ISProgressSummary'、'ISInstallStatus' 和 'ISParcelStatus' 并登录调试日志。
示例 installshield 调试日志条目为:
9-23-2019[10:40:56 AM]: Engine: property 'ISProgressSummary' value now 'The program features you selected are being installed.'
9-23-2019[10:41:12 AM]: Engine: property 'ISInstallStatus' value now 'Installing package Microsoft Visual C++ 2012 Update 4 Redistributable Package (x86)'
9-23-2019[10:41:17 AM]: Engine: property 'ISParcelStatus' value now 'Computing space requirements'
下面的 C# 代码监视调试日志并调用事件处理程序。您创建一个对象 class 并发送您要监视的 'statusType'。 statusType 可以是 ISProgressSummary、ISInstallStatus、ISParcelStatus
public class LogFileMonitorLineEventArgs : EventArgs
{
public string Line { get; set; }
}
public class LogFileMonitor
{
public EventHandler<LogFileMonitorLineEventArgs> OnLine;
readonly string _path;
readonly string _delimiter;
readonly string _statusType;
Timer _timer;
long _currentSize;
bool _isCheckingLog;
protected bool StartCheckingLog()
{
lock (_timer)
{
if (_isCheckingLog)
return true;
_isCheckingLog = true;
return false;
}
}
protected void DoneCheckingLog()
{
lock (_timer)
_isCheckingLog = false;
}
public LogFileMonitor(string path, string delimiter = "\n", string statusType = "")
{
_path = path;
_delimiter = delimiter;
_statusType = statusType;
}
public void Start()
{
_currentSize = new FileInfo(_path).Length;
_timer = new Timer(1000);
_timer.Elapsed += CheckLog;
_timer.AutoReset = true;
_timer.Start();
}
private void CheckLog(object s, ElapsedEventArgs e)
{
if (!StartCheckingLog()) return;
try
{
var newSize = new FileInfo(_path).Length;
if (_currentSize == newSize)
return;
using (FileStream stream = File.Open(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader sr = new StreamReader(stream, Encoding.Unicode))
{
sr.BaseStream.Seek(_currentSize, SeekOrigin.Begin);
var newData = sr.ReadToEnd();
if (!newData.EndsWith(_delimiter))
{
if (newData.IndexOf(_delimiter, StringComparison.Ordinal) == -1)
{
newData = string.Empty;
}
else
{
var pos = newData.LastIndexOf(_delimiter, StringComparison.Ordinal) + _delimiter.Length;
newData = newData.Substring(0, pos);
}
}
string[] lines = newData.Split(new[] { _delimiter }, StringSplitOptions.RemoveEmptyEntries);
string lastInstallStatus = string.Empty;
foreach (string line in lines)
{
if (line.Contains(_statusType))
{
lastInstallStatus = line;
OnLine?.Invoke(this, new LogFileMonitorLineEventArgs { Line = lastInstallStatus });
}
}
}
_currentSize = newSize;
}
catch (Exception)
{
}
DoneCheckingLog();
}
public void Stop()
{
_timer?.Stop();
}
}
我有自己的 Updater.exe 可以启动 InstallShield Suite 安装程序(嵌入了另外两个 InstallShield MSI)。我想从 Suite Installer 获取安装进度状态消息并显示在我的 Updater.exe UI 中。
安装程序是否可以poll/ping获取安装状态消息? (如暂存、安装msi1、安装msi2、配置、安装完成)。
我在我的安装程序中使用 .NET Framework 4.5+ 作为先决条件,Installshield 2016 版,用于自定义操作的 wiX 工具集。
InstallShield 2016 没有任何开箱即用的功能来在安装过程中获取状态消息。
我最终编写了自己的工具来监视使用调试日志参数生成的调试日志中的 installshield 属性 值。
InstallShield 安装程序调试日志:
syntax: Installer.exe /debuglog"logfilepath"
example: installer.exe /debuglog"c:\users\test.user\desktop\debuglog.log"
InstallShield 设置三种不同的状态类型,即; 'ISProgressSummary'、'ISInstallStatus' 和 'ISParcelStatus' 并登录调试日志。
示例 installshield 调试日志条目为:
9-23-2019[10:40:56 AM]: Engine: property 'ISProgressSummary' value now 'The program features you selected are being installed.'
9-23-2019[10:41:12 AM]: Engine: property 'ISInstallStatus' value now 'Installing package Microsoft Visual C++ 2012 Update 4 Redistributable Package (x86)'
9-23-2019[10:41:17 AM]: Engine: property 'ISParcelStatus' value now 'Computing space requirements'
下面的 C# 代码监视调试日志并调用事件处理程序。您创建一个对象 class 并发送您要监视的 'statusType'。 statusType 可以是 ISProgressSummary、ISInstallStatus、ISParcelStatus
public class LogFileMonitorLineEventArgs : EventArgs
{
public string Line { get; set; }
}
public class LogFileMonitor
{
public EventHandler<LogFileMonitorLineEventArgs> OnLine;
readonly string _path;
readonly string _delimiter;
readonly string _statusType;
Timer _timer;
long _currentSize;
bool _isCheckingLog;
protected bool StartCheckingLog()
{
lock (_timer)
{
if (_isCheckingLog)
return true;
_isCheckingLog = true;
return false;
}
}
protected void DoneCheckingLog()
{
lock (_timer)
_isCheckingLog = false;
}
public LogFileMonitor(string path, string delimiter = "\n", string statusType = "")
{
_path = path;
_delimiter = delimiter;
_statusType = statusType;
}
public void Start()
{
_currentSize = new FileInfo(_path).Length;
_timer = new Timer(1000);
_timer.Elapsed += CheckLog;
_timer.AutoReset = true;
_timer.Start();
}
private void CheckLog(object s, ElapsedEventArgs e)
{
if (!StartCheckingLog()) return;
try
{
var newSize = new FileInfo(_path).Length;
if (_currentSize == newSize)
return;
using (FileStream stream = File.Open(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader sr = new StreamReader(stream, Encoding.Unicode))
{
sr.BaseStream.Seek(_currentSize, SeekOrigin.Begin);
var newData = sr.ReadToEnd();
if (!newData.EndsWith(_delimiter))
{
if (newData.IndexOf(_delimiter, StringComparison.Ordinal) == -1)
{
newData = string.Empty;
}
else
{
var pos = newData.LastIndexOf(_delimiter, StringComparison.Ordinal) + _delimiter.Length;
newData = newData.Substring(0, pos);
}
}
string[] lines = newData.Split(new[] { _delimiter }, StringSplitOptions.RemoveEmptyEntries);
string lastInstallStatus = string.Empty;
foreach (string line in lines)
{
if (line.Contains(_statusType))
{
lastInstallStatus = line;
OnLine?.Invoke(this, new LogFileMonitorLineEventArgs { Line = lastInstallStatus });
}
}
}
_currentSize = newSize;
}
catch (Exception)
{
}
DoneCheckingLog();
}
public void Stop()
{
_timer?.Stop();
}
}