如何从. net Windows服务启动exe以更新服务
本文关键字:服务 启动 exe 更新 Windows net | 更新日期: 2023-09-27 18:10:59
我有一个windows服务,我想自动和无声地更新。我开始使用wyBuild来实现这一点,但它有一些问题,并决定尝试构建自己的。我已经编写了一个独立的exe,可以调用它来执行更新过程:用更新检查新的zip文件,下载它,解压缩,停止windows服务,从zip中复制文件,然后重新启动服务。当我从命令行运行它时,这个exe工作得很好,并且编写起来并不困难。
然而,现在我希望服务(正在更新的同一服务)向updater exe提供更新自己。我首先尝试了Process。开始:
var proc = Process.Start(pathToUpdaterExe);
proc.WaitForExit(60000);
这称为更新程序,但是当更新程序停止服务时,进程被杀死并且更新停止。我做了一些搜索,听起来解决方案是使用单独的AppDomain。这是我现在的代码:
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence objEvidence = new System.Security.Policy.Evidence(baseEvidence);
AppDomainSetup setup = new AppDomainSetup();
var updateDomain = AppDomain.CreateDomain("updateDomain", objEvidence, setup);
updateDomain.ExecuteAssembly(updater);
AppDomain.Unload(updateDomain);
然而,现在我得到错误System.IO.IOException: "进程无法访问文件'C:'Program Files (x86)'Company'Service'Service.dll',因为它正在被另一个进程使用"当试图复制新的Service.dll
同样,此时我已经停止了服务。我已经用日志确认了这一点。我无法想象Service.dll仍然被锁定,所以我添加了代码来检查是什么锁定了它: public static IEnumerable<Process> GetProcessesLocking(string filePath)
{
var result = new List<Process>();
result.Clear();
var processes = Process.GetProcesses();
foreach (Process proc in processes)
{
try
{
if (proc.HasExited) continue;
foreach (ProcessModule module in proc.Modules)
{
if ((module.FileName.ToLower().CompareTo(filePath.ToLower()) == 0))
{
result.Add(proc);
break;
}
}
}
catch (Exception ex)
{
Log(ex.ToString());
Log("There was an error checking " + proc.ProcessName );
}
}
return result;
}
然而,这段代码表明dll上没有任何锁(结果为空并且没有记录任何表示错误的内容)。
我怀疑我遇到了一些UAC问题,这是IOException的真正原因。windows服务作为LocalSystem运行。所有这些问题都要问:我应该如何从windows服务中运行更新exe,以便它有权复制c:'Program files中的文件?
正如评论和答案所建议的,Process。Start可以起作用,但有一些细微差别。您必须启动cmd.exe并使用it来启动更新程序。我还发现我不能使用updater exe的完整路径,我需要设置UseShellExecute=false。这是我从.NET服务启动更新程序的最后工作代码:
var cmd = "/c start updater.exe";
var startInfo = new ProcessStartInfo("cmd.exe");
startInfo.Arguments = cmd;
startInfo.WorkingDirectory = AssemblyDirectory;
startInfo.UseShellExecute = false;
var proc = Process.Start(startInfo);
我就是这么做的——使用了一种更简单(有人可能会说笨拙)的方法。服务:
- 生成一个批处理命令,
- 将新的可执行文件下载到暂存位置,
- 启动一个进程:cmd.exe,该进程依次运行批处理脚本w/o等待它完成,然后
- 立即终止自身。
批处理命令:
- ping 127.0.0.1 5次,
- 将可执行文件复制到最终位置,
- 重启服务。
像时钟一样工作。ping是一个可靠的5秒延迟-让服务在复制文件之前关闭。
编辑:
只是为了完整性-我意识到批处理cmd是ping 127.0.0.1而不是128.0.0.1,所以我编辑了这个答案来反映这一点。我想两者都可以——但是128.0.0.1 ping超时,其中127.0.0.1解析为"我"。因为我只是把它用作穷人的延迟,所以无论如何它都可以达到目的。