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); + } } } ///