私はプログラムの削除と、 "App A"というアプリケーションの内容を、カスタムWPF .exeアプリケーションである "installer"プログラムを使って削除しようとしています。 "App B"を呼び出します。 (「アプリケーションB」での私の質問の懸念コードが。)誰かがファイルを開いているディレクトリを削除する
GUIのセットアップ(特に重要ではない)
アプリケーションBは、ユーザーが上にアプリケーションAをコピーするには、コンピュータ名を選ぶことができるGUIを持っています。ファイルピッカーは、管理者が "App A.exe"をクリックしてローカルマシン上のソースディレクトリパスを入力するために使用します。ユーザー名とパスワードのテキストボックスもあるので、管理者は、App Aが提供されるターゲットファイルサーバーの資格情報を入力できます。コードはアクセス許可の問題を防ぐためにユーザーを偽装します。 「コピー」ボタンがルーチンを開始する。
場合に、アプリケーションA、ファイルのプロセスを強制終了し、explorer.exeのと同様に、ドメイン内のすべてのコンピュータ上で「アプリケーションA.EXE」プロセスを殺すことにより、ファイル削除に
コピールーチンが起動をやって彼らApp Aのエクスプローラフォルダを開いていました。明らかにこれは後の時間に行われるだろうが、家に帰る前に誰かがまだ物事を開いてロックしている可能性がある。そして、それは本当に私が解決しようとしている問題の基盤です。
更新されたファイルをコピーする前に、古いディレクトリ全体を削除します。ディレクトリ(およびそのサブディレクトリ)を削除するには、その中の各ファイルを削除する必要があります。 しかし、彼らはApp Aのフォルダからファイルを開いていたと言います。このコードは、ファイルを削除する前に(Eric J.の答えである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の削除失敗以下の私のコードで
、それはファイルの再帰的な削除を行っている、そしてそれは罰金ない、アップ私はディレクトリを削除しようとしていますので、それは、The process cannot access the file '\\\\SERVER\\C$\\APP_A_DIR' because it is being used by another process
を言うだろうDirectory.Delete()
、まで私はファイルを開いていましたが(たとえコードが実際に物理ファイルを削除できたとしても、インスタンスはまだ開いています)。
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
Wait ..アプリケーションはMachineXで動作し、RDPはMachineXで動作しますか?または、彼らはUNCによってリモートでアプリケーションを実行しますか?または、アプリケーションはクライアントマシン上に存在し、MachineXのコンポーネントポイントはいくつか存在しますか? – SledgeHammer