mirror of
https://github.com/soukoku/ntwain.git
synced 2025-11-24 08:47:06 +08:00
Attempt to make boxed version of cap value reads.
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
using NTwain.Data;
|
using NTwain.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace NTwain.Caps;
|
namespace NTwain.Caps;
|
||||||
|
|
||||||
public record ValueContainer<TValue> where TValue : struct
|
public record ValueContainer<TValue>
|
||||||
{
|
{
|
||||||
public TWON ContainerType { get; set; }
|
public TWON ContainerType { get; set; }
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ public record ValueContainer<TValue> where TValue : struct
|
|||||||
{
|
{
|
||||||
return ContainerType switch
|
return ContainerType switch
|
||||||
{
|
{
|
||||||
TWON.ONEVALUE => OneValue.HasValue ? ToEnumerable(OneValue.Value) : [],
|
TWON.ONEVALUE => ToEnumerable(OneValue),
|
||||||
TWON.ARRAY => ArrayValue ?? [],
|
TWON.ARRAY => ArrayValue ?? [],
|
||||||
TWON.ENUMERATION => EnumValue?.Items ?? [],
|
TWON.ENUMERATION => EnumValue?.Items ?? [],
|
||||||
TWON.RANGE => RangeValue != null ? GenerateRangeValues(RangeValue) : [],
|
TWON.RANGE => RangeValue != null ? GenerateRangeValues(RangeValue) : [],
|
||||||
@@ -28,22 +29,27 @@ public record ValueContainer<TValue> where TValue : struct
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<TValue> ToEnumerable(TValue value)
|
private IEnumerable<TValue> ToEnumerable(TValue? value)
|
||||||
{
|
{
|
||||||
|
if (value == null) yield break;
|
||||||
yield return value;
|
yield return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<TValue> GenerateRangeValues(RangeValue<TValue> range)
|
private IEnumerable<TValue> GenerateRangeValues(RangeValue<TValue> range)
|
||||||
{
|
{
|
||||||
var de = new DynamicEnumerator<TValue>(range.Min, range.Max, range.Step);
|
var dynamicType = typeof(DynamicEnumerator<>);
|
||||||
|
var genericType = dynamicType.MakeGenericType(typeof(TValue));
|
||||||
|
|
||||||
|
var de = Activator.CreateInstance(genericType, range.Min, range.Max, range.Step) as IEnumerator;
|
||||||
|
if (de == null) yield break;
|
||||||
while (de.MoveNext())
|
while (de.MoveNext())
|
||||||
{
|
{
|
||||||
yield return de.Current;
|
yield return (TValue)de.Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record EnumValue<TValue> where TValue : struct
|
public record EnumValue<TValue>
|
||||||
{
|
{
|
||||||
public TValue[] Items { get; set; } = [];
|
public TValue[] Items { get; set; } = [];
|
||||||
|
|
||||||
@@ -52,7 +58,7 @@ public record EnumValue<TValue> where TValue : struct
|
|||||||
public int DefaultIndex { get; set; }
|
public int DefaultIndex { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public record RangeValue<TValue> where TValue : struct
|
public record RangeValue<TValue>
|
||||||
{
|
{
|
||||||
public TValue Min { get; set; }
|
public TValue Min { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -292,6 +292,17 @@ namespace NTwain.Data
|
|||||||
return ((IEnumerable<TValue>)this).GetEnumerator();
|
return ((IEnumerable<TValue>)this).GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// A more dotnet-friendly representation of <see cref="TW_RANGE"/> with boxed values.
|
||||||
|
/// </summary>
|
||||||
|
public partial class RangeBoxed
|
||||||
|
{
|
||||||
|
public object MinValue;
|
||||||
|
public object MaxValue;
|
||||||
|
public object StepSize;
|
||||||
|
public object DefaultValue;
|
||||||
|
public object CurrentValue;
|
||||||
|
}
|
||||||
|
|
||||||
partial struct TW_FIX32 : IEquatable<TW_FIX32>, IConvertible
|
partial struct TW_FIX32 : IEquatable<TW_FIX32>, IConvertible
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ namespace NTwain.Data
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a boxed one value out of a cap. This can only be done once if memory is freed.
|
/// Reads a boxed one value out of a cap. This can only be done once if memory is freed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TValue"></typeparam>
|
|
||||||
/// <param name="cap"></param>
|
/// <param name="cap"></param>
|
||||||
/// <param name="memMgr"></param>
|
/// <param name="memMgr"></param>
|
||||||
/// <param name="freeMemory"></param>
|
/// <param name="freeMemory"></param>
|
||||||
@@ -414,6 +413,52 @@ namespace NTwain.Data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RangeBoxed ReadRangeBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
|
||||||
|
{
|
||||||
|
var retVal = new RangeBoxed();
|
||||||
|
|
||||||
|
if (cap.ConType != TWON.RANGE || cap.hContainer == IntPtr.Zero) return retVal;
|
||||||
|
|
||||||
|
var lockedPtr = memMgr.Lock(cap.hContainer);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TWTY itemType;
|
||||||
|
// Mac has a level of indirection and a different structure (ick)...
|
||||||
|
if (TWPlatform.IsMacOSX)
|
||||||
|
{
|
||||||
|
itemType = (TWTY)Marshal.ReadInt32(lockedPtr);
|
||||||
|
lockedPtr += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Windows or the 2.4+ Linux DSM...
|
||||||
|
itemType = (TWTY)Marshal.ReadInt16(lockedPtr);
|
||||||
|
lockedPtr += 2;
|
||||||
|
}
|
||||||
|
retVal.MinValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
|
||||||
|
lockedPtr += 4;
|
||||||
|
retVal.MaxValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
|
||||||
|
lockedPtr += 4;
|
||||||
|
retVal.StepSize = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
|
||||||
|
lockedPtr += 4;
|
||||||
|
retVal.CurrentValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
|
||||||
|
lockedPtr += 4;
|
||||||
|
retVal.DefaultValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
|
||||||
|
lockedPtr += 4;
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
|
||||||
|
if (freeMemory)
|
||||||
|
{
|
||||||
|
memMgr.Free(cap.hContainer);
|
||||||
|
cap.hContainer = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Range<TValue> ReadRange<TValue>(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true) where TValue : struct
|
public static Range<TValue> ReadRange<TValue>(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true) where TValue : struct
|
||||||
{
|
{
|
||||||
var retVal = new Range<TValue>();
|
var retVal = new Range<TValue>();
|
||||||
|
|||||||
@@ -101,6 +101,46 @@ namespace NTwain
|
|||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a CAP's current value as boxed values. This is a simplified version that doesn't require
|
||||||
|
/// manual reading, but may or may not work.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cap"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public STS GetCapCurrentBoxed(CAP cap, out List<object> value)
|
||||||
|
{
|
||||||
|
value = new List<object>();
|
||||||
|
var sts = GetCapCurrent(cap, out TW_CAPABILITY twcap);
|
||||||
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
|
{
|
||||||
|
switch (twcap.ConType)
|
||||||
|
{
|
||||||
|
case TWON.ONEVALUE:
|
||||||
|
var read = twcap.ReadOneValueBoxed(this);
|
||||||
|
if (read != null) value.Add(read);
|
||||||
|
break;
|
||||||
|
case TWON.ENUMERATION:
|
||||||
|
var twenum = twcap.ReadEnumerationBoxed(this);
|
||||||
|
if (twenum.Items != null && twenum.CurrentIndex < twenum.Items.Length)
|
||||||
|
{
|
||||||
|
value.Add(twenum.Items[twenum.CurrentIndex]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TWON.RANGE:
|
||||||
|
value.Add(twcap.ReadRangeBoxed(this).CurrentValue);
|
||||||
|
break;
|
||||||
|
case TWON.ARRAY:
|
||||||
|
var twarr = twcap.ReadArrayBoxed(this);
|
||||||
|
if (twarr != null && twarr.Count > 0) value.AddRange(twarr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
twcap.Free(this); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a CAP's raw default value.
|
/// Gets a CAP's raw default value.
|
||||||
/// Caller will need to manually read and free the memory.
|
/// Caller will need to manually read and free the memory.
|
||||||
@@ -155,6 +195,46 @@ namespace NTwain
|
|||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a CAP's default value. This is a simplified version that doesn't require
|
||||||
|
/// manual reading, but may or may not work.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cap"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public STS GetCapDefaultBoxed(CAP cap, out List<object> value)
|
||||||
|
{
|
||||||
|
value = new List<object>();
|
||||||
|
var sts = GetCapDefault(cap, out TW_CAPABILITY twcap);
|
||||||
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
|
{
|
||||||
|
switch (twcap.ConType)
|
||||||
|
{
|
||||||
|
case TWON.ONEVALUE:
|
||||||
|
var read = twcap.ReadOneValueBoxed(this);
|
||||||
|
if (read != null) value.Add(read);
|
||||||
|
break;
|
||||||
|
case TWON.ENUMERATION:
|
||||||
|
var twenum = twcap.ReadEnumerationBoxed(this);
|
||||||
|
if (twenum.Items != null && twenum.DefaultIndex < twenum.Items.Length)
|
||||||
|
{
|
||||||
|
value.Add(twenum.Items[twenum.DefaultIndex]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TWON.RANGE:
|
||||||
|
value.Add(twcap.ReadRangeBoxed(this).DefaultValue);
|
||||||
|
break;
|
||||||
|
case TWON.ARRAY:
|
||||||
|
var twarr = twcap.ReadArrayBoxed(this);
|
||||||
|
if (twarr != null && twarr.Count > 0) value.AddRange(twarr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
twcap.Free(this); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a CAP's raw supported values.
|
/// Gets a CAP's raw supported values.
|
||||||
/// Caller will need to manually read and free the memory.
|
/// Caller will need to manually read and free the memory.
|
||||||
@@ -226,6 +306,63 @@ namespace NTwain
|
|||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a CAP's supported values. This is a simplified version that doesn't require
|
||||||
|
/// manual reading, but may or may not work.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cap"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public STS GetCapValuesBoxed(CAP cap, out ValueContainer<object> value)
|
||||||
|
{
|
||||||
|
value = new ValueContainer<object> { ContainerType = TWON.DONTCARE };
|
||||||
|
var sts = GetCapValues(cap, out TW_CAPABILITY twcap);
|
||||||
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
|
{
|
||||||
|
value.ContainerType = twcap.ConType;
|
||||||
|
switch (twcap.ConType)
|
||||||
|
{
|
||||||
|
case TWON.ONEVALUE:
|
||||||
|
value.OneValue = twcap.ReadOneValueBoxed(this);
|
||||||
|
break;
|
||||||
|
case TWON.ENUMERATION:
|
||||||
|
var twenum = twcap.ReadEnumerationBoxed(this);
|
||||||
|
if (twenum.Items != null)
|
||||||
|
{
|
||||||
|
value.EnumValue = new EnumValue<object>
|
||||||
|
{
|
||||||
|
CurrentIndex = twenum.CurrentIndex,
|
||||||
|
DefaultIndex = twenum.DefaultIndex,
|
||||||
|
Items = twenum.Items
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TWON.RANGE:
|
||||||
|
var range = twcap.ReadRangeBoxed(this);
|
||||||
|
value.RangeValue = new RangeValue<object>
|
||||||
|
{
|
||||||
|
Min = range.MinValue,
|
||||||
|
Max = range.MaxValue,
|
||||||
|
Step = range.StepSize,
|
||||||
|
DefaultValue = range.DefaultValue,
|
||||||
|
CurrentValue = range.CurrentValue
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case TWON.ARRAY:
|
||||||
|
var twarr = twcap.ReadArrayBoxed(this);
|
||||||
|
if (twarr != null)
|
||||||
|
{
|
||||||
|
value.ArrayValue = twarr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
twcap.Free(this); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a CAP's help text (description).
|
/// Gets a CAP's help text (description).
|
||||||
/// This may not work due to unclear spec.
|
/// This may not work due to unclear spec.
|
||||||
|
|||||||
Reference in New Issue
Block a user