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:
parent
f5f0d0aeed
commit
9d840fec7c
108
Configuration/LockManager.cs
Normal file
108
Configuration/LockManager.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
19
Program.cs
19
Program.cs
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user