-
-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathFileLockKiller.cs
More file actions
118 lines (99 loc) · 3.56 KB
/
FileLockKiller.cs
File metadata and controls
118 lines (99 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
static class FileLockKiller
{
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
[DllImport("rstrtmgr.dll")]
static extern int RmEndSession(uint pSessionHandle);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
static extern int RmRegisterResources(
uint pSessionHandle,
uint nFiles,
string[] rgsFileNames,
uint nApplications,
[In] RM_UNIQUE_PROCESS[] rgApplications,
uint nServices,
string[] rgsServiceNames);
[DllImport("rstrtmgr.dll")]
static extern int RmGetList(
uint dwSessionHandle,
out uint pnProcInfoNeeded,
ref uint pnProcInfo,
[In, Out] RM_PROCESS_INFO[]? rgAffectedApps,
ref uint lpdwRebootReasons);
const int errorMoreData = 234;
[StructLayout(LayoutKind.Sequential)]
struct RM_UNIQUE_PROCESS
{
public uint dwProcessId;
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct RM_PROCESS_INFO
{
public RM_UNIQUE_PROCESS Process;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string strAppName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string strServiceShortName;
public uint ApplicationType;
public uint AppStatus;
public uint TSSessionId;
[MarshalAs(UnmanagedType.Bool)]
public bool bRestartable;
}
public static bool KillLockingProcesses(string filePath)
{
var killed = false;
if (RmStartSession(out var sessionHandle, 0, Guid.NewGuid().ToString()) != 0)
{
return false;
}
try
{
var resources = new[] { filePath };
if (RmRegisterResources(sessionHandle, (uint)resources.Length, resources, 0, [], 0, []) != 0)
{
return false;
}
var procInfo = 0u;
var rebootReasons = 0u;
var result = RmGetList(sessionHandle, out var procInfoNeeded, ref procInfo, null, ref rebootReasons);
if (result != errorMoreData || procInfoNeeded == 0)
{
return false;
}
var processInfo = new RM_PROCESS_INFO[procInfoNeeded];
procInfo = procInfoNeeded;
result = RmGetList(sessionHandle, out procInfoNeeded, ref procInfo, processInfo, ref rebootReasons);
if (result != 0)
{
return false;
}
for (var i = 0; i < procInfo; i++)
{
var processId = (int)processInfo[i].Process.dwProcessId;
if (!ProcessEx.TryGet(processId, out var process))
{
continue;
}
Log.Information(
"Killing locking process '{ProcessName}' (PID: {ProcessId}) for file '{FilePath}'",
processInfo[i].strAppName,
processId,
filePath);
process.KillAndDispose();
killed = true;
}
}
catch (Exception exception)
{
ExceptionHandler.Handle($"Failed to kill locking processes for '{filePath}'.", exception);
}
finally
{
// Nothing useful to do if ending the session fails
_ = RmEndSession(sessionHandle);
}
return killed;
}
}