diff --git a/Pilz.Configuration/Pilz.Configuration.csproj b/Pilz.Configuration/Pilz.Configuration.csproj
index 60441c6..0432be3 100644
--- a/Pilz.Configuration/Pilz.Configuration.csproj
+++ b/Pilz.Configuration/Pilz.Configuration.csproj
@@ -29,6 +29,6 @@
-
+
\ No newline at end of file
diff --git a/Pilz.IO/Pilz.IO.csproj b/Pilz.IO/Pilz.IO.csproj
index 0fbf985..ea2e440 100644
--- a/Pilz.IO/Pilz.IO.csproj
+++ b/Pilz.IO/Pilz.IO.csproj
@@ -91,6 +91,6 @@
-
+
\ No newline at end of file
diff --git a/Pilz.sln b/Pilz.sln
index e3784c6..37cd836 100644
--- a/Pilz.sln
+++ b/Pilz.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34018.315
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Pilz", "Pilz\Pilz.vbproj", "{277D2B83-7613-4C49-9CAB-E080195A6E0C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pilz", "Pilz\Pilz.csproj", "{9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}"
EndProject
Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Pilz.Drawing", "Pilz.Drawing\Pilz.Drawing.vbproj", "{1A0B8106-2449-4908-B5E1-A00D8E9CF8F6}"
EndProject
@@ -53,14 +53,14 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {277D2B83-7613-4C49-9CAB-E080195A6E0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {277D2B83-7613-4C49-9CAB-E080195A6E0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {277D2B83-7613-4C49-9CAB-E080195A6E0C}.Debug|x86.ActiveCfg = Debug|Any CPU
- {277D2B83-7613-4C49-9CAB-E080195A6E0C}.Debug|x86.Build.0 = Debug|Any CPU
- {277D2B83-7613-4C49-9CAB-E080195A6E0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {277D2B83-7613-4C49-9CAB-E080195A6E0C}.Release|Any CPU.Build.0 = Release|Any CPU
- {277D2B83-7613-4C49-9CAB-E080195A6E0C}.Release|x86.ActiveCfg = Release|Any CPU
- {277D2B83-7613-4C49-9CAB-E080195A6E0C}.Release|x86.Build.0 = Release|Any CPU
+ {9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}.Debug|x86.Build.0 = Debug|Any CPU
+ {9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}.Release|x86.ActiveCfg = Release|Any CPU
+ {9559AAE8-BA4B-03B8-1EF3-2AFE7BCD5AAC}.Release|x86.Build.0 = Release|Any CPU
{1A0B8106-2449-4908-B5E1-A00D8E9CF8F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A0B8106-2449-4908-B5E1-A00D8E9CF8F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A0B8106-2449-4908-B5E1-A00D8E9CF8F6}.Debug|x86.ActiveCfg = Debug|Any CPU
diff --git a/Pilz/AppChannel.cs b/Pilz/AppChannel.cs
new file mode 100644
index 0000000..fbb1e5e
--- /dev/null
+++ b/Pilz/AppChannel.cs
@@ -0,0 +1,9 @@
+namespace Pilz;
+
+public enum AppChannel
+{
+ Stable,
+ PreRelease,
+ Beta,
+ Alpha
+}
\ No newline at end of file
diff --git a/Pilz/AppVersion.cs b/Pilz/AppVersion.cs
new file mode 100644
index 0000000..420f7e2
--- /dev/null
+++ b/Pilz/AppVersion.cs
@@ -0,0 +1,152 @@
+using Newtonsoft.Json;
+
+namespace Pilz;
+
+[method: JsonConstructor]
+public class AppVersion(Version version, int build, AppChannel channel) : IComparable, IComparable
+{
+ // P r o p e r t i e s
+
+ [JsonConverter(typeof(Newtonsoft.Json.Converters.VersionConverter))]
+ public Version Version { get; set; } = version;
+ [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
+ public AppChannel Channel { get; set; } = channel;
+ public int Build { get; set; } = build;
+
+ // C o n s t r u c t o r s
+
+ public AppVersion() : this(new Version("1.0.0.0"))
+ {
+ }
+
+ public AppVersion(Version version) : this(version, 1, AppChannel.Stable)
+ {
+ }
+
+ // F e a t u r e s
+
+ public override string ToString()
+ {
+ if (Channel == AppChannel.Stable && Build == 1)
+ return Version.ToString();
+
+ return $"{Version} {Channel} {Build}";
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(this, obj))
+ return true;
+ if (obj is not AppVersion applicationVersion)
+ return false;
+ return applicationVersion == this;
+ }
+
+ public override int GetHashCode()
+ {
+ return ToString().GetHashCode();
+ }
+
+ public static bool TryParse(string input, out AppVersion version)
+ {
+ try
+ {
+ version = Parse(input);
+ }
+ catch (Exception)
+ {
+ version = null;
+ }
+ return version != null;
+ }
+
+ public static AppVersion Parse(string input)
+ {
+ if (string.IsNullOrWhiteSpace(input))
+ throw new FormatException();
+
+ if (input.StartsWith("version", StringComparison.InvariantCultureIgnoreCase))
+ input = input[7..];
+
+ var splitted = input.Trim().Split(' ');
+
+ if (splitted.Length < 1 || !Version.TryParse(splitted[0], out Version? version) || version == null)
+ throw new FormatException();
+
+ if (splitted.Length < 2 || !Enum.TryParse(splitted[1], out AppChannel channel))
+ channel = AppChannel.Stable;
+
+ if (splitted.Length < 3 || !int.TryParse(splitted[2], out int build))
+ build = 1;
+
+ return new AppVersion(version, build, channel);
+ }
+
+ // C o m p a r e
+
+ public int CompareTo(object appVersion)
+ {
+ return CompareTo(appVersion as AppVersion);
+ }
+
+ public int CompareTo(AppVersion appVersion)
+ {
+ if (appVersion is null)
+ return 1;
+
+ if (Version != appVersion.Version)
+ {
+ if (Version > appVersion.Version)
+ return 1;
+ return -1;
+ }
+
+ if (Channel != appVersion.Channel)
+ {
+ if (Channel < appVersion.Channel)
+ return 1;
+ return -1;
+ }
+
+ if (Build != appVersion.Build)
+ {
+ if (Build > appVersion.Build)
+ return 1;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ // O p e r a t o r s
+
+ public static bool operator >(AppVersion a, AppVersion b)
+ {
+ return a.Version > b.Version || a.Version == b.Version && (a.Channel < b.Channel || (a.Channel == b.Channel && a.Build > b.Build));
+ }
+
+ public static bool operator <(AppVersion a, AppVersion b)
+ {
+ return a.Version < b.Version || a.Version == b.Version && (a.Channel > b.Channel || (a.Channel == b.Channel && a.Build < b.Build));
+ }
+
+ public static bool operator ==(AppVersion a, AppVersion b)
+ {
+ return a.Version == b.Version && a.Channel == b.Channel && a.Build == b.Build;
+ }
+
+ public static bool operator !=(AppVersion a, AppVersion b)
+ {
+ return a.Version != b.Version || a.Channel != b.Channel || a.Build != b.Build;
+ }
+
+ public static bool operator >=(AppVersion a, AppVersion b)
+ {
+ return a == b || a > b;
+ }
+
+ public static bool operator <=(AppVersion a, AppVersion b)
+ {
+ return a == b || a < b;
+ }
+}
\ No newline at end of file
diff --git a/Pilz/GeneralEventArgs/GetValueEventArgs.cs b/Pilz/GeneralEventArgs/GetValueEventArgs.cs
new file mode 100644
index 0000000..c947acd
--- /dev/null
+++ b/Pilz/GeneralEventArgs/GetValueEventArgs.cs
@@ -0,0 +1,18 @@
+namespace Pilz.GeneralEventArgs;
+
+
+public class GetValueEventArgs : EventArgs
+{
+
+ public T? Value { get; set; }
+
+ public GetValueEventArgs() : base()
+ {
+ }
+
+ public GetValueEventArgs(T? value) : base()
+ {
+ Value = value;
+ }
+
+}
\ No newline at end of file
diff --git a/Pilz/GeneralEventArgs/GetValueEventArgs.vb b/Pilz/GeneralEventArgs/GetValueEventArgs.vb
deleted file mode 100644
index 397e2ed..0000000
--- a/Pilz/GeneralEventArgs/GetValueEventArgs.vb
+++ /dev/null
@@ -1,18 +0,0 @@
-Namespace GeneralEventArgs
-
- Public Class GetValueEventArgs(Of T)
- Inherits EventArgs
-
- Public Property Value As T
-
- Public Sub New()
- MyBase.New
- End Sub
-
- Public Sub New(value As T)
- MyBase.New
- End Sub
-
- End Class
-
-End Namespace
diff --git a/Pilz/Json/AppVersionStringJsonConverter.cs b/Pilz/Json/AppVersionStringJsonConverter.cs
new file mode 100644
index 0000000..1b34551
--- /dev/null
+++ b/Pilz/Json/AppVersionStringJsonConverter.cs
@@ -0,0 +1,80 @@
+using Newtonsoft.Json;
+
+namespace Pilz.Json;
+
+public class AppVersionStringJsonConverter(bool serializeAsObject) : JsonConverter
+{
+ public AppVersionStringJsonConverter() : this(false)
+ {
+ }
+
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The value.
+ /// The calling serializer.
+ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ if (serializeAsObject || value is not AppVersion appVersion)
+ writer.WriteValue(value);
+ else
+ writer.WriteValue(appVersion.ToString());
+ }
+
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ return null;
+
+ try
+ {
+ if (reader.TokenType == JsonToken.String)
+ {
+ var strValue = reader.Value?.ToString();
+
+ if (string.IsNullOrWhiteSpace(strValue))
+ return null;
+
+ return AppVersion.Parse(strValue);
+
+ }
+
+ if (reader.TokenType == JsonToken.StartObject)
+ return serializer.Deserialize(reader);
+ }
+ catch (Exception ex)
+ {
+ throw new JsonSerializationException("Error converting value {0} to type '{1}'.", ex);
+ }
+
+ // we don't actually expect to get here.
+ throw new JsonSerializationException("Unexpected token {0} when parsing app version.");
+ }
+
+ ///
+ /// Determines whether this instance can convert the specified object type.
+ ///
+ /// Type of the object.
+ ///
+ /// true if this instance can convert the specified object type; otherwise, false.
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(AppVersion);
+ }
+}
diff --git a/Pilz/Pilz.csproj b/Pilz/Pilz.csproj
new file mode 100644
index 0000000..35d11f3
--- /dev/null
+++ b/Pilz/Pilz.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net8.0
+ latest
+ enable
+ enable
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz/Pilz.vbproj b/Pilz/Pilz.vbproj
deleted file mode 100644
index e5cd91f..0000000
--- a/Pilz/Pilz.vbproj
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
- netstandard2.0;net8.0
- Pilz.xml
- true
- latest
- Pilz
- Pilzinsel64
- Pilz
- Copyright © Pilzinsel64 2019 - 2020
- Pilz.xml
- true
- 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
-
-
- true
-
-
- false
-
-
- On
-
-
- Binary
-
-
- Off
- On
-
-
- 2.0.0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Pilz/Runtime/OSType.cs b/Pilz/Runtime/OSType.cs
new file mode 100644
index 0000000..06dc7cd
--- /dev/null
+++ b/Pilz/Runtime/OSType.cs
@@ -0,0 +1,9 @@
+namespace Pilz.Runtime;
+
+public enum OSType
+{
+ Unknown,
+ Windows,
+ Linux,
+ OSX
+}
\ No newline at end of file
diff --git a/Pilz/Runtime/OSType.vb b/Pilz/Runtime/OSType.vb
deleted file mode 100644
index 477cc87..0000000
--- a/Pilz/Runtime/OSType.vb
+++ /dev/null
@@ -1,10 +0,0 @@
-Namespace Runtime
-
- Public Enum OSType
- Unknown
- Windows
- Linux
- OSX
- End Enum
-
-End Namespace
diff --git a/Pilz/Runtime/RuntimeInformationsEx.cs b/Pilz/Runtime/RuntimeInformationsEx.cs
new file mode 100644
index 0000000..29d91ea
--- /dev/null
+++ b/Pilz/Runtime/RuntimeInformationsEx.cs
@@ -0,0 +1,79 @@
+using System.Runtime.InteropServices;
+
+namespace Pilz.Runtime;
+
+public static class RuntimeInformationsEx
+{
+ private static OSType? osType;
+ private static OSType? osTypeReal;
+
+ public static OSType OSType => osType ??= GetOSType();
+
+ public static OSType RealOSType => osTypeReal ??= GetRealOSType();
+
+ public static OSType GetOSType()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ return OSType.Windows;
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ return OSType.Linux;
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ return OSType.OSX;
+
+ return OSType.Unknown;
+ }
+
+ public static OSType GetRealOSType()
+ {
+ var windir = Environment.GetEnvironmentVariable("windir");
+ const string ostypeDirWine = @"Z:\proc\sys\kernel\ostype";
+ const string ostypeDirNative = "/proc/sys/kernel/ostype";
+ const string systemVersionWine = @"Z:\System\Library\CoreServices\SystemVersion.plist";
+ const string systemVersionNative = "/System/Library/CoreServices/SystemVersion.plist";
+
+ // Linux using wine
+ if (File.Exists(ostypeDirWine))
+ {
+ var osTypeString = File.ReadAllText(ostypeDirWine);
+ if (osTypeString.StartsWith("Linux", StringComparison.OrdinalIgnoreCase))
+ // Note: Android gets here too
+ return OSType.Linux;
+ else
+ return OSType.Unknown;
+ }
+
+ // Linux native
+ else if (File.Exists(ostypeDirNative))
+ {
+ var osTypeString = File.ReadAllText(ostypeDirNative);
+ if (osTypeString.StartsWith("Linux", StringComparison.OrdinalIgnoreCase))
+ // Note: Android gets here too
+ return OSType.Linux;
+ else
+ return OSType.Unknown;
+ }
+
+ // OSX using wine
+ else if (File.Exists(systemVersionWine))
+ // Note: iOS gets here too
+ return OSType.OSX;
+
+ // OSX native
+ else if (File.Exists(systemVersionNative))
+ // Note: iOS gets here too
+ return OSType.OSX;
+
+ // Windows
+ else if (!string.IsNullOrEmpty(windir) && Directory.Exists(windir) && Path.DirectorySeparatorChar == '\\')
+ return OSType.Windows;
+
+ return OSType.Unknown;
+ }
+
+ public static bool IsOSPlatform(OSType os, bool checkRealOS)
+ {
+ return (checkRealOS ? RealOSType : OSType) == os;
+ }
+}
\ No newline at end of file
diff --git a/Pilz/Runtime/RuntimeInformationsEx.vb b/Pilz/Runtime/RuntimeInformationsEx.vb
deleted file mode 100644
index 6ad5541..0000000
--- a/Pilz/Runtime/RuntimeInformationsEx.vb
+++ /dev/null
@@ -1,81 +0,0 @@
-Imports System.IO
-Imports System.Runtime.InteropServices
-
-Namespace Runtime
-
- Public Module RuntimeInformationsEx
-
- Public ReadOnly Property OSType As OSType
- Get
- Static t As OSType? = Nothing
-
- If t Is Nothing Then
- Select Case True
- Case RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
- t = OSType.Windows
- Case RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
- t = OSType.Linux
- Case RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
- t = OSType.OSX
- Case Else
- t = OSType.Unknown
- End Select
- End If
-
- Return t
- End Get
- End Property
-
- Public ReadOnly Property RealOSType As OSType
- Get
- Static t As OSType? = Nothing
-
- If t Is Nothing Then
-
- Dim windir = Environment.GetEnvironmentVariable("windir")
- Const ostypeDirWine = "Z:\proc\sys\kernel\ostype"
- Const ostypeDirNative = "/proc/sys/kernel/ostype"
- Const systemVersionWine = "Z:\System\Library\CoreServices\SystemVersion.plist"
- Const systemVersionNative = "/System/Library/CoreServices/SystemVersion.plist"
-
- If File.Exists(ostypeDirWine) Then ' Linux using wine
- Dim osTypeString As String = File.ReadAllText(ostypeDirWine)
- If osTypeString.StartsWith("Linux", StringComparison.OrdinalIgnoreCase) Then
- ' Note: Android gets here too
- t = OSType.Linux
- Else
- t = OSType.Unknown
- End If
- ElseIf File.Exists(ostypeDirNative) Then ' Linux native
- Dim osTypeString As String = File.ReadAllText(ostypeDirNative)
- If osTypeString.StartsWith("Linux", StringComparison.OrdinalIgnoreCase) Then
- ' Note: Android gets here too
- t = OSType.Linux
- Else
- t = OSType.Unknown
- End If
- ElseIf File.Exists(systemVersionWine) Then ' OSX using wine
- ' Note: iOS gets here too
- t = OSType.OSX
- ElseIf File.Exists(systemVersionNative) Then ' OSX native
- ' Note: iOS gets here too
- t = OSType.OSX
- ElseIf Not String.IsNullOrEmpty(windir) AndAlso Directory.Exists(windir) AndAlso Path.DirectorySeparatorChar = "\"c Then ' Windows
- t = OSType.Windows
- Else
- t = OSType.Unknown
- End If
-
- End If
-
- Return t
- End Get
- End Property
-
- Public Function IsOSPlatform(os As OSType, checkRealOS As Boolean) As Boolean
- Return If(checkRealOS, RealOSType, OSType) = os
- End Function
-
- End Module
-
-End Namespace