Я пытаюсь программно удалить и заменить содержимое приложения «Приложение А» с помощью программы «установщика», которая представляет собой просто пользовательское приложение WPF .exe, Вызовите «Приложение B». (Мой вопрос касается кода в "App B".)Удалить каталог, в котором кто-то открыл файл
GUI Setup (не особо важно)
App B имеет графический интерфейс, в котором пользователь может выбрать имя компьютера, чтобы скопировать App A на. Файл-подборщик используется администратором, чтобы заполнить путь к исходному каталогу на локальном компьютере, нажав «Приложение A.exe». Существуют также текстовые поля для имени пользователя и пароля, поэтому администратор может вводить свои учетные данные для целевого файлового сервера, на котором будет подаваться приложение A, - код олицетворяет пользователя этими полномочиями для предотвращения проблем с правами доступа. Кнопка «Копировать» запускает процедуру.
Killing App A, файловые процессы, и делая удаление файла
копирования рутинных начинается, убивая процесс «App A.exe» на всех компьютерах в домене, а также explorer.exe, в случае, если они была открыта папка приложения A. Очевидно, это будет сделано через часы, но кто-то все еще может оставить вещи открытыми и заблокировать их машину, прежде чем отправиться домой. И это действительно основа проблемы, которую я ищу, чтобы решить.
Перед копированием по обновленным файлам мы хотим удалить весь старый каталог. Чтобы удалить каталог (и его подкаталоги), каждый файл внутри них должен быть удален. Но скажите, что у них был файл, открытый из папки App A. Код находит любой процесс блокировки в любом файле до его удаления (используя код из ответа Эрика Дж. На How do I find out which process is locking a file using .NET?), он убивает этот процесс на любом компьютере, на котором он запущен. Если местное, он просто использует:
public static void localProcessKill(string processName)
{
foreach (Process p in Process.GetProcessesByName(processName))
{
p.Kill();
}
}
Если удаленный, он использует WMI:
public static void remoteProcessKill(string computerName, string fullUserName, string pword, string processName)
{
var connectoptions = new ConnectionOptions();
connectoptions.Username = fullUserName; // @"YourDomainName\UserName";
connectoptions.Password = pword;
ManagementScope scope = new ManagementScope(@"\\" + computerName + @"\root\cimv2", connectoptions);
// WMI query
var query = new SelectQuery("select * from Win32_process where name = '" + processName + "'");
using (var searcher = new ManagementObjectSearcher(scope, query))
{
foreach (ManagementObject process in searcher.Get())
{
process.InvokeMethod("Terminate", null);
process.Dispose();
}
}
}
Затем можно удалить файл. Все хорошо.
Удаление каталога Отказ
В моем коде ниже, он делает рекурсивное удаление файлов, и делает это хорошо, до не до Directory.Delete()
, где он будет говорить The process cannot access the file '\\\\SERVER\\C$\\APP_A_DIR' because it is being used by another process
, потому что я пытаюсь удалить каталог в то время как у меня был файл, все еще открытый от него (хотя код действительно мог удалить физический файл - экземпляр все еще открыт).
public void DeleteDirectory(string target_dir)
{
string[] files = Directory.GetFiles(target_dir);
string[] dirs = Directory.GetDirectories(target_dir);
List<Process> lstProcs = new List<Process>();
foreach (string file in files)
{
File.SetAttributes(file, FileAttributes.Normal);
lstProcs = ProcessHandler.WhoIsLocking(file);
if (lstProcs.Count == 0)
File.Delete(file);
else // deal with the file lock
{
foreach (Process p in lstProcs)
{
if (p.MachineName == ".")
ProcessHandler.localProcessKill(p.ProcessName);
else
ProcessHandler.remoteProcessKill(p.MachineName, txtUserName.Text, txtPassword.Password, p.ProcessName);
}
File.Delete(file);
}
}
foreach (string dir in dirs)
{
DeleteDirectory(dir);
}
//ProcessStartInfo psi = new ProcessStartInfo();
//psi.Arguments = "/C choice /C Y /N /D Y /T 1 & Del " + target_dir;
//psi.WindowStyle = ProcessWindowStyle.Hidden;
//psi.CreateNoWindow = true;
//psi.FileName = "cmd.exe";
//Process.Start(psi);
//ProcessStartInfo psi = new ProcessStartInfo();
//psi.Arguments = "/C RMDIR /S /Q " + target_dir;
//psi.WindowStyle = ProcessWindowStyle.Hidden;
//psi.CreateNoWindow = true;
//psi.FileName = "cmd.exe";
//Process.Start(psi);
// This is where the failure occurs
//FileSystem.DeleteDirectory(target_dir, DeleteDirectoryOption.DeleteAllContents);
Directory.Delete(target_dir, false);
}
Я оставил все, что я пробовал, прокомментировал в коде выше. Хотя я могу убивать процессы, прикрепленные к файлам, и удалять их, есть способ убить процессы, связанные с папками, чтобы их удалить?
Все, что я видел, пытается решить эту проблему с помощью задержки с задержкой. Здесь это не сработает. Мне нужно убить файл, который был открыт, что я и делаю, но также обеспечить, чтобы дескриптор был освобожден из папки, чтобы его также можно было удалить в конце. Есть ли способ сделать это?
Другого вариантом я считал, что не будет работать: Я думал, что я мог бы просто заморозить «установку» процесс (копирования), отмечая, что сетевую папку для удаления в реестре и запланировать программную перезагрузку файлового сервера, затем снова запустите.How to delete Thumbs.db (it is being used by another process) дает этот код с помощью которого можно это сделать:
[DllImport("kernel32.dll")]
public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags);
public const int MOVEFILE_DELAY_UNTIL_REBOOT = 0x4;
//Usage:
MoveFileEx(fileName, null, MOVEFILE_DELAY_UNTIL_REBOOT);
Но есть в документации, если MOVEFILE_DELAY_UNTIL_REBOOT
используется, «файл не может существовать на удаленном общем, поскольку отсроченные операции выполняются до того, как сеть доступна. " И это предполагало, что это могло позволить путь к папке вместо имени файла. (Ссылка: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx).
Вы могли бы выход из системы зарегистрированных пользователей. Вы уже являетесь добрым «грубым» :), убивая explorer.exe, поэтому регистрация пользователя отключит все ваши проблемы. Это лучше, чем перезагрузка с тех пор, как вы рискуете, что сервер не вернется по какой-либо причине. – SledgeHammer
Да, к сожалению, у нас есть десятки тысяч пользователей в домене, и только небольшое подмножество будет пользователем этого приложения. Я думаю, что могу безопасно убить explorer.exe (так как он перезапустится, и люди могут легко открывать папки) ...даже несмотря на то, что наша политика заключается в том, что каждый пользователь должен выйти из системы, когда они уйдут, и мы фактически перезагружаем компьютеры при установке обновлений, я не уверен, что отладка в домене - это тот подход, который нам нужен, но может оказаться целесообразным перейти на наш пользовательский стол в нашей базе данных, чтобы найти их. Можем ли мы сделать такой избирательный подход? Как вы привязываете пользователей к входным компьютерам? – vapcguy
Подождите .. приложение работает на MachineX и пользователи RDP в MachineX? Или они запускают приложение удаленно с помощью UNC? Или приложение работает на клиентских компьютерах и некоторые компоненты указывают на MachineX? – SledgeHammer