mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-04-30 05:34:06 +02:00
126 lines
3.9 KiB
C#
126 lines
3.9 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using TweetLib.Core.Utils;
|
|
|
|
namespace TweetLib.Core.Systems.Startup{
|
|
public sealed class LockFile{
|
|
private static int CurrentProcessID{
|
|
get{
|
|
using Process me = Process.GetCurrentProcess();
|
|
return me.Id;
|
|
}
|
|
}
|
|
|
|
private readonly string path;
|
|
private FileStream? stream;
|
|
|
|
public LockFile(string path){
|
|
this.path = path;
|
|
}
|
|
|
|
private void CreateLockFileStream(){
|
|
stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
|
|
stream.Write(BitConverter.GetBytes(CurrentProcessID), 0, sizeof(int));
|
|
stream.Flush(true);
|
|
}
|
|
|
|
private bool ReleaseLockFileStream(){
|
|
if (stream != null){
|
|
stream.Dispose();
|
|
stream = null;
|
|
return true;
|
|
}
|
|
else{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public LockResult Lock(){
|
|
if (stream != null){
|
|
return LockResult.Success;
|
|
}
|
|
|
|
try{
|
|
CreateLockFileStream();
|
|
return LockResult.Success;
|
|
}catch(DirectoryNotFoundException){
|
|
try{
|
|
FileUtils.CreateDirectoryForFile(path);
|
|
CreateLockFileStream();
|
|
return LockResult.Success;
|
|
}catch(Exception e){
|
|
ReleaseLockFileStream();
|
|
return new LockResult.Fail(e);
|
|
}
|
|
}catch(IOException e){
|
|
return DetermineLockingProcessOrFail(e);
|
|
}catch(Exception e){
|
|
ReleaseLockFileStream();
|
|
return new LockResult.Fail(e);
|
|
}
|
|
}
|
|
|
|
public LockResult LockWait(int timeout, int retryDelay){
|
|
for(int elapsed = 0; elapsed < timeout; elapsed += retryDelay){
|
|
var result = Lock();
|
|
|
|
if (result is LockResult.HasProcess info){
|
|
info.Dispose();
|
|
Thread.Sleep(retryDelay);
|
|
}
|
|
else{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return Lock();
|
|
}
|
|
|
|
public bool Unlock(){
|
|
if (ReleaseLockFileStream()){
|
|
try{
|
|
File.Delete(path);
|
|
}catch(Exception e){
|
|
App.ErrorHandler.Log(e.ToString());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private LockResult DetermineLockingProcessOrFail(Exception originalException){
|
|
try{
|
|
int pid;
|
|
|
|
using(var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
|
|
byte[] bytes = new byte[sizeof(int)];
|
|
fileStream.Read(bytes, 0, bytes.Length);
|
|
pid = BitConverter.ToInt32(bytes, 0);
|
|
}
|
|
|
|
try{
|
|
var foundProcess = Process.GetProcessById(pid);
|
|
using var currentProcess = Process.GetCurrentProcess();
|
|
|
|
if (currentProcess.MainModule.FileVersionInfo.InternalName == foundProcess.MainModule.FileVersionInfo.InternalName){
|
|
return new LockResult.HasProcess(foundProcess);
|
|
}
|
|
else{
|
|
foundProcess.Close();
|
|
}
|
|
}catch{
|
|
// GetProcessById throws ArgumentException if the process is missing
|
|
// Process.MainModule can throw exceptions in some cases
|
|
}
|
|
|
|
return new LockResult.Fail(originalException);
|
|
}catch(Exception e){
|
|
return new LockResult.Fail(e);
|
|
}
|
|
}
|
|
}
|
|
}
|