mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-29 15:11:56 +00:00
aae0dd5669
The calls to native windows functions wouldn't be valid on any unix os so expand the check. The check for Windows XP is removed as that platform is not supported anymore.
211 lines
6.8 KiB
C#
Executable file
211 lines
6.8 KiB
C#
Executable file
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace CodeImp.DoomBuilder
|
|
{
|
|
internal static class FileLockChecker
|
|
{
|
|
internal class FileLockCheckResult //mxd
|
|
{
|
|
public string Error;
|
|
public List<Process> Processes = new List<Process>();
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct RM_UNIQUE_PROCESS
|
|
{
|
|
public int dwProcessId;
|
|
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
|
|
}
|
|
|
|
private const int RmRebootReasonNone = 0;
|
|
private const int CCH_RM_MAX_APP_NAME = 255;
|
|
private const int CCH_RM_MAX_SVC_NAME = 63;
|
|
|
|
private enum RM_APP_TYPE
|
|
{
|
|
RmUnknownApp = 0,
|
|
RmMainWindow = 1,
|
|
RmOtherWindow = 2,
|
|
RmService = 3,
|
|
RmExplorer = 4,
|
|
RmConsole = 5,
|
|
RmCritical = 1000
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
private 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)]
|
|
private 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)]
|
|
private static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
|
|
|
|
[DllImport("rstrtmgr.dll")]
|
|
private static extern int RmEndSession(uint pSessionHandle);
|
|
|
|
[DllImport("rstrtmgr.dll")]
|
|
private 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 FileLockCheckResult CheckFile(string path)
|
|
{
|
|
//mxd. Do it the clunky way? (non-Windows)
|
|
if(Environment.OSVersion.Platform == PlatformID.Unix)
|
|
{
|
|
bool locked = false;
|
|
|
|
try
|
|
{
|
|
using(File.Open(path, FileMode.Open)) { }
|
|
}
|
|
catch(IOException e)
|
|
{
|
|
int errorcode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
|
|
locked = (errorcode == 32 || errorcode == 33);
|
|
}
|
|
|
|
return new FileLockCheckResult { Error = (locked ? "Unable to save the map. Map file is locked by another process." : string.Empty) };
|
|
}
|
|
|
|
//mxd. Needs Vista or newer...
|
|
uint handle;
|
|
string key = Guid.NewGuid().ToString();
|
|
FileLockCheckResult result = new FileLockCheckResult(); //mxd
|
|
string errorstart = "Unable to save the map: target file is locked by another process."
|
|
+ Environment.NewLine + "Also, unable to get the name of the offending process:"
|
|
+ Environment.NewLine + Environment.NewLine;
|
|
|
|
int res = RmStartSession(out handle, 0, key);
|
|
if(res != 0)
|
|
{
|
|
RmEndSession(handle); //mxd
|
|
result.Error = errorstart + "Error " + res + ". Could not begin restart session. Unable to determine file locker."; //mxd
|
|
return result;
|
|
}
|
|
|
|
try
|
|
{
|
|
const int ERROR_MORE_DATA = 234;
|
|
uint pnProcInfoNeeded,
|
|
pnProcInfo = 0,
|
|
lpdwRebootReasons = RmRebootReasonNone;
|
|
|
|
string[] resources = new[] { path }; // Just checking on one resource.
|
|
res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);
|
|
if(res != 0)
|
|
{
|
|
result.Error = errorstart + "Error " + res + ". Could not register resource."; //mxd
|
|
return result;
|
|
}
|
|
|
|
//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)
|
|
{
|
|
result.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
|
|
{
|
|
Process process = Process.GetProcessById(processInfo[i].Process.dwProcessId);
|
|
result.Processes.Add(process);
|
|
}
|
|
// catch the error -- in case the process is no longer running
|
|
catch(ArgumentException) {}
|
|
}
|
|
|
|
//mxd
|
|
if(result.Processes.Count > 0)
|
|
{
|
|
result.Error = "Unable to save the map: target file is locked by the following process"
|
|
+ (result.Processes.Count > 1 ? "es" : "") + ":"
|
|
+ Environment.NewLine + Environment.NewLine;
|
|
|
|
foreach(Process process in result.Processes)
|
|
{
|
|
string processpath = string.Empty;
|
|
try
|
|
{
|
|
// All manner of exceptions are possible here...
|
|
processpath = process.MainModule.FileName;
|
|
}catch {}
|
|
|
|
result.Error += process.ProcessName
|
|
+ " (" + (!string.IsNullOrEmpty(processpath) ? "\"" + processpath + "\"" : "")
|
|
+ ", started at " + process.StartTime + ")"
|
|
+ Environment.NewLine;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.Error = "Error " + res + ". Could not list processes locking the resource."; //mxd
|
|
return result;
|
|
}
|
|
}
|
|
else if(res != 0)
|
|
{
|
|
result.Error = "Error " + res + ". Could not list processes locking resource. Failed to get result size."; //mxd
|
|
return result;
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
RmEndSession(handle);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|