diff --git a/BytecodeApi.Wpf/BytecodeApi.Wpf.csproj b/BytecodeApi.Wpf/BytecodeApi.Wpf.csproj
index 29848c7..a478e40 100644
--- a/BytecodeApi.Wpf/BytecodeApi.Wpf.csproj
+++ b/BytecodeApi.Wpf/BytecodeApi.Wpf.csproj
@@ -7,9 +7,9 @@
True
- 3.0.1
- 3.0.1
- 3.0.1
+ 3.0.2
+ 3.0.2
+ 3.0.2
BytecodeApi.Wpf
diff --git a/BytecodeApi.Wpf/Converters/DateOnlyConverter.cs b/BytecodeApi.Wpf/Converters/DateOnlyConverter.cs
index d5d26a1..b3fd68e 100644
--- a/BytecodeApi.Wpf/Converters/DateOnlyConverter.cs
+++ b/BytecodeApi.Wpf/Converters/DateOnlyConverter.cs
@@ -43,6 +43,7 @@ public DateOnlyConverter(DateOnlyConverterMethod method)
DateOnlyConverterMethod.ShortDate => value.Value.ToShortDateString(),
DateOnlyConverterMethod.LongDate => value.Value.ToLongDateString(),
DateOnlyConverterMethod.Year => value.Value.Year.ToString(),
+ DateOnlyConverterMethod.Quarter => ((value.Value.Month - 1) / 3 + 1).ToString(),
DateOnlyConverterMethod.Month => value.Value.Month.ToString(),
DateOnlyConverterMethod.Day => value.Value.Day.ToString(),
DateOnlyConverterMethod.Format => value.Value.ToStringInvariant(parameter ?? ""),
@@ -72,6 +73,7 @@ public DateOnlyConverter(DateOnlyConverterMethod method)
DateOnlyConverterMethod.ShortDate or
DateOnlyConverterMethod.LongDate or
DateOnlyConverterMethod.Year or
+ DateOnlyConverterMethod.Quarter or
DateOnlyConverterMethod.Month or
DateOnlyConverterMethod.Day => DependencyProperty.UnsetValue,
DateOnlyConverterMethod.Format => (value as string)?.ToDateOnly(parameter ?? ""),
diff --git a/BytecodeApi.Wpf/Converters/DateOnlyConverterMethod.cs b/BytecodeApi.Wpf/Converters/DateOnlyConverterMethod.cs
index 1345dfb..9537547 100644
--- a/BytecodeApi.Wpf/Converters/DateOnlyConverterMethod.cs
+++ b/BytecodeApi.Wpf/Converters/DateOnlyConverterMethod.cs
@@ -18,6 +18,10 @@ public enum DateOnlyConverterMethod
///
Year,
///
+ /// Returns the quarter (a number between 1 and 4) of the ? value as a .
+ ///
+ Quarter,
+ ///
/// Returns the month component of the ? value as a .
///
Month,
diff --git a/BytecodeApi.Wpf/Converters/DateTimeConverter.cs b/BytecodeApi.Wpf/Converters/DateTimeConverter.cs
index 6200a0d..04df559 100644
--- a/BytecodeApi.Wpf/Converters/DateTimeConverter.cs
+++ b/BytecodeApi.Wpf/Converters/DateTimeConverter.cs
@@ -46,6 +46,7 @@ public DateTimeConverter(DateTimeConverterMethod method)
DateTimeConverterMethod.LongDate => value.Value.ToLongDateString(),
DateTimeConverterMethod.LongTime => value.Value.ToLongTimeString(),
DateTimeConverterMethod.Year => value.Value.Year.ToString(),
+ DateTimeConverterMethod.Quarter => ((value.Value.Month - 1) / 3 + 1).ToString(),
DateTimeConverterMethod.Month => value.Value.Month.ToString(),
DateTimeConverterMethod.Day => value.Value.Day.ToString(),
DateTimeConverterMethod.Hour => value.Value.Hour.ToString(),
@@ -81,6 +82,7 @@ DateTimeConverterMethod.ShortTime or
DateTimeConverterMethod.LongDate or
DateTimeConverterMethod.LongTime => DateTime.TryParse(value as string, CultureInfo.CurrentCulture, out DateTime dateTime) ? dateTime : null,
DateTimeConverterMethod.Year or
+ DateTimeConverterMethod.Quarter or
DateTimeConverterMethod.Month or
DateTimeConverterMethod.Day or
DateTimeConverterMethod.Hour or
diff --git a/BytecodeApi.Wpf/Converters/DateTimeConverterMethod.cs b/BytecodeApi.Wpf/Converters/DateTimeConverterMethod.cs
index 7d95f2b..9669323 100644
--- a/BytecodeApi.Wpf/Converters/DateTimeConverterMethod.cs
+++ b/BytecodeApi.Wpf/Converters/DateTimeConverterMethod.cs
@@ -26,6 +26,10 @@ public enum DateTimeConverterMethod
///
Year,
///
+ /// Returns the quarter (a number between 1 and 4) of the ? value as a .
+ ///
+ Quarter,
+ ///
/// Returns the month component of the ? value as a .
///
Month,
diff --git a/BytecodeApi/BytecodeApi.csproj b/BytecodeApi/BytecodeApi.csproj
index 2dffe97..13a32da 100644
--- a/BytecodeApi/BytecodeApi.csproj
+++ b/BytecodeApi/BytecodeApi.csproj
@@ -8,9 +8,9 @@
True
- 3.0.2
- 3.0.2
- 3.0.2
+ 3.0.3
+ 3.0.3
+ 3.0.3
BytecodeApi
diff --git a/BytecodeApi/Extensions/RandomExtensions.cs b/BytecodeApi/Extensions/RandomExtensions.cs
index 5d5d47f..5825b64 100644
--- a/BytecodeApi/Extensions/RandomExtensions.cs
+++ b/BytecodeApi/Extensions/RandomExtensions.cs
@@ -273,4 +273,21 @@ public static T NextObject(this Random random, IList list)
return list[random.Next(list.Count)];
}
+ ///
+ /// Returns a random value of the specified type.
+ ///
+ /// The type of the to be returned.
+ /// The object to be used for random number generation.
+ ///
+ /// A random value of the specified type.
+ ///
+ public static T NextEnumValue(this Random random) where T : struct, Enum
+ {
+ Check.ArgumentNull(random);
+
+ T[] values = EnumEx.GetValues();
+ if (values.None()) throw Throw.Argument(nameof(T), "Enum does not have values.");
+
+ return random.NextObject(values);
+ }
}
\ No newline at end of file
diff --git a/BytecodeApi/Extensions/RandomNumberGeneratorExtensions.cs b/BytecodeApi/Extensions/RandomNumberGeneratorExtensions.cs
index 9569e05..c71ab3d 100644
--- a/BytecodeApi/Extensions/RandomNumberGeneratorExtensions.cs
+++ b/BytecodeApi/Extensions/RandomNumberGeneratorExtensions.cs
@@ -269,4 +269,21 @@ public static T GetObject(this RandomNumberGenerator randomNumberGenerator, I
return list[randomNumberGenerator.GetInt32(list.Count)];
}
+ ///
+ /// Returns a random value of the specified type.
+ ///
+ /// The type of the to be returned.
+ /// The object to be used for random number generation.
+ ///
+ /// A random value of the specified type.
+ ///
+ public static T GetEnumValue(this RandomNumberGenerator randomNumberGenerator) where T : struct, Enum
+ {
+ Check.ArgumentNull(randomNumberGenerator);
+
+ T[] values = EnumEx.GetValues();
+ if (values.None()) throw Throw.Argument(nameof(T), "Enum does not have values.");
+
+ return randomNumberGenerator.GetObject(values);
+ }
}
\ No newline at end of file
diff --git a/BytecodeApi/Extensions/ReflectionExtensions.cs b/BytecodeApi/Extensions/ReflectionExtensions.cs
index 4b4e86b..044092a 100644
--- a/BytecodeApi/Extensions/ReflectionExtensions.cs
+++ b/BytecodeApi/Extensions/ReflectionExtensions.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using System.Text.RegularExpressions;
namespace BytecodeApi.Extensions;
@@ -111,7 +112,13 @@ public static string ToCSharpName(this Type type, TypeNaming namingConvention)
while (t.HasElementType)
{
- suffix = new[] { "[]", "*", "&" }.First(name.EndsWith) + suffix;
+ Match match = Regex.Match(name, @"\[,*\]|\*|&", RegexOptions.RightToLeft);
+ if (!match.Success)
+ {
+ throw new InvalidOperationException("Could not parse element type.");
+ }
+
+ suffix = match.Value + suffix;
if (t.GetElementType() is Type elementType)
{
diff --git a/BytecodeApi/Extensions/RegistryExtensions.cs b/BytecodeApi/Extensions/RegistryExtensions.cs
index c7e5ef4..05efad3 100644
--- a/BytecodeApi/Extensions/RegistryExtensions.cs
+++ b/BytecodeApi/Extensions/RegistryExtensions.cs
@@ -121,7 +121,7 @@ public static long GetInt64Value(this RegistryKey key, string? name, long defaul
return key.GetInt64Value(name) ?? defaultValue;
}
///
- /// Retrieves a value from this that is represented as a REG_SZ value. Returns , if the value does not exist in the registry or is not a REG_SZ value.
+ /// Retrieves a value from this that is represented as a REG_SZ or REG_EXPAND_SZ value. Returns , if the value does not exist in the registry or is not a REG_SZ or REG_EXPAND_SZ value.
///
/// The to read the value from.
/// A value specifying the name of the value to read.
@@ -136,7 +136,7 @@ public static long GetInt64Value(this RegistryKey key, string? name, long defaul
return key.GetValue(name) as string;
}
///
- /// Retrieves a value from this that is represented as a REG_SZ value. Returns a default value, if the value does not exist in the registry or is not a REG_SZ value.
+ /// Retrieves a value from this that is represented as a REG_SZ or REG_EXPAND_SZ value. Returns a default value, if the value does not exist in the registry or is not a REG_SZ or REG_EXPAND_SZ value.
///
/// The to read the value from.
/// A value specifying the name of the value to read.
@@ -150,6 +150,35 @@ public static string GetStringValue(this RegistryKey key, string? name, string d
return key.GetStringValue(name) ?? defaultValue;
}
///
+ /// Retrieves the original, unexpanded value from this that is represented as a REG_SZ or REG_EXPAND_SZ value. Returns , if the value does not exist in the registry or is not a REG_SZ or REG_EXPAND_SZ value.
+ ///
+ /// The to read the value from.
+ /// A value specifying the name of the value to read.
+ ///
+ /// The converted value, if it exists and conversion is possible;
+ /// otherwise, .
+ ///
+ public static string? GetExpandStringValue(this RegistryKey key, string? name)
+ {
+ Check.ArgumentNull(key);
+
+ return key.GetValue(name, null, RegistryValueOptions.DoNotExpandEnvironmentNames) as string;
+ }
+ ///
+ /// Retrieves the original, unexpanded value from this that is represented as a REG_SZ or REG_EXPAND_SZ value. Returns a default value, if the value does not exist in the registry or is not a REG_SZ value.
+ ///
+ /// The to read the value from.
+ /// A value specifying the name of the value to read.
+ /// The value that is used if retrieving or conversion failed.
+ ///
+ /// The converted value, if it exists and conversion is possible;
+ /// otherwise, .
+ ///
+ public static string GetExpandStringValue(this RegistryKey key, string? name, string defaultValue)
+ {
+ return key.GetExpandStringValue(name) ?? defaultValue;
+ }
+ ///
/// Retrieves a value from this that is represented as a REG_SZ value. Returns , if the value does not exist in the registry, is not a REG_SZ value, or does not match the format.
/// is used to convert the REG_SZ value.
///
@@ -341,6 +370,25 @@ public static void SetStringValue(this RegistryKey key, string? name, string? va
}
}
///
+ /// Writes a value to this that is represented as a REG_EXPAND_SZ value. If is provided, the value will be deleted.
+ ///
+ /// The to write the value to.
+ /// A value specifying the name of the value to write to.
+ /// The value to be written. If is provided, the value will be deleted.
+ public static void SetExpandStringValue(this RegistryKey key, string? name, string? value)
+ {
+ Check.ArgumentNull(key);
+
+ if (value == null)
+ {
+ key.DeleteValue(name ?? "", false);
+ }
+ else
+ {
+ key.SetValue(name, value, RegistryValueKind.ExpandString);
+ }
+ }
+ ///
/// Writes a value to this that is represented as a REG_SZ value. If is provided, the value will be deleted.
/// is used to convert to a REG_SZ value.
///
diff --git a/BytecodeApi/IO/CommandLine.cs b/BytecodeApi/IO/CommandLine.cs
index e467b98..5b5f5f8 100644
--- a/BytecodeApi/IO/CommandLine.cs
+++ b/BytecodeApi/IO/CommandLine.cs
@@ -1,4 +1,5 @@
-using System.Runtime.InteropServices;
+using BytecodeApi.Extensions;
+using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
@@ -21,19 +22,26 @@ public static string[] GetArguments(string commandLine)
{
Check.ArgumentNull(commandLine);
- nint argumentsPtr = Native.CommandLineToArgvW(commandLine, out int count);
- if (argumentsPtr == 0)
+ if (commandLine.IsNullOrWhiteSpace())
{
- throw Throw.Win32();
+ return new string[0];
}
-
- try
- {
- return Create.Array(count, i => Marshal.PtrToStringUni(Marshal.ReadIntPtr(argumentsPtr, i * nint.Size)) ?? "");
- }
- finally
+ else
{
- Native.LocalFree(argumentsPtr);
+ nint argumentsPtr = Native.CommandLineToArgvW(commandLine, out int count);
+ if (argumentsPtr == 0)
+ {
+ throw Throw.Win32();
+ }
+
+ try
+ {
+ return Create.Array(count, i => Marshal.PtrToStringUni(Marshal.ReadIntPtr(argumentsPtr, i * nint.Size)) ?? "");
+ }
+ finally
+ {
+ Native.LocalFree(argumentsPtr);
+ }
}
}
///