删除带有文件的Windows服务文件夹会引发错误
c#
我知道已经有人问过这个问题,但到目前为止我找不到解决方案。
我想要做的是卸载 Windows 服务并使用 C# 删除带有 Windows 服务的文件夹。
Windows 服务卸载
public static void Uninstall(string exeFilename)
{
var commandLineOptions = new string[1] { "/LogFile=uninstall.log" };
if (!Directory.Exists(exeFilename)) return;
var fileNames = Directory.GetFiles(exeFilename);
var serviceFile = fileNames.FirstOrDefault(f => f.EndsWith(".exe"));
var serviceFileName = Path.GetFileName(serviceFile);
var serviceName = Path.GetFileNameWithoutExtension(serviceFile);
var serviceExists = ServiceController.GetServices().Any(s => s.ServiceName == serviceName);
if (!serviceExists) return;
var installer =
new AssemblyInstaller($"{exeFilename}{serviceFileName}", commandLineOptions)
{
UseNewContext = true
};
installer.Uninstall(null);
installer.Dispose();
}
文件夹和文件删除
public static void DeleteFolder(string folderPath)
{
if(!Directory.Exists(folderPath)) return;
try
{
foreach (var folder in Directory.GetDirectories(folderPath))
{
DeleteFolder(folder);
}
foreach (var file in Directory.GetFiles(folderPath))
{
var pPath = Path.Combine(folderPath, file);
File.SetAttributes(pPath, FileAttributes.Normal);
File.Delete(file);
}
Directory.Delete(folderPath);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
我得到的错误
Access to the path 'c:servicesxx.exe' is denied.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.InternalDelete(String path, Boolean checkHost)
at System.IO.File.Delete(String path)
这个错误是随机发生的。.exe 文件不是只读的,有时文件会被删除。
有谁知道出了什么问题?
回答
停止 Windows 服务并不等同于退出进程。一个可执行文件可以容纳多个 Windows 服务(它本质上是服务的物理外壳)。
因此,您遇到的情况似乎是该服务可能停止正常,并且卸载可以继续并且文件的删除可以继续,但只能直到它到达可执行文件的点为止,而尚未执行有机会退出。
停止、退出、卸载都是异步的,需要时间完成才能进入下一步。
你要做的就是遵循这个公式
- 如果可以,请确保您的代码以提升的权限运行;如果你不能,你可能会遇到Access Denied。您还可以尝试更改目标可执行文件的所有权。
- 停止或确保服务已停止。如果有多个服务,请停止所有服务。
- 等待停止实际发生。这并不总是立竿见影的。
- 调用
Uninstall(). - 等待一段时间。检查进程是否正在运行。如果是,您将调用Process.Kill()(请参阅下面的实现)。
- 最后,您可以调用
DeleteFolder()您的实现对我来说足够的 。
退出进程
编写一个看起来像这样的方法。你可能想要调整它。
void Exit(Process p)
{
for (int i = 0; i <= 5; i++)
{
// doesn't block
if (p.HasExited) return;
// doesn't block; pass true to terminate children (if any)
p.Kill(true);
// wait 5 seconds then try again
Thread.Sleep(5000);
}
}
毕竟,你应该很高兴去。