1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-08-18 13:31:41 +02:00
Files
.github
Application
Browser
Configuration
Controls
Dialogs
Management
Plugins
Properties
Resources
Updates
Utils
bld
lib
TweetLib.Communication
TweetLib.Core
Application
Browser
Collections
Data
Features
Serialization
Systems
Configuration
Startup
LockManager.cs
Updates
Utils
App.cs
Lib.cs
TweetLib.Core.csproj
TweetTest.System
TweetTest.Unit
subprocess
video
.gitattributes
.gitignore
LICENSE.md
Program.cs
README.md
Reporter.cs
TweetDuck.csproj
TweetDuck.sln
TweetDuck.sln.DotSettings
Version.cs
packages.config
TweetDuck/lib/TweetLib.Core/Systems/Startup/LockManager.cs

163 lines
4.8 KiB
C#

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading;
namespace TweetLib.Core.Systems.Startup{
public sealed class LockManager{
private const int RetryDelay = 250;
public enum Result{
Success, HasProcess, Fail
}
private readonly string file;
private FileStream? lockStream;
private Process? lockingProcess;
public LockManager(string file){
this.file = file;
}
// Lock file
private bool ReleaseLockFileStream(){
if (lockStream != null){
lockStream.Dispose();
lockStream = null;
return true;
}
else{
return false;
}
}
private Result TryCreateLockFile(){
void CreateLockFileStream(){
lockStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read);
lockStream.Write(BitConverter.GetBytes(CurrentProcessID), 0, sizeof(int));
lockStream.Flush(true);
}
try{
CreateLockFileStream();
return Result.Success;
}catch(DirectoryNotFoundException){
try{
CreateLockFileStream();
return Result.Success;
}catch{
ReleaseLockFileStream();
return Result.Fail;
}
}catch(IOException){
return Result.HasProcess;
}catch{
ReleaseLockFileStream();
return Result.Fail;
}
}
// Lock management
public Result Lock(){
if (lockStream != null){
return Result.Success;
}
Result initialResult = TryCreateLockFile();
if (initialResult == Result.HasProcess){
try{
int pid;
using(FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
byte[] bytes = new byte[sizeof(int)];
fileStream.Read(bytes, 0, bytes.Length);
pid = BitConverter.ToInt32(bytes, 0);
}
try{
Process foundProcess = Process.GetProcessById(pid);
if (MatchesCurrentProcess(foundProcess)){
lockingProcess = foundProcess;
}
else{
foundProcess.Close();
}
}catch{
// GetProcessById throws ArgumentException if the process is missing
// Process.MainModule can throw exceptions in some cases
}
return lockingProcess == null ? Result.Fail : Result.HasProcess;
}catch{
return Result.Fail;
}
}
return initialResult;
}
public Result LockWait(int timeout){
for(int elapsed = 0; elapsed < timeout; elapsed += RetryDelay){
Result result = Lock();
if (result == Result.HasProcess){
Thread.Sleep(RetryDelay);
}
else{
return result;
}
}
return Lock();
}
public bool Unlock(){
if (ReleaseLockFileStream()){
try{
File.Delete(file);
}catch(Exception e){
App.ErrorHandler.Log(e.ToString());
return false;
}
}
return true;
}
// Locking process
public bool RestoreLockingProcess(){
return lockingProcess != null && App.LockHandler.RestoreProcess(lockingProcess);
}
public bool CloseLockingProcess(){
if (lockingProcess != null && App.LockHandler.CloseProcess(lockingProcess)){
lockingProcess = null;
return true;
}
return false;
}
// Utilities
private static int CurrentProcessID{
get{
using Process me = Process.GetCurrentProcess();
return me.Id;
}
}
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
private static bool MatchesCurrentProcess(Process process){
using Process current = Process.GetCurrentProcess();
return current.MainModule.FileVersionInfo.InternalName == process.MainModule.FileVersionInfo.InternalName;
}
}
}