mirror of
https://github.com/soukoku/ntwain.git
synced 2025-11-07 18:14:46 +08:00
More cleanup for v1.
This commit is contained in:
@@ -1,232 +0,0 @@
|
||||
using NTwain.Properties;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NTwain.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// The one-stop class for reading TWAIN cap values.
|
||||
/// This contains all the properties for the 4 container types.
|
||||
/// </summary>
|
||||
public class CapReadOut
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the value from a <see cref="TWCapability"/> that was returned
|
||||
/// from a TWAIN source.
|
||||
/// </summary>
|
||||
/// <param name="capability">The capability.</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="System.ArgumentNullException">capability</exception>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// Capability contains no data.;capability
|
||||
/// or
|
||||
/// capability
|
||||
/// </exception>
|
||||
public static CapReadOut ReadValue(TWCapability capability)
|
||||
{
|
||||
if (capability == null) { throw new ArgumentNullException("capability"); }
|
||||
if (capability.Container == IntPtr.Zero) { throw new ArgumentException(Resources.CapHasNoData, "capability"); }
|
||||
|
||||
IntPtr baseAddr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
baseAddr = Platform.MemoryManager.Lock(capability.Container);
|
||||
switch (capability.ContainerType)
|
||||
{
|
||||
case ContainerType.Array:
|
||||
return new CapReadOut
|
||||
{
|
||||
ContainerType = capability.ContainerType,
|
||||
}.ReadArrayValue(baseAddr);
|
||||
case ContainerType.Enum:
|
||||
return new CapReadOut
|
||||
{
|
||||
ContainerType = capability.ContainerType,
|
||||
}.ReadEnumValue(baseAddr);
|
||||
case ContainerType.OneValue:
|
||||
return new CapReadOut
|
||||
{
|
||||
ContainerType = capability.ContainerType,
|
||||
}.ReadOneValue(baseAddr);
|
||||
case ContainerType.Range:
|
||||
return new CapReadOut
|
||||
{
|
||||
ContainerType = capability.ContainerType,
|
||||
}.ReadRangeValue(baseAddr);
|
||||
default:
|
||||
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.CapHasBadContainer, capability.ContainerType), "capability");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (baseAddr != IntPtr.Zero)
|
||||
{
|
||||
Platform.MemoryManager.Unlock(baseAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region common prop
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying container type.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The container.
|
||||
/// </value>
|
||||
public ContainerType ContainerType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the TWAIN value.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The type of the value.
|
||||
/// </value>
|
||||
public ItemType ItemType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the one value if container is <see cref="NTwain.ContainerType.Array"/>.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The one value.
|
||||
/// </value>
|
||||
public object OneValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection values if container is <see cref="NTwain.ContainerType.Enum"/> or <see cref="NTwain.ContainerType.Range"/> .
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The collection values.
|
||||
/// </value>
|
||||
public IList<object> CollectionValues { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region enum prop
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value index if container is <see cref="NTwain.ContainerType.Enum"/>.
|
||||
/// </summary>
|
||||
public int EnumCurrentIndex { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the default value index if container is <see cref="NTwain.ContainerType.Enum" />.
|
||||
/// </summary>
|
||||
public int EnumDefaultIndex { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region range prop
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value if container is <see cref="NTwain.ContainerType.Range" />.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The range current value.
|
||||
/// </value>
|
||||
public object RangeCurrentValue { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the default value if container is <see cref="NTwain.ContainerType.Range" />.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The range default value.
|
||||
/// </value>
|
||||
public object RangeDefaultValue { get; private set; }
|
||||
/// <summary>
|
||||
/// The least positive/most negative value of the range.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The range minimum value.
|
||||
/// </value>
|
||||
public uint RangeMinValue { get; private set; }
|
||||
/// <summary>
|
||||
/// The most positive/least negative value of the range.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The range maximum value.
|
||||
/// </value>
|
||||
public uint RangeMaxValue { get; private set; }
|
||||
/// <summary>
|
||||
/// The delta between two adjacent values of the range.
|
||||
/// e.g. Item2 - Item1 = StepSize;
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The size of the range step.
|
||||
/// </value>
|
||||
public uint RangeStepSize { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region reader methods
|
||||
|
||||
CapReadOut ReadOneValue(IntPtr baseAddr)
|
||||
{
|
||||
int offset = 0;
|
||||
ItemType = (ItemType)(ushort)Marshal.ReadInt16(baseAddr, offset);
|
||||
offset += 2;
|
||||
OneValue = TypeReader.ReadValue(baseAddr, ref offset, ItemType);
|
||||
return this;
|
||||
}
|
||||
|
||||
CapReadOut ReadArrayValue(IntPtr baseAddr)
|
||||
{
|
||||
int offset = 0;
|
||||
ItemType = (ItemType)(ushort)Marshal.ReadInt16(baseAddr, offset);
|
||||
offset += 2;
|
||||
var count = Marshal.ReadInt32(baseAddr, offset);
|
||||
offset += 4;
|
||||
if (count > 0)
|
||||
{
|
||||
CollectionValues = new object[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
CollectionValues[i] = TypeReader.ReadValue(baseAddr, ref offset, ItemType);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
CapReadOut ReadEnumValue(IntPtr baseAddr)
|
||||
{
|
||||
int offset = 0;
|
||||
ItemType = (ItemType)(ushort)Marshal.ReadInt16(baseAddr, offset);
|
||||
offset += 2;
|
||||
int count = Marshal.ReadInt32(baseAddr, offset);
|
||||
offset += 4;
|
||||
EnumCurrentIndex = Marshal.ReadInt32(baseAddr, offset);
|
||||
offset += 4;
|
||||
EnumDefaultIndex = Marshal.ReadInt32(baseAddr, offset);
|
||||
offset += 4;
|
||||
if (count > 0)
|
||||
{
|
||||
CollectionValues = new object[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
CollectionValues[i] = TypeReader.ReadValue(baseAddr, ref offset, ItemType);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
CapReadOut ReadRangeValue(IntPtr baseAddr)
|
||||
{
|
||||
int offset = 0;
|
||||
ItemType = (ItemType)(ushort)Marshal.ReadInt16(baseAddr, offset);
|
||||
offset += 2;
|
||||
RangeMinValue = (uint)Marshal.ReadInt32(baseAddr, offset);
|
||||
offset += 4;
|
||||
RangeMaxValue = (uint)Marshal.ReadInt32(baseAddr, offset);
|
||||
offset += 4;
|
||||
RangeStepSize = (uint)Marshal.ReadInt32(baseAddr, offset);
|
||||
offset += 4;
|
||||
RangeDefaultValue = (uint)Marshal.ReadInt32(baseAddr, offset);
|
||||
offset += 4;
|
||||
RangeCurrentValue = (uint)Marshal.ReadInt32(baseAddr, offset);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace NTwain.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates how the source should be enabled in a TWAIN session.
|
||||
/// </summary>
|
||||
public enum SourceEnableMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Start acquiring without driver UI.
|
||||
/// </summary>
|
||||
NoUI,
|
||||
/// <summary>
|
||||
/// Start acquiring with driver UI.
|
||||
/// </summary>
|
||||
ShowUI,
|
||||
/// <summary>
|
||||
/// Show driver UI for settings change but no acquisition.
|
||||
/// </summary>
|
||||
ShowUIOnly
|
||||
}
|
||||
}
|
||||
@@ -486,10 +486,12 @@ namespace NTwain.Data
|
||||
/// <summary>
|
||||
/// Channel-specific transform parameters.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWDecodeFunction[] Decode { get { return _decode; } }//set { _decode = value; } }
|
||||
/// <summary>
|
||||
/// Flattened 3x3 matrix that specifies how channels are mixed in.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWFix32[] Mix { get { return _mix; } }//set { _mix = value; } }
|
||||
|
||||
/// <summary>
|
||||
@@ -527,6 +529,7 @@ namespace NTwain.Data
|
||||
/// <summary>
|
||||
/// Array of ItemType values starts here.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public object[] ItemList
|
||||
{
|
||||
get { return _itemList; }
|
||||
@@ -1060,6 +1063,7 @@ namespace NTwain.Data
|
||||
/// Optional table look-up values used by the decode function. Samples
|
||||
/// are ordered sequentially and end-to-end as A, B, C, L, M, and N.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWFix32[] Samples { get { return _samples; } }
|
||||
}
|
||||
|
||||
@@ -1251,6 +1255,7 @@ namespace NTwain.Data
|
||||
/// <summary>
|
||||
/// The enumerated list: one value resides within each array element.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public object[] ItemList
|
||||
{
|
||||
get { return _itemList; }
|
||||
@@ -1352,6 +1357,7 @@ namespace NTwain.Data
|
||||
/// <summary>
|
||||
/// Array of information.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWInfo[] Info { get { return _info; } }
|
||||
|
||||
#region IDisposable Members
|
||||
@@ -1493,6 +1499,7 @@ namespace NTwain.Data
|
||||
/// Transfer curve descriptors. All three channels (Channel1, Channel2
|
||||
/// and Channel3) must contain the same value for every entry.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWElement8[] Response { get { return _response; } set { _response = value; } }
|
||||
}
|
||||
|
||||
@@ -1772,6 +1779,7 @@ namespace NTwain.Data
|
||||
/// bits. However, both the application and Source must simultaneously
|
||||
/// support sample sizes greater than 8 bits per color.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public short[] BitsPerSample { get { return _bitsPerSample; } }
|
||||
/// <summary>
|
||||
/// The number of bits in each image pixel (or bit depth). This value is
|
||||
@@ -1969,23 +1977,28 @@ namespace NTwain.Data
|
||||
/// <summary>
|
||||
/// Mapping of components to Quantization tables.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public ushort[] QuantMap { get { return _quantMap; } set { _quantMap = value; } }
|
||||
/// <summary>
|
||||
/// Quantization tables.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWMemory[] QuantTable { get { return _quantTable; } set { _quantTable = value; } }
|
||||
/// <summary>
|
||||
/// Mapping of components to Huffman tables. Null entries signify
|
||||
/// selection of the default tables.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public ushort[] HuffmanMap { get { return _huffmanMap; } set { _huffmanMap = value; } }
|
||||
/// <summary>
|
||||
/// DC Huffman tables. Null entries signify selection of the default tables.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWMemory[] HuffmanDC { get { return _huffmanDC; } set { _huffmanDC = value; } }
|
||||
/// <summary>
|
||||
/// AC Huffman tables. Null entries signify selection of the default tables.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWMemory[] HuffmanAC { get { return _huffmanAC; } set { _huffmanAC = value; } }
|
||||
}
|
||||
|
||||
@@ -2023,6 +2036,7 @@ namespace NTwain.Data
|
||||
/// <summary>
|
||||
/// Array of palette values.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWElement8[] Colors { get { return _colors; } set { _colors = value; } }
|
||||
}
|
||||
|
||||
@@ -2134,6 +2148,7 @@ namespace NTwain.Data
|
||||
/// Transfer curve descriptors. To minimize color shift problems, writing the
|
||||
/// same values into each channel is desirable.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public TWElement8[] Response { get { return _response; } set { _response = value; } }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NTwain.Data
|
||||
@@ -67,7 +68,7 @@ namespace NTwain.Data
|
||||
val = ReadString(baseAddress, offset, TwainConst.String64 - 2);
|
||||
break;
|
||||
case ItemType.Handle:
|
||||
val = new IntPtr(baseAddress.ToInt64() + offset);
|
||||
val = Marshal.ReadIntPtr(baseAddress, offset);
|
||||
break;
|
||||
}
|
||||
offset += GetItemTypeSize(type);
|
||||
@@ -93,6 +94,28 @@ namespace NTwain.Data
|
||||
//return sb.ToString();
|
||||
}
|
||||
|
||||
static readonly Dictionary<ItemType, int> __sizes = GenerateSizes();
|
||||
|
||||
private static Dictionary<ItemType, int> GenerateSizes()
|
||||
{
|
||||
var sizes = new Dictionary<ItemType, int>();
|
||||
sizes[ItemType.Int8] = 1;
|
||||
sizes[ItemType.UInt8] = 1;
|
||||
sizes[ItemType.Int16] = 2;
|
||||
sizes[ItemType.UInt16] = 2;
|
||||
sizes[ItemType.Bool] = 2;
|
||||
sizes[ItemType.Int32] = 4;
|
||||
sizes[ItemType.UInt32] = 4;
|
||||
sizes[ItemType.Fix32] = 4;
|
||||
sizes[ItemType.Frame] = 16;
|
||||
sizes[ItemType.String32] = TwainConst.String32;
|
||||
sizes[ItemType.String64] = TwainConst.String64;
|
||||
sizes[ItemType.String128] = TwainConst.String128;
|
||||
sizes[ItemType.String255] = TwainConst.String255;
|
||||
sizes[ItemType.Handle] = IntPtr.Size;
|
||||
|
||||
return sizes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the byte size of the item type.
|
||||
@@ -101,31 +124,9 @@ namespace NTwain.Data
|
||||
/// <returns></returns>
|
||||
public static int GetItemTypeSize(ItemType type)
|
||||
{
|
||||
switch (type)
|
||||
if (__sizes.ContainsKey(type))
|
||||
{
|
||||
case ItemType.Int8:
|
||||
case ItemType.UInt8:
|
||||
return 1;
|
||||
case ItemType.UInt16:
|
||||
case ItemType.Int16:
|
||||
case ItemType.Bool:
|
||||
return 2;
|
||||
case ItemType.Int32:
|
||||
case ItemType.UInt32:
|
||||
case ItemType.Fix32:
|
||||
return 4;
|
||||
case ItemType.Frame:
|
||||
return 16;
|
||||
case ItemType.String32:
|
||||
return TwainConst.String32;
|
||||
case ItemType.String64:
|
||||
return TwainConst.String64;
|
||||
case ItemType.String128:
|
||||
return TwainConst.String128;
|
||||
case ItemType.String255:
|
||||
return TwainConst.String255;
|
||||
case ItemType.Handle:
|
||||
return IntPtr.Size;
|
||||
return __sizes[type];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,24 +8,50 @@ namespace NTwain.Data
|
||||
/// <summary>
|
||||
/// Utility on converting (possibly bad) integer values to enum values.
|
||||
/// </summary>
|
||||
public static class ValueConverter
|
||||
public static class ValueExtensions
|
||||
{
|
||||
public static IList<T> CastToEnum<T>(this IEnumerable<object> list) where T : struct,IConvertible
|
||||
/// <summary>
|
||||
/// Casts a list of objects to a list of specified enum.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">The type of the enum.</typeparam>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <returns></returns>
|
||||
public static IList<TEnum> CastToEnum<TEnum>(this IEnumerable<object> list) where TEnum : struct,IConvertible
|
||||
{
|
||||
return list.CastToEnum<T>(true);
|
||||
return list.CastToEnum<TEnum>(true);
|
||||
}
|
||||
public static IList<T> CastToEnum<T>(this IEnumerable<object> list, bool tryUpperWord) where T : struct,IConvertible
|
||||
/// <summary>
|
||||
/// Casts a list of objects to a list of specified enum.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">The type of the enum.</typeparam>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="tryUpperWord">set to <c>true</c> for working with bad values.</param>
|
||||
/// <returns></returns>
|
||||
public static IList<TEnum> CastToEnum<TEnum>(this IEnumerable<object> list, bool tryUpperWord) where TEnum : struct,IConvertible
|
||||
{
|
||||
return list.Select(o => o.ConvertToEnum<T>(tryUpperWord)).ToList();
|
||||
return list.Select(o => o.ConvertToEnum<TEnum>(tryUpperWord)).ToList();
|
||||
}
|
||||
|
||||
public static T ConvertToEnum<T>(this object value) where T : struct,IConvertible
|
||||
/// <summary>
|
||||
/// Casts an objects to the specified enum.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">The type of the enum.</typeparam>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns></returns>
|
||||
public static TEnum ConvertToEnum<TEnum>(this object value) where TEnum : struct,IConvertible
|
||||
{
|
||||
return ConvertToEnum<T>(value, true);
|
||||
return ConvertToEnum<TEnum>(value, true);
|
||||
}
|
||||
public static T ConvertToEnum<T>(this object value, bool tryUpperWord) where T : struct,IConvertible
|
||||
/// <summary>
|
||||
/// Casts an objects to the specified enum.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">The type of the enum.</typeparam>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="tryUpperWord">if set to <c>true</c> [try upper word].</param>
|
||||
/// <returns></returns>
|
||||
public static TEnum ConvertToEnum<TEnum>(this object value, bool tryUpperWord) where TEnum : struct,IConvertible
|
||||
{
|
||||
var returnType = typeof(T);
|
||||
var returnType = typeof(TEnum);
|
||||
|
||||
// standard int values
|
||||
if (returnType.IsEnum)
|
||||
@@ -41,22 +67,22 @@ namespace NTwain.Data
|
||||
var enumVal = GetLowerWord(intVal);
|
||||
if (!Enum.IsDefined(returnType, enumVal))
|
||||
{
|
||||
return (T)Enum.ToObject(returnType, GetUpperWord(intVal));
|
||||
return (TEnum)Enum.ToObject(returnType, GetUpperWord(intVal));
|
||||
}
|
||||
}
|
||||
}
|
||||
// this may work better?
|
||||
return (T)Enum.ToObject(returnType, value);
|
||||
return (TEnum)Enum.ToObject(returnType, value);
|
||||
//// cast to underlying type first then to the enum
|
||||
//return (T)Convert.ChangeType(value, rawType);
|
||||
}
|
||||
else if (typeof(IConvertible).IsAssignableFrom(returnType))
|
||||
{
|
||||
// for regular integers and whatnot
|
||||
return (T)Convert.ChangeType(value, returnType, CultureInfo.InvariantCulture);
|
||||
return (TEnum)Convert.ChangeType(value, returnType, CultureInfo.InvariantCulture);
|
||||
}
|
||||
// return as-is from cap. if caller made a mistake then there should be exceptions
|
||||
return (T)value;
|
||||
return (TEnum)value;
|
||||
}
|
||||
|
||||
static ushort GetLowerWord(uint value)
|
||||
Reference in New Issue
Block a user