Skip to content

Commit

Permalink
- Use Handle2 to get locking information
Browse files Browse the repository at this point in the history
- Reduce amount of 3rd party dependencies
- Simplify the code
  • Loading branch information
PolarGoose committed Feb 4, 2023
1 parent 6018097 commit d025379
Show file tree
Hide file tree
Showing 67 changed files with 938 additions and 1,095 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ charset = utf-8
indent_style = space
indent_size = 4

[*.{xml,wxs}]
[*.{xml,wxs, csproj, wixproj, config, sln, svg, manifest, json}]
indent_size = 2
18 changes: 3 additions & 15 deletions .github/workflows/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ Function CheckReturnCodeOfPreviousCommand($msg) {
Function GetVersion() {
$gitCommand = Get-Command -Name git

$nearestTag = & $gitCommand describe --exact-match --tags HEAD
$tag = & $gitCommand describe --exact-match --tags HEAD
if(-Not $?) {
Info "The commit is not tagged. Use 'v0.0-dev' as a version instead"
$nearestTag = "v0.0-dev"
$tag = "v0.0-dev"
}

$commitHash = & $gitCommand rev-parse --short HEAD
CheckReturnCodeOfPreviousCommand "Failed to get git commit hash"

return "$($nearestTag.Substring(1))-$commitHash"
return "$($tag.Substring(1))-$commitHash"
}

Function GetInstallerVersion($version) {
Expand Down Expand Up @@ -86,15 +86,3 @@ CheckReturnCodeOfPreviousCommand "build failed"
RemoveFileIfExists "$publishDir/${projectName}.msi.zip"
Info "Create zip archive from msi installer"
Compress-Archive -Path "$publishDir/$projectName.msi" -DestinationPath "$publishDir/${projectName}.msi.zip"

# Skip running tests if the build script is run on Github Actions.
# There are no processes which lock files on Github Actions executors. It makes a lot of test fail.
if ($null -eq $env:GITHUB_ACTIONS) {
& "$buildDir/nuget/nunit.consolerunner/*/tools/nunit3-console.exe" `
"$publishDir/net461/Test.dll" `
--stoponerror `
--labels=Before `
--noheader `
--noresult
CheckReturnCodeOfPreviousCommand "tests failed"
}
4 changes: 2 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- run: .github/workflows/build.ps1
- uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
Expand All @@ -13,7 +13,7 @@ jobs:
with:
draft: true
files: Build/Release/*.msi.zip
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
with:
name: Build artifacts
path: Build/Release/*.msi.zip
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/Build
.vs/
/Build/
/.vs/
/.idea/
launchSettings.json
27 changes: 12 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
# ShowWhatProcessLocksFile
An utility to discover what processes lock a specific file or folder.<br>
A utility to discover what processes lock a specific file or folder.

# Screenshots
## Context menu
![Screenshot](doc/ContextMenu.png)
## The application
![Screenshot](doc/Screenshot.png)
<img src="doc/ContextMenu.png" width="70%" height="70%"/>

## Application
<img src="doc/Screenshot.png" width="70%" height="70%"/>

# System requirements
* .Net Framework 4.6.1 or higher (Windows 10 already has it)
* Windows 10 or higher (it can also work on Windows 8 if you install [.Net Framework 4.6.2](https://dotnet.microsoft.com/en-us/download/dotnet-framework/thank-you/net462-web-installer))
* The user should be allowed to run applications as an Administrator.

# How it works
The application uses [Handle by Mark Russinovich](https://docs.microsoft.com/en-us/sysinternals/downloads/handle) to get information about locking processes. The output of `handle.exe` is parsed and displayed in the GUI.<br>
The application uses [Handle2](https://github.com/PolarGoose/Handle2) to get information about locking processes.

# How to use
* Download `ShowWhatProcessLocksFile.msi.zip` from the latest [release](https://github.com/PolarGoose/ShowWhatProcessLocksFile/releases).
* Run the installer. The installer will install this programm to the `%AppData%\ShowWhatProcessLocksFile` folder and add a "Show what locks this file" Windows File Explorer context menu element.
* Use "Show what locks this file" File Explorer's context menu to select a file or folder
* To terminate selected processes, open a context menu by clicking mouse right button
* Run the installer. The installer will install this programm to the `%AppData%\ShowWhatProcessLocksFile` folder and add a `Show what locks this file` Windows File Explorer context menu element.
* Use `Show what locks this file` File Explorer's context menu to select a file or folder
* To terminate a process, select it and open a context menu by clicking right mouse button
* If you want to uninstall the program, use `Control Panel\Programs\Programs and Features`, uninstaller will remove an integration with the context menu and all files which were installed.

# How to build
* Use `Visual Studio 2019` with [Wix Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=WixToolset.WixToolsetVisualStudio2019Extension) and [Wix Toolset](https://wixtoolset.org/releases/).
* Run `.github\workflows\build.ps1` to build a release (`git.exe` should be in your PATH)

# References
* This tool is inspired by [LockHunter](https://lockhunter.com/)
* Article about API used by `Handle.exe` with code samples: [Examine Information on Windows NT System Level Primitives](https://www.codeguru.com/cpp/w-p/system/processesmodules/article.php/c2827/Examine-Information-on-Windows-NT-System-Level-Primitives.htm)
* To work with the codebase, use `Visual Studio 2022` with a plugin [HeatWave for VS2022](https://marketplace.visualstudio.com/items?itemName=FireGiant.FireGiantHeatWaveDev17).
* To build a release, run `.github\workflows\build.ps1` (`git.exe` should be in your PATH)
4 changes: 2 additions & 2 deletions ShowWhatProcessLocksFile.sln
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31129.286
# Visual Studio Version 17
VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShowWhatProcessLocksFile", "src\App\ShowWhatProcessLocksFile.csproj", "{952F82E5-8372-4435-8318-3ED0C114A57C}"
EndProject
Expand Down
Binary file modified doc/ContextMenu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/Screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 12 additions & 9 deletions src/App/App.xaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
<Application x:Class="ShowWhatProcessLocksFile.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:ShowWhatProcessLocksFile.Gui.Controls"
StartupUri="Gui/MainWindow.xaml">
<Application.Resources>
<Style x:Key="ButtonStyle" TargetType="ButtonBase">
<Style.Setters>
<Setter Property="Background" Value="White"/>
</Style.Setters>
</Style>
<Style TargetType="Button" BasedOn="{StaticResource ButtonStyle}"/>
<Style TargetType="ToggleButton" BasedOn="{StaticResource ButtonStyle}"/>
<Style TargetType="controls:IconButton" BasedOn="{StaticResource ButtonStyle}"/>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Gui/Icons.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ButtonStyle" TargetType="ButtonBase">
<Style.Setters>
<Setter Property="Background" Value="White" />
</Style.Setters>
</Style>
<Style TargetType="Button" BasedOn="{StaticResource ButtonStyle}" />
<Style TargetType="ToggleButton" BasedOn="{StaticResource ButtonStyle}" />
</ResourceDictionary>
</Application.Resources>
</Application>
7 changes: 3 additions & 4 deletions src/App/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System.Windows;

namespace ShowWhatProcessLocksFile
namespace ShowWhatProcessLocksFile;

public partial class App : Application
{
public partial class App : Application
{
}
}
8 changes: 4 additions & 4 deletions src/App/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
25 changes: 8 additions & 17 deletions src/App/Gui/Controls/ExpandToggleButton.xaml
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
<ToggleButton x:Class="ShowWhatProcessLocksFile.Gui.Controls.ExpandToggleButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ToggleButton.Style>
<Style TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Setter Property="Content">
<Setter.Value>
<svgc:SvgViewbox Source="/Gui/Icons/ExpandRight_md_16x.svg"/>
</Setter.Value>
</Setter>
<Setter Property="Content" Value="{StaticResource ExpandRight_icon}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<svgc:SvgViewbox Source="/Gui/Icons/ExpandDown_md_16x.svg"/>
</Setter.Value>
</Setter>
<Setter Property="Content" Value="{StaticResource ExpandDown_icon}" />
</Trigger>
</Style.Triggers>
</Style>
Expand Down
11 changes: 5 additions & 6 deletions src/App/Gui/Controls/ExpandToggleButton.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
using System.Windows.Controls.Primitives;

namespace ShowWhatProcessLocksFile.Gui.Controls
namespace ShowWhatProcessLocksFile.Gui.Controls;

public partial class ExpandToggleButton : ToggleButton
{
public partial class ExpandToggleButton : ToggleButton
public ExpandToggleButton()
{
public ExpandToggleButton()
{
InitializeComponent();
}
InitializeComponent();
}
}
11 changes: 0 additions & 11 deletions src/App/Gui/Controls/IconButton.xaml

This file was deleted.

23 changes: 0 additions & 23 deletions src/App/Gui/Controls/IconButton.xaml.cs

This file was deleted.

17 changes: 10 additions & 7 deletions src/App/Gui/Controls/ProcessInfoListView.xaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<UserControl x:Class="ShowWhatProcessLocksFile.Gui.Controls.ProcessInfoListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ShowWhatProcessLocksFile.Gui.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Expand All @@ -14,21 +14,24 @@
</Grid.RowDefinitions>

<StackPanel Grid.Row="0" Orientation="Horizontal">
<local:IconButton Height="21" Width="21" Margin="2" Command="{Binding ExpandAllCommand}" Icon="/Gui/Icons/ExpandAll_16x.svg" ToolTip="Expand All"/>
<local:IconButton Height="21" Width="21" Margin="2" Command="{Binding CollapseAllCommand}" Icon="/Gui/Icons/CollapseAll_16x.svg" ToolTip="Collapse All"/>
<Button Height="21" Width="21" Margin="2" Command="{Binding ExpandAllCommand}"
Content="{StaticResource ExpandAll_icon}" ToolTip="Expand All" />
<Button Height="21" Width="21" Margin="2" Command="{Binding CollapseAllCommand}"
Content="{StaticResource CollapseAll_icon}" ToolTip="Collapse All" />
</StackPanel>

<ListBox x:Name="processInfoList" Grid.Row="1" SelectionMode="Extended" ItemsSource="{Binding ProcessInfoViewModels}" ScrollViewer.CanContentScroll="False">
<ListBox x:Name="processInfoList" Grid.Row="1" SelectionMode="Extended"
ItemsSource="{Binding ProcessInfoViewModels}" ScrollViewer.CanContentScroll="False">
<ListBox.ItemTemplate>
<DataTemplate>
<local:ProcessInfoView DataContext="{Binding}"/>
<local:ProcessInfoView DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Terminate selected processes"
Command="{Binding KillSelected}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItems}"/>
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItems}" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
Expand Down
11 changes: 5 additions & 6 deletions src/App/Gui/Controls/ProcessInfoListView.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
using System.Windows.Controls;

namespace ShowWhatProcessLocksFile.Gui.Controls
namespace ShowWhatProcessLocksFile.Gui.Controls;

public partial class ProcessInfoListView : UserControl
{
public partial class ProcessInfoListView : UserControl
public ProcessInfoListView()
{
public ProcessInfoListView()
{
InitializeComponent();
}
InitializeComponent();
}
}
63 changes: 29 additions & 34 deletions src/App/Gui/Controls/ProcessInfoListViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,48 +1,43 @@
using ShowWhatProcessLocksFile.Gui.Utils;
using ShowWhatProcessLocksFile.LockFinding;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ShowWhatProcessLocksFile.Gui.Utils;
using ShowWhatProcessLocksFile.LockFinding;

namespace ShowWhatProcessLocksFile.Gui.Controls;

namespace ShowWhatProcessLocksFile.Gui.Controls
internal class ProcessInfoListViewModel : ViewModelBase
{
internal class ProcessInfoListViewModel : ViewModelBase
public IEnumerable<ProcessInfoViewModel> ProcessInfoViewModels { get; }
public RelayCommand ExpandAllCommand { get; }
public RelayCommand CollapseAllCommand { get; }
public RelayCommand<IEnumerable> KillSelected { get; }

public ProcessInfoListViewModel(IEnumerable<ProcessInfo> processesInfoViewModels,
Action<IEnumerable<ProcessInfo>> killProcessesRequested)
{
public IEnumerable<ProcessInfoViewModel> ProcessInfoViewModels { get; }
public RelayCommand ExpandAllCommand { get; }
public RelayCommand CollapseAllCommand { get; }
public RelayCommand KillAll { get; }
public RelayCommand<System.Collections.IEnumerable> KillSelected { get; }
ProcessInfoViewModels = processesInfoViewModels.Select(p => new ProcessInfoViewModel(p)).ToList();

public ProcessInfoListViewModel(IEnumerable<ProcessInfo> processesInfoViewModels, Action<IEnumerable<ProcessInfo>> killProcessesRequested)
ExpandAllCommand = new RelayCommand(() =>
{
ProcessInfoViewModels = processesInfoViewModels.Select(p => new ProcessInfoViewModel(p)).ToList();

ExpandAllCommand = new RelayCommand(() =>
{
foreach (var p in ProcessInfoViewModels)
{
p.IsExpanded = true;
}
});

CollapseAllCommand = new RelayCommand(() =>
foreach (var p in ProcessInfoViewModels)
{
foreach (var p in ProcessInfoViewModels)
{
p.IsExpanded = false;
}
});
p.IsExpanded = true;
}
});

KillAll = new RelayCommand(() =>
CollapseAllCommand = new RelayCommand(() =>
{
foreach (var p in ProcessInfoViewModels)
{
killProcessesRequested(ProcessInfoViewModels.Select(p => p.Process));
});
p.IsExpanded = false;
}
});

KillSelected = new RelayCommand<System.Collections.IEnumerable>(processes =>
{
killProcessesRequested(processes.OfType<ProcessInfoViewModel>().Select(p => p.Process));
});
}
KillSelected = new RelayCommand<IEnumerable>(processes =>
{
killProcessesRequested(processes.OfType<ProcessInfoViewModel>().Select(p => p.Process));
});
}
}
Loading

0 comments on commit d025379

Please sign in to comment.