Skip to content

Commit

Permalink
加上占用文件工具
Browse files Browse the repository at this point in the history
  • Loading branch information
lindexi committed Jul 26, 2024
1 parent 9382a88 commit 59a6cdc
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 0 deletions.
9 changes: 9 additions & 0 deletions app/Tool/占用文件工具/TakeUpFile/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Application x:Class="TakeUpFile.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TakeUpFile"
StartupUri="MainWindow.xaml">
<Application.Resources>

</Application.Resources>
</Application>
17 changes: 17 additions & 0 deletions app/Tool/占用文件工具/TakeUpFile/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace TakeUpFile
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
10 changes: 10 additions & 0 deletions app/Tool/占用文件工具/TakeUpFile/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Windows;

[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)
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)
)]
168 changes: 168 additions & 0 deletions app/Tool/占用文件工具/TakeUpFile/FileUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace TakeUpFile
{
/// <summary>
/// The file utils
/// </summary>
/// <remarks>Copy from: https://stackoverflow.com/a/20623311/6116637</remarks>
public static class FileUtil
{
// ReSharper disable InconsistentNaming
// ReSharper disable FieldCanBeMadeReadOnly.Local
// ReSharper disable StringLiteralTypo
// ReSharper disable InlineOutVariableDeclaration
// ReSharper disable MemberCanBePrivate.Local
// ReSharper disable UnusedMember.Local
// ReSharper disable RedundantAssignment
[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;
const int ERROR_MORE_DATA = 234;

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.Unicode)]
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>
public static 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) return null;

try
{
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.");
return null;
}

//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
{
return null;
}
}
else if (res != 0)
{
//throw new Exception("Could not list processes locking resource. Failed to get size of result.");
return null;
}
}
finally
{
RmEndSession(handle);
}

return processes;
}
}
}
22 changes: 22 additions & 0 deletions app/Tool/占用文件工具/TakeUpFile/MainWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Window x:Class="TakeUpFile.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TakeUpFile"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Background="Gray" AllowDrop="true" Drop="Grid_Drop">

</Grid>
<Grid Grid.Row="1" Margin="10,10,10,10">
<TextBlock x:Name="TracerTextBlock" Margin="10,10,10,10" />
<Button HorizontalAlignment="Right" Margin="10,10,10,10" Click="Button_Click">释放</Button>
</Grid>
</Grid>
</Window>
91 changes: 91 additions & 0 deletions app/Tool/占用文件工具/TakeUpFile/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TakeUpFile
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private FileStream? CurrentFileStream { set; get; }

private void Grid_Drop(object sender, DragEventArgs e)
{
Release();

var fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
if (fileList is not null)
{
var file = fileList.FirstOrDefault();
if (file != null)
{
if (File.Exists(file))
{
try
{
CurrentFileStream = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException ioException)
{
if (ioException.HResult == unchecked((int)0x80070020))
{
var processList = FileUtil.WhoIsLocking(file);
if (processList != null)
{
var message = $"文件{file}被程序占用中:";
foreach (var item in processList)
{
message += $"{item.ProcessName}({item.Id});";
}

TracerTextBlock.Text = message;
return;
}
}
}

TracerTextBlock.Text = $"锁定 {file}";
}
}
}
}

private void Release()
{
try
{
CurrentFileStream?.Dispose();
}
catch
{
// 忽略
}
}

private void Button_Click(object sender, RoutedEventArgs e)
{
Release();
}
}
}
10 changes: 10 additions & 0 deletions app/Tool/占用文件工具/TakeUpFile/TakeUpFile.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>

</Project>
25 changes: 25 additions & 0 deletions app/Tool/占用文件工具/TakeUpFile/TakeUpFile.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TakeUpFile", "TakeUpFile.csproj", "{A83FBEF0-5408-438E-9197-CB5F44940C69}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A83FBEF0-5408-438E-9197-CB5F44940C69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A83FBEF0-5408-438E-9197-CB5F44940C69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A83FBEF0-5408-438E-9197-CB5F44940C69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A83FBEF0-5408-438E-9197-CB5F44940C69}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7A219E99-A212-4562-B33A-3E461157007C}
EndGlobalSection
EndGlobal

0 comments on commit 59a6cdc

Please sign in to comment.