Skip to content

Commit 11b04a3

Browse files
authored
Merge pull request #4 from CodeDead/release/v1.0.1
Release/v1.0.1
2 parents 9d23a61 + 577a312 commit 11b04a3

File tree

8 files changed

+199
-80
lines changed

8 files changed

+199
-80
lines changed

README.md

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,30 @@
55
![GitHub](https://img.shields.io/badge/language-C%23-green)
66
![GitHub](https://img.shields.io/github/license/CodeDead/deadlock-dotnet-sdk)
77

8-
deadlock-dotnet-sdk is a simple-to-use SDK for unlocking files in C# / dotnet.
8+
deadlock-dotnet-sdk is a simple-to-use SDK for unlocking files in C# / dotnet on Windows based operating systems.
99

1010
## Usage
1111

12-
Add deadlock-dotnet-sdk to your solution tree using NuGet:
12+
Add deadlock-dotnet-sdk to your solution tree using [NuGet](https://www.nuget.org/packages/deadlock-dotnet-sdk/):
1313
```shell
1414
Install-Package deadlock-dotnet-sdk
1515
```
1616

17+
You can initialize a new `DeadLock` helper object like so:
18+
```c#
19+
DeadLock deadLock = new DeadLock();
20+
```
21+
22+
In addition, if you would like to rethrow inner exceptions, you can change the `RethrowExceptions` property when declaring a new `DeadLock` object:
23+
```c#
24+
DeadLock deadLock = new DeadLock(`true` | `false`);
25+
```
26+
27+
You can also change the property dynamically:
28+
```c#
29+
deadlock.RethrowExceptions = `true` | `false`
30+
```
31+
1732
### Finding the processes that are locking a file
1833

1934
To find all the `FileLocker` objects that are locking a file, you can make use of the `FindLockingProcesses` method:
@@ -28,6 +43,11 @@ string path = @"C:\...\file.txt";
2843
List<FileLocker> lockers = await DeadLock.FindLockingProcessesAsync(path);
2944
```
3045

46+
To find the `Process` objects that are locking one or more files, you can invoke the `FindLockingProcesses` (or `FindLockingProcessesAsync`) method with multiple `path` parameters:
47+
```c#
48+
List<FileLocker> fileLockers = FindLockingProcesses("a", "c", "c");
49+
```
50+
3151
### Unlocking a file
3252

3353
To unlock a `FileLocker`, you can execute the `Unlock` method:
@@ -37,12 +57,71 @@ DeadLock.Unlock(locker);
3757

3858
You can also run the code asynchronously by running the `UnlockAsync` method:
3959
```c#
40-
DeadLock.UnlockAsync(locker);
60+
await DeadLock.UnlockAsync(locker);
61+
```
62+
63+
To unlock more than one `FileLocker` object, you can invoke the `Unlock` (or `UnlockAsync`) method with multiple `FileLocker` parameters:
64+
```c#
65+
Unlock(fileLockerA, fileLockerB, fileLockerC);
4166
```
4267

68+
Alternatively, if you only want to unlock a file and you are not interested in using the `FileLocker` objects, you can do so by providing any of the `Unlock` or `UnlockAsync` methods with one or more `string` variables that represent the path or paths of the file(s) that should be unlocked:
69+
```c#
70+
// Unlock a single path
71+
string path = @"C:\...\file.txt";
72+
Unlock(path);
73+
74+
// Unlock multiple files
75+
Unlock(path1, path2, path3);
76+
77+
// Asynchronously unlock one or more files
78+
await UnlockAsync(path);
79+
await UnlockAsync(path1, path2, path3);
80+
```
81+
82+
### `FileLocker`
83+
84+
The `FileLocker` object contains a `List` of `System.Diagnostics.Process` objects that are locking a file.
85+
You can retrieve the `List` of `Process` objects by retrieving the respective property:
86+
```c#
87+
List<Process> processes = fileLocker.Lockers;
88+
```
89+
90+
To retrieve the path of the file that the `Process` objects are locking, you can make use of the `Path` property:
91+
```c#
92+
string path = fileLocker.Path;
93+
```
94+
95+
### Error handling
96+
97+
deadlock-dotnet-sdk has three specific `Exception` types that might occur when trying to find the `Process` objects that are locking a file.
98+
99+
* `RegisterResourceException`
100+
* `RmListException`
101+
* `StartSessionException`
102+
103+
In case you want more detailed error messages, it is recommended that you call the `Marshal.GetLastWin32Error` method as soon as one of these `Exception` types occur:
104+
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.getlastwin32error?view=net-6.0
105+
106+
#### `RegisterResourceException`
107+
108+
This error occurs when the system goes out of memory, when a specific time-out occurs or if an invalid handle is detected. You can find more information about this exception here:
109+
https://docs.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmanager-rmregisterresources#return-value
110+
111+
#### `RmListException`
112+
113+
This error occurs when the system goes out of memory, when a specific time-out occurs or if an invalid handle is detected. You can find more information about this exception here:
114+
https://docs.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmanager-rmgetlist#return-value
115+
116+
#### `StartSessionException`
117+
118+
This error occurs when the system goes out of memory, when a specific time-out occurs or if an invalid handle is detected. You can find more information about this exception here:
119+
https://docs.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmanager-rmstartsession#return-value
120+
43121
## Credits
44122

45-
Images by: [RemixIcon](https://remixicon.com/)
123+
* [RemixIcon](https://remixicon.com/)
124+
* [dotnet](https://dotnet.microsoft.com/en-us/)
46125

47126
## About
48127

deadlock-dotnet-sdk/DeadLock.cs

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,41 @@ namespace deadlock_dotnet_sdk
55
{
66
public class DeadLock
77
{
8+
#region Properties
9+
10+
/// <summary>
11+
/// Property that specifies whether inner exceptions should be rethrown or not
12+
/// </summary>
13+
public bool RethrowExceptions { get; set; }
14+
15+
#endregion
16+
17+
/// <summary>
18+
/// Default constructor
19+
/// </summary>
20+
public DeadLock()
21+
{
22+
// Default constructor
23+
}
24+
25+
/// <summary>
26+
/// Initialize a new DeadLock
27+
/// </summary>
28+
/// <param name="rethrowExceptions">True if inner exceptions should be rethrown, otherwise false</param>
29+
public DeadLock(bool rethrowExceptions)
30+
{
31+
RethrowExceptions = rethrowExceptions;
32+
}
33+
834
/// <summary>
935
/// Retrieve the FileLocker object that contains a List of Process objects that are locking a file
1036
/// </summary>
1137
/// <param name="filePath">The full path of a file</param>
1238
/// <returns>The FileLocker object that contains a List of Process objects that are locking a file</returns>
1339
public FileLocker FindLockingProcesses(string filePath)
1440
{
15-
IEnumerable<Process> lockers = NativeMethods.FindLockingProcesses(filePath);
16-
FileLocker fileLocker = new(filePath, lockers.ToList());
17-
41+
FileLocker fileLocker = new(filePath,
42+
NativeMethods.FindLockingProcesses(filePath, RethrowExceptions).ToList());
1843
return fileLocker;
1944
}
2045

@@ -45,8 +70,8 @@ public async Task<FileLocker> FindLockingProcessesAsync(string filePath)
4570

4671
await Task.Run(() =>
4772
{
48-
IEnumerable<Process> lockers = NativeMethods.FindLockingProcesses(filePath);
49-
fileLocker = new(filePath, lockers.ToList());
73+
fileLocker = new FileLocker(filePath,
74+
NativeMethods.FindLockingProcesses(filePath, RethrowExceptions).ToList());
5075
});
5176

5277
return fileLocker;
@@ -57,16 +82,16 @@ await Task.Run(() =>
5782
/// </summary>
5883
/// <param name="filePaths">The full path of a file</param>
5984
/// <returns>The List of FileLocker objects that contain the processes that are locking a file</returns>
60-
public async Task<List<FileLocker>> FindLockingProcessesAsnyc(params string[] filePaths)
85+
public async Task<List<FileLocker>> FindLockingProcessesAsync(params string[] filePaths)
6186
{
6287
List<FileLocker> fileLockers = new();
6388

6489
await Task.Run(() =>
6590
{
6691
foreach (string filePath in filePaths)
6792
{
68-
IEnumerable<Process> lockers = NativeMethods.FindLockingProcesses(filePath);
69-
fileLockers.Add(new(filePath, lockers.ToList()));
93+
fileLockers.Add(new FileLocker(filePath,
94+
NativeMethods.FindLockingProcesses(filePath, RethrowExceptions).ToList()));
7095
}
7196
});
7297

@@ -103,7 +128,7 @@ public void Unlock(params FileLocker[] fileLockers)
103128
/// Unlock a File asynchronously by killing all the processes that are holding a handle on the file
104129
/// </summary>
105130
/// <param name="fileLocker">The FileLocker that contains the List of Process objects that should be killed</param>
106-
public async void UnlockAsync(FileLocker fileLocker)
131+
public async Task UnlockAsync(FileLocker fileLocker)
107132
{
108133
await Task.Run(() =>
109134
{
@@ -120,7 +145,7 @@ await Task.Run(() =>
120145
/// Unlock one or more files asynchronously by killing all the processes that are holding a handle on the files
121146
/// </summary>
122147
/// <param name="fileLockers">The FileLocker objects that contain the List of Process objects that are locking a file</param>
123-
public async void UnlockAsync(params FileLocker[] fileLockers)
148+
public async Task UnlockAsync(params FileLocker[] fileLockers)
124149
{
125150
await Task.Run(() =>
126151
{
@@ -135,5 +160,52 @@ await Task.Run(() =>
135160
}
136161
});
137162
}
163+
164+
/// <summary>
165+
/// Unlock a file without retrieving the List of FileLocker objects
166+
/// </summary>
167+
/// <param name="filePath">The path of the file that should be unlocked</param>
168+
public void Unlock(string filePath)
169+
{
170+
FileLocker fileLocker = FindLockingProcesses(filePath);
171+
Unlock(fileLocker);
172+
}
173+
174+
/// <summary>
175+
/// Unlock a file without retrieving the List of FileLocker objects asynchronously
176+
/// </summary>
177+
/// <param name="filePath">The path of the file that should be unlocked</param>
178+
public async Task UnlockAsync(string filePath)
179+
{
180+
FileLocker locker = await FindLockingProcessesAsync(filePath);
181+
await UnlockAsync(locker);
182+
}
183+
184+
/// <summary>
185+
/// Unlock one or more files without retrieving the List of FileLocker objects
186+
/// </summary>
187+
/// <param name="filePaths">The full paths of the files that should be unlocked</param>
188+
public void Unlock(params string[] filePaths)
189+
{
190+
List<FileLocker> fileLockers = FindLockingProcesses(filePaths);
191+
192+
foreach (FileLocker fileLocker in fileLockers)
193+
{
194+
Unlock(fileLocker);
195+
}
196+
}
197+
198+
/// <summary>
199+
/// Unlock one or more files without retrieving the List of FileLocker objects asynchronously
200+
/// </summary>
201+
/// <param name="filePaths">The full paths of the files that should be unlocked</param>
202+
public async Task UnlockAsync(params string[] filePaths)
203+
{
204+
List<FileLocker> fileLockers = await FindLockingProcessesAsync(filePaths);
205+
foreach (FileLocker f in fileLockers)
206+
{
207+
await UnlockAsync(f);
208+
}
209+
}
138210
}
139211
}

deadlock-dotnet-sdk/Domain/FileLocker.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ public class FileLocker
77
#region Properties
88

99
/// <summary>
10-
/// Get the path of the file that is locked
10+
/// Get or set the path of the file that is locked
1111
/// </summary>
12-
public string Path { get; }
12+
public string Path { get; set; }
1313

1414
/// <summary>
15-
/// Get the List of Process objects that are locking the file
15+
/// Get or set the List of Process objects that are locking the file
1616
/// </summary>
17-
public List<Process> Lockers { get; }
17+
public List<Process> Lockers { get; set; }
1818

1919
#endregion
2020

0 commit comments

Comments
 (0)