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 System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NTwain.Caps;
|
||||
|
||||
public record ValueContainer<TValue> where TValue : struct
|
||||
public record ValueContainer<TValue>
|
||||
{
|
||||
public TWON ContainerType { get; set; }
|
||||
|
||||
@@ -20,7 +21,7 @@ public record ValueContainer<TValue> where TValue : struct
|
||||
{
|
||||
return ContainerType switch
|
||||
{
|
||||
TWON.ONEVALUE => OneValue.HasValue ? ToEnumerable(OneValue.Value) : [],
|
||||
TWON.ONEVALUE => ToEnumerable(OneValue),
|
||||
TWON.ARRAY => ArrayValue ?? [],
|
||||
TWON.ENUMERATION => EnumValue?.Items ?? [],
|
||||
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;
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
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; } = [];
|
||||
|
||||
@@ -52,7 +58,7 @@ public record EnumValue<TValue> where TValue : struct
|
||||
public int DefaultIndex { get; set; }
|
||||
}
|
||||
|
||||
public record RangeValue<TValue> where TValue : struct
|
||||
public record RangeValue<TValue>
|
||||
{
|
||||
public TValue Min { get; set; }
|
||||
|
||||
|
||||
@@ -292,6 +292,17 @@ namespace NTwain.Data
|
||||
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
|
||||
{
|
||||
|
||||
@@ -87,7 +87,6 @@ namespace NTwain.Data
|
||||
/// <summary>
|
||||
/// Reads a boxed one value out of a cap. This can only be done once if memory is freed.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="cap"></param>
|
||||
/// <param name="memMgr"></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
|
||||
{
|
||||
var retVal = new Range<TValue>();
|
||||
|
||||
@@ -101,6 +101,46 @@ namespace NTwain
|
||||
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>
|
||||
/// Gets a CAP's raw default value.
|
||||
/// Caller will need to manually read and free the memory.
|
||||
@@ -155,6 +195,46 @@ namespace NTwain
|
||||
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>
|
||||
/// Gets a CAP's raw supported values.
|
||||
/// Caller will need to manually read and free the memory.
|
||||
@@ -226,6 +306,63 @@ namespace NTwain
|
||||
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>
|
||||
/// Gets a CAP's help text (description).
|
||||
/// This may not work due to unclear spec.
|
||||
|
||||
Reference in New Issue
Block a user