1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-05-06 14:34:05 +02:00

Add a locking mechanism to avoid multiple simultaneous processes

This commit is contained in:
chylex 2016-04-12 13:55:56 +02:00
parent f5f0d0aeed
commit 9d840fec7c
3 changed files with 126 additions and 2 deletions

View File

@ -0,0 +1,108 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace TweetDick.Configuration{
class LockManager{
private readonly string file;
private FileStream lockStream;
private Process lockingProcess;
public LockManager(string file){
this.file = file;
}
private bool CreateLockFile(){
if (lockStream != null){
throw new InvalidOperationException("Lock file already exists.");
}
try{
lockStream = new FileStream(file,FileMode.Create,FileAccess.Write,FileShare.Read);
byte[] id = BitConverter.GetBytes(Process.GetCurrentProcess().Id);
lockStream.Write(id,0,id.Length);
lockStream.Flush();
if (lockingProcess != null){
lockingProcess.Close();
lockingProcess = null;
}
return true;
}catch(Exception){
if (lockStream != null){
lockStream.Close();
lockStream.Dispose();
}
return false;
}
}
public bool Lock(){
if (lockStream != null)return true;
try{
byte[] bytes = new byte[4];
using(FileStream fileStream = new FileStream(file,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)){
fileStream.Read(bytes,0,4);
}
int pid = BitConverter.ToInt32(bytes,0);
try{
lockingProcess = Process.GetProcessById(pid);
}catch(ArgumentException){}
return lockingProcess == null && CreateLockFile();
}catch(DirectoryNotFoundException){
string dir = Path.GetDirectoryName(file);
if (dir != null){
Directory.CreateDirectory(dir);
return CreateLockFile();
}
}catch(FileNotFoundException){
return CreateLockFile();
}catch(Exception e){
return false;
}
return false;
}
public void Unlock(){
if (lockStream != null){
lockStream.Close();
lockStream.Dispose();
File.Delete(file);
lockStream = null;
}
}
public bool CloseLockingProcess(int timeout){
if (lockingProcess != null){
lockingProcess.CloseMainWindow();
for(int waited = 0; waited < timeout && !lockingProcess.HasExited;){
lockingProcess.Refresh();
Thread.Sleep(100);
waited += 100;
}
if (lockingProcess.HasExited){
lockingProcess.Close();
lockingProcess = null;
return true;
}
}
return false;
}
}
}

View File

@ -19,7 +19,9 @@ static class Program{
#endif
public static readonly string StoragePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),BrandName);
public static readonly UserConfig UserConfig;
private static readonly LockManager LockManager;
public static UserConfig UserConfig { get; private set; }
private static string HeaderAcceptLanguage{
get{
@ -35,7 +37,7 @@ private static string HeaderAcceptLanguage{
}
static Program(){
UserConfig = UserConfig.Load(Path.Combine(StoragePath,"TD_UserConfig.cfg"));
LockManager = new LockManager(Path.Combine(StoragePath,".lock"));
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
@ -48,6 +50,18 @@ static Program(){
private static void Main(){
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (!LockManager.Lock()){
if (MessageBox.Show("Another instance of "+BrandName+" is already running.\r\nDo you want to close it?",BrandName+" is Already Running",MessageBoxButtons.YesNo,MessageBoxIcon.Error,MessageBoxDefaultButton.Button2) == DialogResult.Yes){
if (!LockManager.CloseLockingProcess(10000)){
MessageBox.Show("Could not close the other process.",BrandName+" Has Failed :(",MessageBoxButtons.OK,MessageBoxIcon.Error);
return;
}
}
else return;
}
UserConfig = UserConfig.Load(Path.Combine(StoragePath,"TD_UserConfig.cfg"));
MigrationManager.Run();
@ -70,6 +84,7 @@ private static void Main(){
Application.ApplicationExit += (sender, args) => {
UserConfig.Save();
LockManager.Unlock();
Cef.Shutdown();
};

View File

@ -75,6 +75,7 @@
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="Configuration\LockManager.cs" />
<Compile Include="Configuration\UserConfig.cs" />
<Compile Include="Core\Controls\FlatProgressBar.cs">
<SubType>Component</SubType>