diff --git a/GreenshotPlugin/Core/Language.cs b/GreenshotPlugin/Core/Language.cs
index ace4d2f13..4eb6fd67b 100644
--- a/GreenshotPlugin/Core/Language.cs
+++ b/GreenshotPlugin/Core/Language.cs
@@ -56,7 +56,7 @@ namespace GreenshotPlugin.Core {
/// Static initializer for the language code
///
static Language() {
- if (!IniConfig.IsInited) {
+ if (!IniConfig.isInitialized) {
LOG.Warn("IniConfig hasn't been initialized yet! (Design mode?)");
IniConfig.Init("greenshot", "greenshot");
}
diff --git a/GreenshotPlugin/IniFile/IniConfig.cs b/GreenshotPlugin/IniFile/IniConfig.cs
index 43059b5d9..1f3f1207d 100644
--- a/GreenshotPlugin/IniFile/IniConfig.cs
+++ b/GreenshotPlugin/IniFile/IniConfig.cs
@@ -25,6 +25,7 @@ using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
+using System.Runtime.CompilerServices;
namespace Greenshot.IniFile {
public class IniConfig {
@@ -33,17 +34,54 @@ namespace Greenshot.IniFile {
private const string DEFAULTS_POSTFIX = "-defaults";
private const string FIXED_POSTFIX = "-fixed";
+ ///
+ /// A lock object for the ini file saving
+ ///
+ private static object iniLock = new object();
+
+ ///
+ /// This is used to monitor the greenshot.ini changes
+ ///
private static FileSystemWatcher watcher;
+
+ ///
+ /// As the ini implementation is kept someone generic, for reusing, this holds the name of the application
+ ///
private static string applicationName = null;
+
+ ///
+ /// As the ini implementation is kept someone generic, for reusing, this holds the name of the configuration
+ ///
private static string configName = null;
+ ///
+ /// A Dictionary with all the sections stored by section name
+ ///
private static Dictionary sectionMap = new Dictionary();
+
+ ///
+ /// A Dictionary with the properties for a section stored by section name
+ ///
private static Dictionary> sections = new Dictionary>();
+
+ ///
+ /// A Dictionary with the fixed-properties for a section stored by section name
+ ///
private static Dictionary> fixedProperties = null;
-
+
+ ///
+ /// The IniChanged event, which can be registed
+ ///
public static event FileSystemEventHandler IniChanged;
+
+ ///
+ /// Stores if we checked for portable
+ ///
private static bool portableCheckMade = false;
+ ///
+ /// Is the configuration portable (meaning we don't store it in the AppData directory)
+ ///
private static bool portable = false;
public static bool IsPortable {
get {
@@ -63,12 +101,18 @@ namespace Greenshot.IniFile {
WatchConfigFile(true);
}
- public static bool IsInited {
+ ///
+ /// Checks if we initialized the ini
+ ///
+ public static bool isInitialized {
get {
return applicationName != null && configName != null;
}
}
+ ///
+ /// This forces the ini to be stored in the startup path, used for portable applications
+ ///
public static void ForceIniInStartupPath() {
if (portableCheckMade) {
throw new Exception("ForceLocal should be called before any file is read");
@@ -336,6 +380,11 @@ namespace Greenshot.IniFile {
return section;
}
+ ///
+ /// Get the raw properties for a section
+ ///
+ ///
+ ///
public static Dictionary PropertiesForSection(IniSection section) {
Type iniSectionType = section.GetType();
string sectionName = section.IniSectionAttribute.Name;
@@ -350,49 +399,76 @@ namespace Greenshot.IniFile {
return properties;
}
+ ///
+ /// Save the ini file
+ ///
public static void Save() {
- string iniLocation = CreateIniLocation(configName + INI_EXTENSION);
+ bool acquiredLock = false;
try {
- SaveInternally(iniLocation);
- } catch (Exception ex) {
- LOG.Error("A problem occured while writing the configuration file to: " + iniLocation);
- LOG.Error(ex);
- }
- }
-
- private static void SaveInternally(string iniLocation) {
- WatchConfigFile(false);
-
- LOG.Info("Saving configuration to: " + iniLocation);
- if (!Directory.Exists(Path.GetDirectoryName(iniLocation))) {
- Directory.CreateDirectory(Path.GetDirectoryName(iniLocation));
- }
- TextWriter writer = new StreamWriter(iniLocation, false, Encoding.UTF8);
- foreach (IniSection section in sectionMap.Values) {
- section.Write(writer, false);
- // Add empty line after section
- writer.WriteLine();
- section.IsDirty = false;
- }
- writer.WriteLine();
- // Write left over properties
- foreach (string sectionName in sections.Keys) {
- // Check if the section is one that is "registered", if so skip it!
- if (!sectionMap.ContainsKey(sectionName)) {
- writer.WriteLine("; The section {0} hasn't been 'claimed' since the last start of Greenshot, therefor it doesn't have additional information here!", sectionName);
- writer.WriteLine("; The reason could be that the section {0} just hasn't been used, a plugin has an error and can't claim it or maybe the whole section {0} is obsolete.", sectionName);
- // Write section name
- writer.WriteLine("[{0}]", sectionName);
- Dictionary properties = sections[sectionName];
- // Loop and write properties
- foreach (string propertyName in properties.Keys) {
- writer.WriteLine("{0}={1}", propertyName, properties[propertyName]);
+ acquiredLock = Monitor.TryEnter(iniLock, TimeSpan.FromMilliseconds(200));
+ if (acquiredLock) {
+ // Code that accesses resources that are protected by the lock.
+ string iniLocation = CreateIniLocation(configName + INI_EXTENSION);
+ try {
+ SaveInternally(iniLocation);
+ } catch (Exception ex) {
+ LOG.Error("A problem occured while writing the configuration file to: " + iniLocation);
+ LOG.Error(ex);
}
- writer.WriteLine();
+ } else {
+ // Code to deal with the fact that the lock was not acquired.
+ LOG.Warn("A second thread tried to save the ini-file, we blocked as the first took too long.");
+ }
+ } finally {
+ if (acquiredLock) {
+ Monitor.Exit(iniLock);
+ }
+ }
+ }
+
+ ///
+ /// The real save implementation, this first disables the watch otherwise we would be informed of our own changes.
+ ///
+ ///
+ private static void SaveInternally(string iniLocation) {
+ WatchConfigFile(false);
+ try {
+ LOG.Info("Saving configuration to: " + iniLocation);
+ if (!Directory.Exists(Path.GetDirectoryName(iniLocation))) {
+ Directory.CreateDirectory(Path.GetDirectoryName(iniLocation));
+ }
+ using (TextWriter writer = new StreamWriter(iniLocation, false, Encoding.UTF8)) {
+ foreach (IniSection section in sectionMap.Values) {
+ section.Write(writer, false);
+ // Add empty line after section
+ writer.WriteLine();
+ section.IsDirty = false;
+ }
+ writer.WriteLine();
+ // Write left over properties
+ foreach (string sectionName in sections.Keys) {
+ // Check if the section is one that is "registered", if so skip it!
+ if (!sectionMap.ContainsKey(sectionName)) {
+ writer.WriteLine("; The section {0} hasn't been 'claimed' since the last start of Greenshot, therefor it doesn't have additional information here!", sectionName);
+ writer.WriteLine("; The reason could be that the section {0} just hasn't been used, a plugin has an error and can't claim it or maybe the whole section {0} is obsolete.", sectionName);
+ // Write section name
+ writer.WriteLine("[{0}]", sectionName);
+ Dictionary properties = sections[sectionName];
+ // Loop and write properties
+ foreach (string propertyName in properties.Keys) {
+ writer.WriteLine("{0}={1}", propertyName, properties[propertyName]);
+ }
+ writer.WriteLine();
+ }
+ }
+ }
+ } finally {
+ try {
+ WatchConfigFile(true);
+ } catch (Exception ex) {
+ LOG.Error("A problem occured while enabling the WatchConfigFile: ", ex);
}
}
- writer.Close();
- WatchConfigFile(true);
}
}
}