mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-30 05:34:06 +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
|
#endif
|
||||||
|
|
||||||
public static readonly string StoragePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),BrandName);
|
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{
|
private static string HeaderAcceptLanguage{
|
||||||
get{
|
get{
|
||||||
@ -35,7 +37,7 @@ private static string HeaderAcceptLanguage{
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Program(){
|
static Program(){
|
||||||
UserConfig = UserConfig.Load(Path.Combine(StoragePath,"TD_UserConfig.cfg"));
|
LockManager = new LockManager(Path.Combine(StoragePath,".lock"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||||
@ -48,6 +50,18 @@ static Program(){
|
|||||||
private static void Main(){
|
private static void Main(){
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
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();
|
MigrationManager.Run();
|
||||||
|
|
||||||
@ -70,6 +84,7 @@ private static void Main(){
|
|||||||
|
|
||||||
Application.ApplicationExit += (sender, args) => {
|
Application.ApplicationExit += (sender, args) => {
|
||||||
UserConfig.Save();
|
UserConfig.Save();
|
||||||
|
LockManager.Unlock();
|
||||||
Cef.Shutdown();
|
Cef.Shutdown();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Configuration\LockManager.cs" />
|
||||||
<Compile Include="Configuration\UserConfig.cs" />
|
<Compile Include="Configuration\UserConfig.cs" />
|
||||||
<Compile Include="Core\Controls\FlatProgressBar.cs">
|
<Compile Include="Core\Controls\FlatProgressBar.cs">
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
|
Loading…
Reference in New Issue
Block a user