如何删除C#中另一个进程locking的文件?
我正在寻找一种方法来删除由另一个进程使用C#locking的文件。 我怀疑该方法必须能够find哪个进程locking文件(可能通过跟踪句柄,虽然我不知道如何在C#中执行此操作),然后closures该进程,然后才能使用File.Delete()
完成文件删除File.Delete()
。
杀死其他进程并不是一件健康的事情。 如果您的scheme涉及到卸载等操作,则可以使用MoveFileEx
API函数在下次重新引导时将该文件标记为删除。
如果您真的需要删除另一个进程正在使用的文件,build议在考虑任何解决scheme之前重新考虑实际问题。
典型的方法如下。 你已经说过你想在C#中这样做,所以这里…
- 如果您不知道哪个进程将文件locking,则需要检查每个进程的句柄列表,并查询每个句柄以确定是否识别出被locking的文件。 在C#中执行此操作可能需要P / Invoke或中间C ++ / CLI来调用您需要的本机API。
- 一旦你找出哪个进程已经locking了文件,你需要安全地在进程中注入一个小的本地DLL(你也可以注入一个托pipe的DLL,但是这样会变得更加混乱,因为你必须启动或附加到.NET运行时)。
- 该引导DLL然后使用CloseHandleclosures句柄等
本质上:解锁“locking”文件的方法是将DLL文件注入到违规进程的地址空间中并自行closures。 您可以使用本机代码或托pipe代码执行此操作。 无论如何,你将需要less量的本地代码或至lessP / Invoke到相同的。
有用的url:
- 将代码注入另一个进程的三种方法
- .NET代码注入
祝你好运!
如果你想以编程方式做。 我不确定…我真的会推荐它。 如果你只是在你自己的机器上进行故障排除, SysInternals Process Explorer可以帮助你
运行它,使用查找处理命令(我认为它是在查找或处理菜单),并search文件的名称。 一旦find手柄,您可以强行closures手柄。
然后您可以删除该文件等。
要小心 ,这样做可能会导致拥有这个句柄的程序出现奇怪的行为,因为你刚刚从它下面拉出了一些常规的地毯,但是当你正在debugging你自己的错误代码,或者当visual studio / windows explorer正在废话,不释放文件句柄,即使你告诉他们closures文件年龄前…叹气:-)
您可以使用此程序Handle来查找哪个进程对您的文件有locking。 这是一个命令行工具,所以我想你使用的输出…我不知道关于编程find它。
如果删除文件可以等待,则可以在下次启动时将其指定为删除文件:
-
启动
REGEDT32 (W2K)
或REGEDIT (WXP)
并导航到:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager
-
W2K和WXP
-
W2K:
编辑
添加值…
数据types:REG_MULTI_SZ
值名称:PendingFileRenameOperations
好 -
WXP:
编辑
新
多string值
input
PendingFileRenameOperations
-
-
在数据区域中,input要删除的
"\??\" + filename
。 可以inputLFN而不用embedded引号。 要删除C:\Long Directory Name\Long File Name.exe
,请input以下数据:\??\C:\Long Directory Name\Long File Name.exe
然后按确定 。
-
“目标文件名”是一个空(零)string。 它被input如下:
-
W2K:
编辑
二进制
select数据格式:hex
点击hexstring的末尾
input0000(四个零)
好 -
WXP:
用鼠标右键单击该值
select“修改二进制数据”
点击hexstring的末尾
input0000(四个零)
好
-
-
closures
REGEDT32/REGEDIT
并重启以删除文件。
(为了后代的缘故,无耻地从一些随意的论坛里偷来的)
使用Orion Edwards的build议我下载了Sysinternals 进程资源pipe理器 ,这反过来又让我发现,我有删除困难的文件实际上是不是由Excel.Applications
对象举行我认为,而是事实,我的C#代码发送邮件代码创build了一个Attachment对象,该对象将打开该文件的句柄。
一旦我看到这个,我很简单地调用了Attachment对象的dispose方法,并且释放了句柄。
Sysinternals浏览器允许我发现这与Visual Studio 2005debugging器一起使用。
我强烈推荐这个工具!
哦,我多年前雇用的一个大黑客就是Windows不会让你删除文件,但它确实可以让你移动它们。
伪sorting的代码:
mv %WINDIR%\System32\mfc42.dll %WINDIR\System32\mfc42.dll.old Install new mfc42.dll Tell user to save work and restart applications
当应用程序重新启动(注意我们不需要重新启动机器),他们加载了新的mfc42.dll
,一切都很好。 再加上PendingFileOperations
删除旧的,下一次整个系统重新启动,工作得很好。
这看起来很有希望 杀死文件句柄的一种方法….
http://www.timstall.com/2009/02/killing-file-handles-but-not-process.html
你可以使用你提供完整文件path的代码,它将返回一个locking该文件的任何东西的List<Processes>
:
using System.Runtime.InteropServices; using System.Diagnostics; static public class FileUtil { [StructLayout(LayoutKind.Sequential)] struct RM_UNIQUE_PROCESS { public int dwProcessId; public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; } const int RmRebootReasonNone = 0; const int CCH_RM_MAX_APP_NAME = 255; const int CCH_RM_MAX_SVC_NAME = 63; enum RM_APP_TYPE { RmUnknownApp = 0, RmMainWindow = 1, RmOtherWindow = 2, RmService = 3, RmExplorer = 4, RmConsole = 5, RmCritical = 1000 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] struct RM_PROCESS_INFO { public RM_UNIQUE_PROCESS Process; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] public string strAppName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] public string strServiceShortName; public RM_APP_TYPE ApplicationType; public uint AppStatus; public uint TSSessionId; [MarshalAs(UnmanagedType.Bool)] public bool bRestartable; } [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] static extern int RmRegisterResources(uint pSessionHandle, UInt32 nFiles, string[] rgsFilenames, UInt32 nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications, UInt32 nServices, string[] rgsServiceNames); [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)] static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey); [DllImport("rstrtmgr.dll")] static extern int RmEndSession(uint pSessionHandle); [DllImport("rstrtmgr.dll")] static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons); /// <summary> /// Find out what process(es) have a lock on the specified file. /// </summary> /// <param name="path">Path of the file.</param> /// <returns>Processes locking the file</returns> /// <remarks>See also: /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing) /// /// </remarks> static public List<Process> WhoIsLocking(string path) { uint handle; string key = Guid.NewGuid().ToString(); List<Process> processes = new List<Process>(); int res = RmStartSession(out handle, 0, key); if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker."); try { const int ERROR_MORE_DATA = 234; uint pnProcInfoNeeded = 0, pnProcInfo = 0, lpdwRebootReasons = RmRebootReasonNone; string[] resources = new string[] { path }; // Just checking on one resource. res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null); if (res != 0) throw new Exception("Could not register resource."); //Note: there's a race condition here -- the first call to RmGetList() returns // the total number of process. However, when we call RmGetList() again to get // the actual processes this number may have increased. res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); if (res == ERROR_MORE_DATA) { // Create an array to store the process results RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; pnProcInfo = pnProcInfoNeeded; // Get the list res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); if (res == 0) { processes = new List<Process>((int)pnProcInfo); // Enumerate all of the results and add them to the // list to be returned for (int i = 0; i < pnProcInfo; i++) { try { processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); } // catch the error -- in case the process is no longer running catch (ArgumentException) { } } } else throw new Exception("Could not list processes locking resource."); } else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result."); } finally { RmEndSession(handle); } return processes; } }
然后,迭代进程列表并closures它们并删除文件:
string[] files = Directory.GetFiles(target_dir); List<Process> lstProcs = new List<Process>(); foreach (string file in files) { lstProcs = ProcessHandler.WhoIsLocking(file); if (lstProcs.Count > 0) // 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); } else File.Delete(file); }
取决于文件是否在本地计算机上:
public static void localProcessKill(string processName) { foreach (Process p in Process.GetProcessesByName(processName)) { p.Kill(); } }
或networking电脑:
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(); } } }
参考文献:
如何找出使用.NETlocking文件的过程?
删除某人打开文件的目录