Start resurrecting old value reader/writer.

This commit is contained in:
Eugene Wang 2023-04-04 08:17:46 -04:00
parent 5678fd3e77
commit 9e59e2355d
5 changed files with 1064 additions and 1085 deletions

View File

@ -1,444 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using TWAINWorkingGroup;
using static TWAINWorkingGroup.TWAIN;
namespace NTwain
{
/// <summary>
/// Contains methods for reading pointers into various things.
/// </summary>
public static class ValueReader
{
/// <summary>
/// Reads pointer as UTF8 string.
/// </summary>
/// <param name="intPtr">Pointer to string.</param>
/// <param name="length">Number of bytes to read.</param>
/// <returns></returns>
public static unsafe string PtrToStringUTF8(IntPtr intPtr, int length)
{
if (intPtr == IntPtr.Zero) throw new ArgumentNullException(nameof(intPtr));
if (length == 0) throw new ArgumentOutOfRangeException(nameof(length), length, "Length must be greater than 0.");
//// safe method with 2 copies
//var bytes = new byte[length];
//Marshal.Copy(intPtr, bytes, 0, length);
//return Encoding.UTF8.GetString(bytes);
// unsafe method with 1 copy (does it work?)
sbyte* bytes = (sbyte*)intPtr;
var str = new string(bytes, 0, length, Encoding.UTF8);
return str;
}
// most of these are modified from the original TWAIN.CapabilityToCsv()
public static TValue ReadOneValueContainer<TValue>(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
{
if (cap.hContainer == IntPtr.Zero) return default;
var lockedPtr = twain.DsmMemLock(cap.hContainer);
try
{
TWTY itemType;
// Mac has a level of indirection and a different structure (ick)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var onevalue = MarshalTo<TW_ONEVALUE_MACOSX>(lockedPtr);
itemType = (TWTY)onevalue.ItemType;
lockedPtr += Marshal.SizeOf(onevalue);
}
else
{
// Crack the container...
var onevalue = MarshalTo<TW_ONEVALUE>(lockedPtr);
itemType = onevalue.ItemType;
lockedPtr += Marshal.SizeOf(onevalue);
}
return ReadContainerData<TValue>(lockedPtr, itemType, 0);
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
}
}
public static Enumeration<TValue> ReadEnumerationContainer<TValue>(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
{
Enumeration<TValue> retVal = new Enumeration<TValue>();
if (cap.hContainer == IntPtr.Zero) return retVal;
var lockedPtr = twain.DsmMemLock(cap.hContainer);
try
{
TWTY itemType;
int count = 0;
// Mac has a level of indirection and a different structure (ick)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var twenumerationmacosx = MarshalTo<TW_ENUMERATION_MACOSX>(lockedPtr);
itemType = (TWTY)twenumerationmacosx.ItemType;
count = (int)twenumerationmacosx.NumItems;
retVal.DefaultIndex = (int)twenumerationmacosx.DefaultIndex;
retVal.CurrentIndex = (int)twenumerationmacosx.CurrentIndex;
lockedPtr += Marshal.SizeOf(twenumerationmacosx);
}
// Windows or the 2.4+ Linux DSM...
else if (TWAIN.GetPlatform() == Platform.WINDOWS || ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
{
// Crack the container...
var twenumeration = MarshalTo<TW_ENUMERATION>(lockedPtr);
itemType = twenumeration.ItemType;
count = (int)twenumeration.NumItems;
retVal.DefaultIndex = (int)twenumeration.DefaultIndex;
retVal.CurrentIndex = (int)twenumeration.CurrentIndex;
lockedPtr += Marshal.SizeOf(twenumeration);
}
// The -2.3 Linux DSM...
else if (twain.m_blFound020302Dsm64bit && (twain.m_linuxdsm == TWAIN.LinuxDsm.Is020302Dsm64bit))
{
// Crack the container...
var twenumerationlinux64 = MarshalTo<TW_ENUMERATION_LINUX64>(lockedPtr);
itemType = twenumerationlinux64.ItemType;
count = (int)twenumerationlinux64.NumItems;
retVal.DefaultIndex = (int)twenumerationlinux64.DefaultIndex;
retVal.CurrentIndex = (int)twenumerationlinux64.CurrentIndex;
lockedPtr += Marshal.SizeOf(twenumerationlinux64);
}
// This shouldn't be possible, but what the hey...
else
{
Log.Error("This is serious, you win a cookie for getting here...");
return retVal;
}
retVal.Items = new TValue[count];
for (var i = 0; i < count; i++)
{
retVal.Items[i] = ReadContainerData<TValue>(lockedPtr, itemType, i);
}
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
}
return retVal;
}
public static IList<TValue> ReadArrayContainer<TValue>(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
{
if (cap.hContainer == IntPtr.Zero) return EmptyArray<TValue>.Value;
var lockedPtr = twain.DsmMemLock(cap.hContainer);
try
{
TWTY itemType;
uint count;
// Mac has a level of indirection and a different structure (ick)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var twarraymacosx = MarshalTo<TW_ARRAY_MACOSX>(lockedPtr);
itemType = (TWTY)twarraymacosx.ItemType;
count = twarraymacosx.NumItems;
lockedPtr += Marshal.SizeOf(twarraymacosx);
}
else
{
// Crack the container...
var twarray = MarshalTo<TW_ARRAY>(lockedPtr);
itemType = twarray.ItemType;
count = twarray.NumItems;
lockedPtr += Marshal.SizeOf(twarray);
}
var arr = new TValue[count];
for (var i = 0; i < count; i++)
{
arr[i] = ReadContainerData<TValue>(lockedPtr, itemType, i);
}
return arr;
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
}
}
public static Range<TValue> ReadRangeContainer<TValue>(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
{
var retVal = new Range<TValue>();
if (cap.hContainer == IntPtr.Zero) return retVal;
var lockedPtr = twain.DsmMemLock(cap.hContainer);
try
{
TW_RANGE twrange = default;
TW_RANGE_FIX32 twrangefix32 = default;
// Mac has a level of indirection and a different structure (ick)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
var twrangemacosx = MarshalTo<TW_RANGE_MACOSX>(lockedPtr);
var twrangefix32macosx = MarshalTo<TW_RANGE_FIX32_MACOSX>(lockedPtr);
twrange.ItemType = (TWTY)twrangemacosx.ItemType;
twrange.MinValue = twrangemacosx.MinValue;
twrange.MaxValue = twrangemacosx.MaxValue;
twrange.StepSize = twrangemacosx.StepSize;
twrange.DefaultValue = twrangemacosx.DefaultValue;
twrange.CurrentValue = twrangemacosx.CurrentValue;
twrangefix32.ItemType = (TWTY)twrangefix32macosx.ItemType;
twrangefix32.MinValue = twrangefix32macosx.MinValue;
twrangefix32.MaxValue = twrangefix32macosx.MaxValue;
twrangefix32.StepSize = twrangefix32macosx.StepSize;
twrangefix32.DefaultValue = twrangefix32macosx.DefaultValue;
twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
}
// Windows or the 2.4+ Linux DSM...
else if (TWAIN.GetPlatform() == Platform.WINDOWS || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
{
twrange = MarshalTo<TW_RANGE>(lockedPtr);
twrangefix32 = MarshalTo<TW_RANGE_FIX32>(lockedPtr);
}
// The -2.3 Linux DSM...
else
{
var twrangelinux64 = MarshalTo<TW_RANGE_LINUX64>(lockedPtr);
var twrangefix32macosx = MarshalTo<TW_RANGE_FIX32_MACOSX>(lockedPtr);
twrange.ItemType = twrangelinux64.ItemType;
twrange.MinValue = (uint)twrangelinux64.MinValue;
twrange.MaxValue = (uint)twrangelinux64.MaxValue;
twrange.StepSize = (uint)twrangelinux64.StepSize;
twrange.DefaultValue = (uint)twrangelinux64.DefaultValue;
twrange.CurrentValue = (uint)twrangelinux64.CurrentValue;
twrangefix32.ItemType = (TWTY)twrangefix32macosx.ItemType;
twrangefix32.MinValue = twrangefix32macosx.MinValue;
twrangefix32.MaxValue = twrangefix32macosx.MaxValue;
twrangefix32.StepSize = twrangefix32macosx.StepSize;
twrangefix32.DefaultValue = twrangefix32macosx.DefaultValue;
twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
}
switch (twrange.ItemType)
{
// use dynamic since I know they fit the type.
case TWTY.FIX32:
retVal.MinValue = (dynamic)twrangefix32.MinValue;
retVal.MaxValue = (dynamic)twrangefix32.MaxValue;
retVal.StepSize = (dynamic)twrangefix32.StepSize;
retVal.CurrentValue = (dynamic)twrangefix32.CurrentValue;
retVal.DefaultValue = (dynamic)twrangefix32.DefaultValue;
break;
case TWTY.INT8:
case TWTY.UINT8:
case TWTY.INT16:
case TWTY.BOOL:
case TWTY.UINT16:
case TWTY.INT32:
case TWTY.UINT32:
retVal.MinValue = (dynamic)twrange.MinValue;
retVal.MaxValue = (dynamic)twrange.MaxValue;
retVal.StepSize = (dynamic)twrange.StepSize;
retVal.CurrentValue = (dynamic)twrange.CurrentValue;
retVal.DefaultValue = (dynamic)twrange.DefaultValue;
break;
default:
throw new NotSupportedException($"The value type {twrange.ItemType} is not supported as range.");
}
return retVal;
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
}
}
/// <summary>
/// Read the one value of a cap as string. Only STR* and HANDLE types are supported.
/// </summary>
/// <param name="twain"></param>
/// <param name="cap"></param>
/// <param name="freeMemory"></param>
/// <returns></returns>
public static string ReadOneValueContainerString(TWAIN twain, TW_CAPABILITY cap, bool freeMemory = true)
{
if (cap.hContainer == IntPtr.Zero) return null;
var lockedPtr = twain.DsmMemLock(cap.hContainer);
try
{
if (cap.ConType == TWON.ONEVALUE)
{
TWTY itemType;
// Mac has a level of indirection and a different structure (ick)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var onevalue = MarshalTo<TW_ONEVALUE_MACOSX>(lockedPtr);
itemType = (TWTY)onevalue.ItemType;
lockedPtr += Marshal.SizeOf(onevalue);
}
else
{
// Crack the container...
var onevalue = MarshalTo<TW_ONEVALUE>(lockedPtr);
itemType = onevalue.ItemType;
lockedPtr += Marshal.SizeOf(onevalue);
}
switch (itemType)
{
case TWTY.STR32:
return MarshalTo<TW_STR32>(lockedPtr).ToString();
case TWTY.STR64:
return MarshalTo<TW_STR64>(lockedPtr).ToString();
case TWTY.STR128:
return MarshalTo<TW_STR128>(lockedPtr).ToString();
case TWTY.STR255:
return MarshalTo<TW_STR255>(lockedPtr).ToString();
case TWTY.HANDLE:
// null-terminated and encoded string.
// good chance this ain't right.
using (var stream = new MemoryStream())
{
byte read = Marshal.ReadByte(lockedPtr);
while (read != 0)
{
stream.WriteByte(read);
read = Marshal.ReadByte(lockedPtr);
lockedPtr += 1;
}
// which one?
return Encoding.Unicode.GetString(Encoding.Convert(Language.GetEncoding(), Encoding.Unicode, stream.ToArray()));
//return Language.GetEncoding().GetString(stream.ToArray());
}
}
}
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer);
if (freeMemory) twain.DsmMemFree(ref cap.hContainer);
}
return null;
}
/// <summary>
/// Read the container pointer content.
/// </summary>
/// <param name="intptr">A locked pointer to the container's data pointer. If data is array this is the 0th item.</param>
/// <param name="type">The twain type.</param>
/// <param name="itemIndex">Index of the item if pointer is array.</param>
/// <returns></returns>
static TValue ReadContainerData<TValue>(IntPtr intptr, TWTY type, int itemIndex) where TValue : struct
{
var isEnum = typeof(TValue).IsEnum;
switch (type)
{
default:
throw new NotSupportedException($"Unsupported item type {type} for reading.");
// TODO: verify if needs to read int32 for small types
case TWTY.INT8:
intptr += 1 * itemIndex;
if (isEnum)
{
return NumericToEnum<sbyte, TValue>(MarshalTo<sbyte>(intptr));
}
return MarshalTo<TValue>(intptr);
case TWTY.UINT8:
intptr += 1 * itemIndex;
if (isEnum)
{
return NumericToEnum<byte, TValue>(MarshalTo<byte>(intptr));
}
return MarshalTo<TValue>(intptr);
case TWTY.INT16:
intptr += 2 * itemIndex;
if (isEnum)
{
return NumericToEnum<short, TValue>(MarshalTo<short>(intptr));
}
return MarshalTo<TValue>(intptr);
case TWTY.BOOL:
case TWTY.UINT16:
intptr += 2 * itemIndex;
if (isEnum)
{
return NumericToEnum<ushort, TValue>(MarshalTo<ushort>(intptr));
}
return MarshalTo<TValue>(intptr);
case TWTY.INT32:
intptr += 4 * itemIndex;
if (isEnum)
{
return NumericToEnum<int, TValue>(MarshalTo<int>(intptr));
}
return MarshalTo<TValue>(intptr);
case TWTY.UINT32:
intptr += 4 * itemIndex;
if (isEnum)
{
return NumericToEnum<uint, TValue>(MarshalTo<uint>(intptr));
}
return MarshalTo<TValue>(intptr);
case TWTY.FIX32:
intptr += 4 * itemIndex;
return MarshalTo<TValue>(intptr);
case TWTY.FRAME:
intptr += 16 * itemIndex;
return MarshalTo<TValue>(intptr);
case TWTY.STR32:
intptr += TW_STR32.Size * itemIndex;
return MarshalTo<TValue>(intptr);
case TWTY.STR64:
intptr += TW_STR64.Size * itemIndex;
return MarshalTo<TValue>(intptr);
case TWTY.STR128:
intptr += TW_STR128.Size * itemIndex;
return MarshalTo<TValue>(intptr);
case TWTY.STR255:
intptr += TW_STR255.Size * itemIndex;
return MarshalTo<TValue>(intptr);
}
}
static TEnum NumericToEnum<TNumber, TEnum>(TNumber num) where TEnum : struct
{
// some caps returns a data type that's not the underlying datatype for the enum
// so best way is to ToString() it and parse it as the enum type.
var str = num.ToString();
if (Enum.TryParse(str, out TEnum parsed))
{
return parsed;
}
return default;
}
static T MarshalTo<T>(IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T));
}
}

View File

@ -1,617 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using TWAINWorkingGroup;
using static TWAINWorkingGroup.TWAIN;
namespace NTwain
{
/// <summary>
/// Contains methods for writing vairous things to pointers.
/// </summary>
public static class ValueWriter
{
/// <summary>
/// Allocates and copies the string value into a pointer in UTF8 that's null-terminated.
/// </summary>
/// <param name="twain"></param>
/// <param name="value"></param>
/// <param name="length">Actual number of bytes used to encode the string without the null.</param>
/// <returns></returns>
public static unsafe IntPtr StringToPtrUTF8(TWAIN twain, string value, out int length)
{
if (value == null)
{
length = 0;
return IntPtr.Zero;
}
var utf8 = Encoding.UTF8;
length = utf8.GetByteCount(value);
var ptr = twain.DsmMemAlloc((uint)length + 1); // +1 for null-terminated
// TODO: test if this works
int written;
byte* bytes = (byte*)ptr;
try
{
// fixed for managed pointer
fixed (char* firstChar = value)
{
written = Encoding.UTF8.GetBytes(firstChar, value.Length, bytes, length);
}
bytes[written] = 0;
}
catch
{
// just in case
if (ptr != IntPtr.Zero) twain.DsmMemFree(ref ptr);
throw;
}
return ptr;
}
// most of these are modified from the original TWAIN.CsvToCapability()
public static void WriteOneValueContainer<TValue>(TWAIN twain, ref TW_CAPABILITY twCap, TValue value) where TValue : struct
{
IntPtr lockedPtr = IntPtr.Zero;
try
{
if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer);
TWTY itemType = GetItemType<TValue>();
// Allocate the container (go for worst case, which is TW_STR255)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE_MACOSX)) + Marshal.SizeOf(default(TW_STR255))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
TW_ONEVALUE_MACOSX twonevaluemacosx = default;
twonevaluemacosx.ItemType = (uint)itemType;
Marshal.StructureToPtr(twonevaluemacosx, lockedPtr, false);
lockedPtr += Marshal.SizeOf(twonevaluemacosx);
}
else
{
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE)) + Marshal.SizeOf(default(TW_STR255))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
TW_ONEVALUE twonevalue = default;
twonevalue.ItemType = itemType;
Marshal.StructureToPtr(twonevalue, lockedPtr, false);
lockedPtr += Marshal.SizeOf(twonevalue);
}
WriteContainerData(lockedPtr, itemType, value, 0);
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(twCap.hContainer);
}
}
public static void WriteArrayContainer<TValue>(TWAIN twain, ref TW_CAPABILITY twCap, TValue[] values) where TValue : struct
{
IntPtr lockedPtr = IntPtr.Zero;
try
{
if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer);
TWTY itemType = GetItemType<TValue>();
// Allocate the container (go for worst case, which is TW_STR255)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ARRAY_MACOSX)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
// Set the meta data...
TW_ARRAY_MACOSX twarraymacosx = default;
twarraymacosx.ItemType = (uint)itemType;
twarraymacosx.NumItems = (uint)values.Length;
Marshal.StructureToPtr(twarraymacosx, lockedPtr, false);
// Get the pointer to the ItemList...
lockedPtr += Marshal.SizeOf(twarraymacosx);
}
else
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ARRAY)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
// Set the meta data...
TW_ARRAY twarray = default;
twarray.ItemType = itemType;
twarray.NumItems = (uint)values.Length;
Marshal.StructureToPtr(twarray, lockedPtr, false);
// Get the pointer to the ItemList...
lockedPtr += Marshal.SizeOf(twarray);
}
// Set the ItemList...
for (var i = 0; i < values.Length; i++)
{
WriteContainerData(lockedPtr, itemType, values[i], i);
}
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(twCap.hContainer);
}
}
public static void WriteEnumContainer<TValue>(TWAIN twain, ref TW_CAPABILITY twCap, Enumeration<TValue> value) where TValue : struct
{
IntPtr lockedPtr = IntPtr.Zero;
try
{
if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer);
TWTY itemType = GetItemType<TValue>();
// Allocate the container (go for worst case, which is TW_STR255)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_MACOSX)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
// Set the meta data...
TW_ENUMERATION_MACOSX twenumerationmacosx = default;
twenumerationmacosx.ItemType = (uint)itemType;
twenumerationmacosx.NumItems = (uint)value.Items.Length;
twenumerationmacosx.CurrentIndex = (uint)value.CurrentIndex;
twenumerationmacosx.DefaultIndex = (uint)value.DefaultIndex;
Marshal.StructureToPtr(twenumerationmacosx, lockedPtr, false);
// Get the pointer to the ItemList...
lockedPtr += Marshal.SizeOf(twenumerationmacosx);
}
// Windows or the 2.4+ Linux DSM...
else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
(twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
// Set the meta data...
TW_ENUMERATION twenumeration = default;
twenumeration.ItemType = itemType;
twenumeration.NumItems = (uint)value.Items.Length;
twenumeration.CurrentIndex = (uint)value.CurrentIndex;
twenumeration.DefaultIndex = (uint)value.CurrentIndex;
Marshal.StructureToPtr(twenumeration, lockedPtr, false);
// Get the pointer to the ItemList...
lockedPtr += Marshal.SizeOf(twenumeration);
}
// The -2.3 Linux DSM...
else
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_LINUX64)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
// Set the meta data...
TW_ENUMERATION_LINUX64 twenumerationlinux64 = default;
twenumerationlinux64.ItemType = itemType;
twenumerationlinux64.NumItems = (ulong)value.Items.Length;
twenumerationlinux64.CurrentIndex = (ulong)value.CurrentIndex;
twenumerationlinux64.DefaultIndex = (ulong)value.CurrentIndex;
Marshal.StructureToPtr(twenumerationlinux64, lockedPtr, false);
// Get the pointer to the ItemList...
lockedPtr += Marshal.SizeOf(twenumerationlinux64);
}
// Set the ItemList...
for (var i = 0; i < value.Items.Length; i++)
{
WriteContainerData(lockedPtr, itemType, value.Items[i], i);
}
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(twCap.hContainer);
}
}
public static void WriteRangeContainer<TValue>(TWAIN twain, ref TW_CAPABILITY twCap, Range<TValue> value) where TValue : struct
{
IntPtr lockedPtr = IntPtr.Zero;
try
{
if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer);
TWTY itemType = GetItemType<TValue>();
// Allocate the container (go for worst case, which is TW_STR255)...
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_RANGE_MACOSX))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
}
// Windows or the 2.4+ Linux DSM...
else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
(twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_RANGE))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
}
// The -2.3 Linux DSM...
else
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_RANGE_LINUX64))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
}
// Set the Item...
WriteRangeValues(twain, lockedPtr, itemType, value);
}
finally
{
if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(twCap.hContainer);
}
}
static void WriteRangeValues<TValue>(TWAIN twain, IntPtr lockedPtr, TWTY itemType, Range<TValue> value) where TValue : struct
{
// TODO: reduce this later
TW_RANGE twrange = default;
TW_RANGE_MACOSX twrangemacosx = default;
TW_RANGE_LINUX64 twrangelinux64 = default;
switch (itemType)
{
default:
throw new NotSupportedException($"{itemType} is not supported for range.");
case TWTY.INT8:
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = (uint)Convert.ToSByte(value.MinValue);
twrangemacosx.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
twrangemacosx.StepSize = (uint)Convert.ToSByte(value.StepSize);
twrangemacosx.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
twrangemacosx.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
}
else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
{
twrange.ItemType = itemType;
twrange.MinValue = (uint)Convert.ToSByte(value.MinValue);
twrange.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
twrange.StepSize = (uint)Convert.ToSByte(value.StepSize);
twrange.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
twrange.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
Marshal.StructureToPtr(twrange, lockedPtr, false);
}
else
{
twrangelinux64.ItemType = itemType;
twrangelinux64.MinValue = (uint)Convert.ToSByte(value.MinValue);
twrangelinux64.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
twrangelinux64.StepSize = (uint)Convert.ToSByte(value.StepSize);
twrangelinux64.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
twrangelinux64.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
}
break;
case TWTY.UINT8:
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = Convert.ToByte(value.MinValue);
twrangemacosx.MaxValue = Convert.ToByte(value.MaxValue);
twrangemacosx.StepSize = Convert.ToByte(value.StepSize);
twrangemacosx.DefaultValue = Convert.ToByte(value.DefaultValue);
twrangemacosx.CurrentValue = Convert.ToByte(value.CurrentValue);
Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
}
else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
{
twrange.ItemType = itemType;
twrange.MinValue = Convert.ToByte(value.MinValue);
twrange.MaxValue = Convert.ToByte(value.MaxValue);
twrange.StepSize = Convert.ToByte(value.StepSize);
twrange.DefaultValue = Convert.ToByte(value.DefaultValue);
twrange.CurrentValue = Convert.ToByte(value.CurrentValue);
Marshal.StructureToPtr(twrange, lockedPtr, false);
}
else
{
twrangelinux64.ItemType = itemType;
twrangelinux64.MinValue = Convert.ToByte(value.MinValue);
twrangelinux64.MaxValue = Convert.ToByte(value.MaxValue);
twrangelinux64.StepSize = Convert.ToByte(value.StepSize);
twrangelinux64.DefaultValue = Convert.ToByte(value.DefaultValue);
twrangelinux64.CurrentValue = Convert.ToByte(value.CurrentValue);
Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
}
break;
case TWTY.INT16:
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = (uint)Convert.ToInt16(value.MinValue);
twrangemacosx.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
twrangemacosx.StepSize = (uint)Convert.ToInt16(value.StepSize);
twrangemacosx.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
twrangemacosx.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
}
else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
{
twrange.ItemType = itemType;
twrange.MinValue = (uint)Convert.ToInt16(value.MinValue);
twrange.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
twrange.StepSize = (uint)Convert.ToInt16(value.StepSize);
twrange.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
twrange.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
Marshal.StructureToPtr(twrange, lockedPtr, false);
}
else
{
twrangelinux64.ItemType = itemType;
twrangelinux64.MinValue = (uint)Convert.ToInt16(value.MinValue);
twrangelinux64.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
twrangelinux64.StepSize = (uint)Convert.ToInt16(value.StepSize);
twrangelinux64.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
twrangelinux64.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
}
break;
case TWTY.BOOL:
case TWTY.UINT16:
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = Convert.ToUInt16(value.MinValue);
twrangemacosx.MaxValue = Convert.ToUInt16(value.MaxValue);
twrangemacosx.StepSize = Convert.ToUInt16(value.StepSize);
twrangemacosx.DefaultValue = Convert.ToUInt16(value.DefaultValue);
twrangemacosx.CurrentValue = Convert.ToUInt16(value.CurrentValue);
Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
}
else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
{
twrange.ItemType = itemType;
twrange.MinValue = Convert.ToUInt16(value.MinValue);
twrange.MaxValue = Convert.ToUInt16(value.MaxValue);
twrange.StepSize = Convert.ToUInt16(value.StepSize);
twrange.DefaultValue = Convert.ToUInt16(value.DefaultValue);
twrange.CurrentValue = Convert.ToUInt16(value.CurrentValue);
Marshal.StructureToPtr(twrange, lockedPtr, false);
}
else
{
twrangelinux64.ItemType = itemType;
twrangelinux64.MinValue = Convert.ToUInt16(value.MinValue);
twrangelinux64.MaxValue = Convert.ToUInt16(value.MaxValue);
twrangelinux64.StepSize = Convert.ToUInt16(value.StepSize);
twrangelinux64.DefaultValue = Convert.ToUInt16(value.DefaultValue);
twrangelinux64.CurrentValue = Convert.ToUInt16(value.CurrentValue);
Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
}
break;
case TWTY.INT32:
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = (uint)Convert.ToInt32(value.MinValue);
twrangemacosx.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
twrangemacosx.StepSize = (uint)Convert.ToInt32(value.StepSize);
twrangemacosx.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
twrangemacosx.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
}
else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
{
twrange.ItemType = itemType;
twrange.MinValue = (uint)Convert.ToInt32(value.MinValue);
twrange.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
twrange.StepSize = (uint)Convert.ToInt32(value.StepSize);
twrange.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
twrange.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
Marshal.StructureToPtr(twrange, lockedPtr, false);
}
else
{
twrangelinux64.ItemType = itemType;
twrangelinux64.MinValue = (uint)Convert.ToInt32(value.MinValue);
twrangelinux64.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
twrangelinux64.StepSize = (uint)Convert.ToInt32(value.StepSize);
twrangelinux64.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
twrangelinux64.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
}
break;
case TWTY.UINT32:
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = Convert.ToUInt32(value.MinValue);
twrangemacosx.MaxValue = Convert.ToUInt32(value.MaxValue);
twrangemacosx.StepSize = Convert.ToUInt32(value.StepSize);
twrangemacosx.DefaultValue = Convert.ToUInt32(value.DefaultValue);
twrangemacosx.CurrentValue = Convert.ToUInt32(value.CurrentValue);
Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
}
else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
{
twrange.ItemType = itemType;
twrange.MinValue = Convert.ToUInt32(value.MinValue);
twrange.MaxValue = Convert.ToUInt32(value.MaxValue);
twrange.StepSize = Convert.ToUInt32(value.StepSize);
twrange.DefaultValue = Convert.ToUInt32(value.DefaultValue);
twrange.CurrentValue = Convert.ToUInt32(value.CurrentValue);
Marshal.StructureToPtr(twrange, lockedPtr, false);
}
else
{
twrangelinux64.ItemType = itemType;
twrangelinux64.MinValue = Convert.ToUInt32(value.MinValue);
twrangelinux64.MaxValue = Convert.ToUInt32(value.MaxValue);
twrangelinux64.StepSize = Convert.ToUInt32(value.StepSize);
twrangelinux64.DefaultValue = Convert.ToUInt32(value.DefaultValue);
twrangelinux64.CurrentValue = Convert.ToUInt32(value.CurrentValue);
Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
}
break;
case TWTY.FIX32:
double min = Convert.ToDouble(value.MinValue);
double max = Convert.ToDouble(value.MaxValue);
double step = Convert.ToDouble(value.StepSize);
double def = Convert.ToDouble(value.DefaultValue);
double current = Convert.ToDouble(value.CurrentValue);
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
TW_RANGE_FIX32_MACOSX twrangefix32macosx = default;
twrangefix32macosx.ItemType = (uint)itemType;
twrangefix32macosx.MinValue = new TW_FIX32(min);
twrangefix32macosx.MaxValue = new TW_FIX32(max);
twrangefix32macosx.StepSize = new TW_FIX32(step);
twrangefix32macosx.DefaultValue = new TW_FIX32(def);
twrangefix32macosx.CurrentValue = new TW_FIX32(current);
Marshal.StructureToPtr(twrangefix32macosx, lockedPtr, false);
}
else
{
TW_RANGE_FIX32 twrangefix32 = default;
twrangefix32.ItemType = itemType;
twrangefix32.MinValue = new TW_FIX32(min);
twrangefix32.MaxValue = new TW_FIX32(max);
twrangefix32.StepSize = new TW_FIX32(step);
twrangefix32.DefaultValue = new TW_FIX32(def);
twrangefix32.CurrentValue = new TW_FIX32(current);
Marshal.StructureToPtr(twrangefix32, lockedPtr, false);
}
break;
}
}
static TWTY GetItemType<TValue>() where TValue : struct
{
var type = typeof(TValue);
if (type == typeof(BoolType)) return TWTY.BOOL;
if (type == typeof(TW_FIX32)) return TWTY.FIX32;
if (type == typeof(TW_STR32)) return TWTY.STR32;
if (type == typeof(TW_STR64)) return TWTY.STR64;
if (type == typeof(TW_STR128)) return TWTY.STR128;
if (type == typeof(TW_STR255)) return TWTY.STR255;
if (type == typeof(TW_FRAME)) return TWTY.FRAME;
if (type.IsEnum)
{
type = type.GetEnumUnderlyingType();
}
if (type == typeof(ushort)) return TWTY.UINT16;
if (type == typeof(short)) return TWTY.INT16;
if (type == typeof(uint)) return TWTY.UINT32;
if (type == typeof(int)) return TWTY.INT32;
if (type == typeof(byte)) return TWTY.UINT8;
if (type == typeof(sbyte)) return TWTY.INT8;
throw new NotSupportedException($"{type.Name} is not supported for writing.");
}
/// <summary>
/// Writes single piece of value to the container pointer.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="intptr">A locked pointer to the container's data pointer. If data is array this is the 0th item.</param>
/// <param name="type">The twain type.</param>
/// <param name="value"></param>
/// <param name="itemIndex">Index of the item if pointer is array.</param>
static void WriteContainerData<TValue>(IntPtr intptr, TWTY type, TValue value, int itemIndex) where TValue : struct
{
switch (type)
{
default:
throw new NotSupportedException($"Unsupported item type {type} for writing.");
// TODO: for small types needs to fill whole int32 before writing?
case TWTY.INT8:
intptr += 1 * itemIndex;
//int intval = Convert.ToSByte(value);
//Marshal.StructureToPtr(intval, intptr, false);
Marshal.StructureToPtr(Convert.ToSByte(value), intptr, false);
break;
case TWTY.UINT8:
intptr += 1 * itemIndex;
//uint uintval = Convert.ToByte(value);
//Marshal.StructureToPtr(uintval, intptr, false);
Marshal.StructureToPtr(Convert.ToByte(value), intptr, false);
break;
case TWTY.INT16:
intptr += 2 * itemIndex;
//intval = Convert.ToInt16(value);
//Marshal.StructureToPtr(intval, intptr, false);
Marshal.StructureToPtr(Convert.ToInt16(value), intptr, false);
break;
case TWTY.BOOL:
case TWTY.UINT16:
intptr += 2 * itemIndex;
//uintval = Convert.ToUInt16(value);
//Marshal.StructureToPtr(uintval, intptr, false);
Marshal.StructureToPtr(Convert.ToUInt16(value), intptr, false);
break;
case TWTY.INT32:
intptr += 4 * itemIndex;
Marshal.StructureToPtr(Convert.ToInt32(value), intptr, false);
break;
case TWTY.UINT32:
intptr += 4 * itemIndex;
Marshal.StructureToPtr(Convert.ToUInt32(value), intptr, false);
break;
case TWTY.FIX32:
intptr += 4 * itemIndex;
Marshal.StructureToPtr(value, intptr, false);
break;
case TWTY.FRAME:
intptr += 16 * itemIndex;
Marshal.StructureToPtr(value, intptr, false);
break;
case TWTY.STR32:
intptr += TW_STR32.Size * itemIndex;
Marshal.StructureToPtr(value, intptr, false);
break;
case TWTY.STR64:
intptr += TW_STR64.Size * itemIndex;
Marshal.StructureToPtr(value, intptr, false);
break;
case TWTY.STR128:
intptr += TW_STR128.Size * itemIndex;
Marshal.StructureToPtr(value, intptr, false);
break;
case TWTY.STR255:
intptr += TW_STR255.Size * itemIndex;
Marshal.StructureToPtr(value, intptr, false);
break;
}
}
}
}

View File

@ -710,30 +710,7 @@ namespace NTwain.Data
string? val = null;
if (UTF8string != IntPtr.Zero && Size > 0)
{
var locked = mgr.Lock(UTF8string);
if (locked != IntPtr.Zero)
{
// does this work? who knows.
try
{
#if NETFRAMEWORK
// safe method but with 2 copies (arr and parsed string)
var bytes = new byte[Size];
Marshal.Copy(locked, bytes, 0, bytes.Length);
val = Encoding.UTF8.GetString(bytes);
//// unsafe method with 1 copy (does it work?)
//sbyte* bytes = (sbyte*)locked;
//val = new string(bytes, 0, length, Encoding.UTF8);
#else
val = Marshal.PtrToStringUTF8(locked, (int)Size);
#endif
}
finally
{
mgr.Unlock(UTF8string);
}
}
val = ValueReader.PtrToStringUTF8(mgr, UTF8string, (int)Size);
}
if (freeMemory) Free(mgr);
return val;

View File

@ -0,0 +1,454 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace NTwain.Data
{
/// <summary>
/// Contains methods for reading pointers into various things.
/// </summary>
static class ValueReader
{
/// <summary>
/// Reads pointer as UTF8 string.
/// </summary>
/// <param name="data">Pointer to string.</param>
/// <param name="length">Number of bytes to read.</param>
/// <returns></returns>
public static string? PtrToStringUTF8(IMemoryManager memMgr, IntPtr data, int length)
{
string? val = null;
var locked = memMgr.Lock(data);
if (locked != IntPtr.Zero)
{
// does this work? who knows.
try
{
#if NETFRAMEWORK
// safe method but with 2 copies (arr and parsed string)
var bytes = new byte[length];
Marshal.Copy(locked, bytes, 0, bytes.Length);
val = Encoding.UTF8.GetString(bytes);
//// unsafe method with 1 copy (does it work?)
//sbyte* bytes = (sbyte*)locked;
//val = new string(bytes, 0, length, Encoding.UTF8);
#else
val = Marshal.PtrToStringUTF8(locked, length);
#endif
}
finally
{
memMgr.Unlock(data);
}
}
return val;
}
// most of these are modified from the original TWAIN.CapabilityToCsv()
//public static TValue ReadOneValueContainer<TValue>(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
//{
// if (cap.hContainer == IntPtr.Zero) return default;
// var lockedPtr = memMgr.Lock(cap.hContainer);
// try
// {
// TWTY itemType;
// // Mac has a level of indirection and a different structure (ick)...
// if (TwainPlatform.IsMacOSX)
// {
// // Crack the container...
// var onevalue = MarshalTo<TW_ONEVALUE_MACOSX>(lockedPtr);
// itemType = (TWTY)onevalue.ItemType;
// lockedPtr += Marshal.SizeOf(onevalue);
// }
// else
// {
// // Crack the container...
// var onevalue = MarshalTo<TW_ONEVALUE>(lockedPtr);
// itemType = onevalue.ItemType;
// lockedPtr += Marshal.SizeOf(onevalue);
// }
// return ReadContainerData<TValue>(lockedPtr, itemType, 0);
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
// if (freeMemory) memMgr.Free(ref cap.hContainer);
// }
//}
//public static Enumeration<TValue> ReadEnumerationContainer<TValue>(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
//{
// Enumeration<TValue> retVal = new Enumeration<TValue>();
// if (cap.hContainer == IntPtr.Zero) return retVal;
// var lockedPtr = memMgr.Lock(cap.hContainer);
// try
// {
// TWTY itemType;
// int count = 0;
// // Mac has a level of indirection and a different structure (ick)...
// if (TwainPlatform.IsMacOSX)
// {
// // Crack the container...
// var twenumerationmacosx = MarshalTo<TW_ENUMERATION_MACOSX>(lockedPtr);
// itemType = (TWTY)twenumerationmacosx.ItemType;
// count = (int)twenumerationmacosx.NumItems;
// retVal.DefaultIndex = (int)twenumerationmacosx.DefaultIndex;
// retVal.CurrentIndex = (int)twenumerationmacosx.CurrentIndex;
// lockedPtr += Marshal.SizeOf(twenumerationmacosx);
// }
// // Windows or the 2.4+ Linux DSM...
// else if (TWAIN.GetPlatform() == Platform.WINDOWS || ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
// {
// // Crack the container...
// var twenumeration = MarshalTo<TW_ENUMERATION>(lockedPtr);
// itemType = twenumeration.ItemType;
// count = (int)twenumeration.NumItems;
// retVal.DefaultIndex = (int)twenumeration.DefaultIndex;
// retVal.CurrentIndex = (int)twenumeration.CurrentIndex;
// lockedPtr += Marshal.SizeOf(twenumeration);
// }
// // The -2.3 Linux DSM...
// else if (twain.m_blFound020302Dsm64bit && (twain.m_linuxdsm == TWAIN.LinuxDsm.Is020302Dsm64bit))
// {
// // Crack the container...
// var twenumerationlinux64 = MarshalTo<TW_ENUMERATION_LINUX64>(lockedPtr);
// itemType = twenumerationlinux64.ItemType;
// count = (int)twenumerationlinux64.NumItems;
// retVal.DefaultIndex = (int)twenumerationlinux64.DefaultIndex;
// retVal.CurrentIndex = (int)twenumerationlinux64.CurrentIndex;
// lockedPtr += Marshal.SizeOf(twenumerationlinux64);
// }
// // This shouldn't be possible, but what the hey...
// else
// {
// Log.Error("This is serious, you win a cookie for getting here...");
// return retVal;
// }
// retVal.Items = new TValue[count];
// for (var i = 0; i < count; i++)
// {
// retVal.Items[i] = ReadContainerData<TValue>(lockedPtr, itemType, i);
// }
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
// if (freeMemory) memMgr.Free(ref cap.hContainer);
// }
// return retVal;
//}
//public static IList<TValue> ReadArrayContainer<TValue>(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
//{
// if (cap.hContainer == IntPtr.Zero) return EmptyArray<TValue>.Value;
// var lockedPtr = memMgr.Lock(cap.hContainer);
// try
// {
// TWTY itemType;
// uint count;
// // Mac has a level of indirection and a different structure (ick)...
// if (TwainPlatform.IsMacOSX)
// {
// // Crack the container...
// var twarraymacosx = MarshalTo<TW_ARRAY_MACOSX>(lockedPtr);
// itemType = (TWTY)twarraymacosx.ItemType;
// count = twarraymacosx.NumItems;
// lockedPtr += Marshal.SizeOf(twarraymacosx);
// }
// else
// {
// // Crack the container...
// var twarray = MarshalTo<TW_ARRAY>(lockedPtr);
// itemType = twarray.ItemType;
// count = twarray.NumItems;
// lockedPtr += Marshal.SizeOf(twarray);
// }
// var arr = new TValue[count];
// for (var i = 0; i < count; i++)
// {
// arr[i] = ReadContainerData<TValue>(lockedPtr, itemType, i);
// }
// return arr;
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
// if (freeMemory) memMgr.Free(ref cap.hContainer);
// }
//}
//public static Range<TValue> ReadRangeContainer<TValue>(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct
//{
// var retVal = new Range<TValue>();
// if (cap.hContainer == IntPtr.Zero) return retVal;
// var lockedPtr = memMgr.Lock(cap.hContainer);
// try
// {
// TW_RANGE twrange = default;
// TW_RANGE_FIX32 twrangefix32 = default;
// // Mac has a level of indirection and a different structure (ick)...
// if (TwainPlatform.IsMacOSX)
// {
// var twrangemacosx = MarshalTo<TW_RANGE_MACOSX>(lockedPtr);
// var twrangefix32macosx = MarshalTo<TW_RANGE_FIX32_MACOSX>(lockedPtr);
// twrange.ItemType = (TWTY)twrangemacosx.ItemType;
// twrange.MinValue = twrangemacosx.MinValue;
// twrange.MaxValue = twrangemacosx.MaxValue;
// twrange.StepSize = twrangemacosx.StepSize;
// twrange.DefaultValue = twrangemacosx.DefaultValue;
// twrange.CurrentValue = twrangemacosx.CurrentValue;
// twrangefix32.ItemType = (TWTY)twrangefix32macosx.ItemType;
// twrangefix32.MinValue = twrangefix32macosx.MinValue;
// twrangefix32.MaxValue = twrangefix32macosx.MaxValue;
// twrangefix32.StepSize = twrangefix32macosx.StepSize;
// twrangefix32.DefaultValue = twrangefix32macosx.DefaultValue;
// twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
// }
// // Windows or the 2.4+ Linux DSM...
// else if (TWAIN.GetPlatform() == Platform.WINDOWS || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
// ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
// {
// twrange = MarshalTo<TW_RANGE>(lockedPtr);
// twrangefix32 = MarshalTo<TW_RANGE_FIX32>(lockedPtr);
// }
// // The -2.3 Linux DSM...
// else
// {
// var twrangelinux64 = MarshalTo<TW_RANGE_LINUX64>(lockedPtr);
// var twrangefix32macosx = MarshalTo<TW_RANGE_FIX32_MACOSX>(lockedPtr);
// twrange.ItemType = twrangelinux64.ItemType;
// twrange.MinValue = (uint)twrangelinux64.MinValue;
// twrange.MaxValue = (uint)twrangelinux64.MaxValue;
// twrange.StepSize = (uint)twrangelinux64.StepSize;
// twrange.DefaultValue = (uint)twrangelinux64.DefaultValue;
// twrange.CurrentValue = (uint)twrangelinux64.CurrentValue;
// twrangefix32.ItemType = (TWTY)twrangefix32macosx.ItemType;
// twrangefix32.MinValue = twrangefix32macosx.MinValue;
// twrangefix32.MaxValue = twrangefix32macosx.MaxValue;
// twrangefix32.StepSize = twrangefix32macosx.StepSize;
// twrangefix32.DefaultValue = twrangefix32macosx.DefaultValue;
// twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
// }
// switch (twrange.ItemType)
// {
// // use dynamic since I know they fit the type.
// case TWTY.FIX32:
// retVal.MinValue = (dynamic)twrangefix32.MinValue;
// retVal.MaxValue = (dynamic)twrangefix32.MaxValue;
// retVal.StepSize = (dynamic)twrangefix32.StepSize;
// retVal.CurrentValue = (dynamic)twrangefix32.CurrentValue;
// retVal.DefaultValue = (dynamic)twrangefix32.DefaultValue;
// break;
// case TWTY.INT8:
// case TWTY.UINT8:
// case TWTY.INT16:
// case TWTY.BOOL:
// case TWTY.UINT16:
// case TWTY.INT32:
// case TWTY.UINT32:
// retVal.MinValue = (dynamic)twrange.MinValue;
// retVal.MaxValue = (dynamic)twrange.MaxValue;
// retVal.StepSize = (dynamic)twrange.StepSize;
// retVal.CurrentValue = (dynamic)twrange.CurrentValue;
// retVal.DefaultValue = (dynamic)twrange.DefaultValue;
// break;
// default:
// throw new NotSupportedException($"The value type {twrange.ItemType} is not supported as range.");
// }
// return retVal;
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
// if (freeMemory) memMgr.Free(ref cap.hContainer);
// }
//}
///// <summary>
///// Read the one value of a cap as string. Only STR* and HANDLE types are supported.
///// </summary>
///// <param name="twain"></param>
///// <param name="cap"></param>
///// <param name="freeMemory"></param>
///// <returns></returns>
//public static string ReadOneValueContainerString(IMemoryManager memMgr, TW_CAPABILITY cap, bool freeMemory = true)
//{
// if (cap.hContainer == IntPtr.Zero) return null;
// var lockedPtr = memMgr.Lock(cap.hContainer);
// try
// {
// if (cap.ConType == TWON.ONEVALUE)
// {
// TWTY itemType;
// // Mac has a level of indirection and a different structure (ick)...
// if (TwainPlatform.IsMacOSX)
// {
// // Crack the container...
// var onevalue = MarshalTo<TW_ONEVALUE_MACOSX>(lockedPtr);
// itemType = (TWTY)onevalue.ItemType;
// lockedPtr += Marshal.SizeOf(onevalue);
// }
// else
// {
// // Crack the container...
// var onevalue = MarshalTo<TW_ONEVALUE>(lockedPtr);
// itemType = onevalue.ItemType;
// lockedPtr += Marshal.SizeOf(onevalue);
// }
// switch (itemType)
// {
// case TWTY.STR32:
// return MarshalTo<TW_STR32>(lockedPtr).ToString();
// case TWTY.STR64:
// return MarshalTo<TW_STR64>(lockedPtr).ToString();
// case TWTY.STR128:
// return MarshalTo<TW_STR128>(lockedPtr).ToString();
// case TWTY.STR255:
// return MarshalTo<TW_STR255>(lockedPtr).ToString();
// case TWTY.HANDLE:
// // null-terminated and encoded string.
// // good chance this ain't right.
// using (var stream = new MemoryStream())
// {
// byte read = Marshal.ReadByte(lockedPtr);
// while (read != 0)
// {
// stream.WriteByte(read);
// read = Marshal.ReadByte(lockedPtr);
// lockedPtr += 1;
// }
// // which one?
// return Encoding.Unicode.GetString(Encoding.Convert(Language.GetEncoding(), Encoding.Unicode, stream.ToArray()));
// //return Language.GetEncoding().GetString(stream.ToArray());
// }
// }
// }
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
// if (freeMemory) memMgr.Free(ref cap.hContainer);
// }
// return null;
//}
///// <summary>
///// Read the container pointer content.
///// </summary>
///// <param name="intptr">A locked pointer to the container's data pointer. If data is array this is the 0th item.</param>
///// <param name="type">The twain type.</param>
///// <param name="itemIndex">Index of the item if pointer is array.</param>
///// <returns></returns>
//static TValue ReadContainerData<TValue>(IntPtr intptr, TWTY type, int itemIndex) where TValue : struct
//{
// var isEnum = typeof(TValue).IsEnum;
// switch (type)
// {
// default:
// throw new NotSupportedException($"Unsupported item type {type} for reading.");
// // TODO: verify if needs to read int32 for small types
// case TWTY.INT8:
// intptr += 1 * itemIndex;
// if (isEnum)
// {
// return NumericToEnum<sbyte, TValue>(MarshalTo<sbyte>(intptr));
// }
// return MarshalTo<TValue>(intptr);
// case TWTY.UINT8:
// intptr += 1 * itemIndex;
// if (isEnum)
// {
// return NumericToEnum<byte, TValue>(MarshalTo<byte>(intptr));
// }
// return MarshalTo<TValue>(intptr);
// case TWTY.INT16:
// intptr += 2 * itemIndex;
// if (isEnum)
// {
// return NumericToEnum<short, TValue>(MarshalTo<short>(intptr));
// }
// return MarshalTo<TValue>(intptr);
// case TWTY.BOOL:
// case TWTY.UINT16:
// intptr += 2 * itemIndex;
// if (isEnum)
// {
// return NumericToEnum<ushort, TValue>(MarshalTo<ushort>(intptr));
// }
// return MarshalTo<TValue>(intptr);
// case TWTY.INT32:
// intptr += 4 * itemIndex;
// if (isEnum)
// {
// return NumericToEnum<int, TValue>(MarshalTo<int>(intptr));
// }
// return MarshalTo<TValue>(intptr);
// case TWTY.UINT32:
// intptr += 4 * itemIndex;
// if (isEnum)
// {
// return NumericToEnum<uint, TValue>(MarshalTo<uint>(intptr));
// }
// return MarshalTo<TValue>(intptr);
// case TWTY.FIX32:
// intptr += 4 * itemIndex;
// return MarshalTo<TValue>(intptr);
// case TWTY.FRAME:
// intptr += 16 * itemIndex;
// return MarshalTo<TValue>(intptr);
// case TWTY.STR32:
// intptr += TW_STR32.Size * itemIndex;
// return MarshalTo<TValue>(intptr);
// case TWTY.STR64:
// intptr += TW_STR64.Size * itemIndex;
// return MarshalTo<TValue>(intptr);
// case TWTY.STR128:
// intptr += TW_STR128.Size * itemIndex;
// return MarshalTo<TValue>(intptr);
// case TWTY.STR255:
// intptr += TW_STR255.Size * itemIndex;
// return MarshalTo<TValue>(intptr);
// }
//}
//static TEnum NumericToEnum<TNumber, TEnum>(TNumber num) where TEnum : struct
//{
// // some caps returns a data type that's not the underlying datatype for the enum
// // so best way is to ToString() it and parse it as the enum type.
// var str = num.ToString();
// if (Enum.TryParse(str, out TEnum parsed))
// {
// return parsed;
// }
// return default;
//}
//static T MarshalTo<T>(IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T));
}
}

View File

@ -0,0 +1,609 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace NTwain.Data
{
/// <summary>
/// Contains methods for writing vairous things to pointers.
/// </summary>
static class ValueWriter
{
///// <summary>
///// Allocates and copies the string value into a pointer in UTF8 that's null-terminated.
///// </summary>
///// <param name="twain"></param>
///// <param name="value"></param>
///// <param name="length">Actual number of bytes used to encode the string without the null.</param>
///// <returns></returns>
//public static unsafe IntPtr StringToPtrUTF8(IMemoryManager memMgr, string value, out int length)
//{
// if (value == null)
// {
// length = 0;
// return IntPtr.Zero;
// }
// var utf8 = Encoding.UTF8;
// length = utf8.GetByteCount(value);
// var ptr = memMgr.Alloc((uint)length + 1); // +1 for null-terminated
// // TODO: test if this works
// int written;
// byte* bytes = (byte*)ptr;
// try
// {
// // fixed for managed pointer
// fixed (char* firstChar = value)
// {
// written = Encoding.UTF8.GetBytes(firstChar, value.Length, bytes, length);
// }
// bytes[written] = 0;
// }
// finally
// {
// if (ptr != IntPtr.Zero) memMgr.Free(ptr);
// }
// return ptr;
//}
// most of these are modified from the original TWAIN.CsvToCapability()
//public static void WriteOneValueContainer<TValue>(IMemoryManager memMgr, ref TW_CAPABILITY twCap, TValue value) where TValue : struct
//{
// IntPtr lockedPtr = IntPtr.Zero;
// try
// {
// if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer);
// TWTY itemType = GetItemType<TValue>();
// // Allocate the container (go for worst case, which is TW_STR255)...
// if (TwainPlatform.IsMacOSX)
// {
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE_MACOSX)) + Marshal.SizeOf(default(TW_STR255))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// TW_ONEVALUE_MACOSX twonevaluemacosx = default;
// twonevaluemacosx.ItemType = (uint)itemType;
// Marshal.StructureToPtr(twonevaluemacosx, lockedPtr, false);
// lockedPtr += Marshal.SizeOf(twonevaluemacosx);
// }
// else
// {
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE)) + Marshal.SizeOf(default(TW_STR255))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// TW_ONEVALUE twonevalue = default;
// twonevalue.ItemType = itemType;
// Marshal.StructureToPtr(twonevalue, lockedPtr, false);
// lockedPtr += Marshal.SizeOf(twonevalue);
// }
// WriteContainerData(lockedPtr, itemType, value, 0);
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(twCap.hContainer);
// }
//}
//public static void WriteArrayContainer<TValue>(IMemoryManager memMgr, ref TW_CAPABILITY twCap, TValue[] values) where TValue : struct
//{
// IntPtr lockedPtr = IntPtr.Zero;
// try
// {
// if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer);
// TWTY itemType = GetItemType<TValue>();
// // Allocate the container (go for worst case, which is TW_STR255)...
// if (TwainPlatform.IsMacOSX)
// {
// // Allocate...
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ARRAY_MACOSX)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// // Set the meta data...
// TW_ARRAY_MACOSX twarraymacosx = default;
// twarraymacosx.ItemType = (uint)itemType;
// twarraymacosx.NumItems = (uint)values.Length;
// Marshal.StructureToPtr(twarraymacosx, lockedPtr, false);
// // Get the pointer to the ItemList...
// lockedPtr += Marshal.SizeOf(twarraymacosx);
// }
// else
// {
// // Allocate...
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ARRAY)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// // Set the meta data...
// TW_ARRAY twarray = default;
// twarray.ItemType = itemType;
// twarray.NumItems = (uint)values.Length;
// Marshal.StructureToPtr(twarray, lockedPtr, false);
// // Get the pointer to the ItemList...
// lockedPtr += Marshal.SizeOf(twarray);
// }
// // Set the ItemList...
// for (var i = 0; i < values.Length; i++)
// {
// WriteContainerData(lockedPtr, itemType, values[i], i);
// }
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(twCap.hContainer);
// }
//}
//public static void WriteEnumContainer<TValue>(IMemoryManager memMgr, ref TW_CAPABILITY twCap, Enumeration<TValue> value) where TValue : struct
//{
// IntPtr lockedPtr = IntPtr.Zero;
// try
// {
// if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer);
// TWTY itemType = GetItemType<TValue>();
// // Allocate the container (go for worst case, which is TW_STR255)...
// if (TwainPlatform.IsMacOSX)
// {
// // Allocate...
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_MACOSX)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// // Set the meta data...
// TW_ENUMERATION_MACOSX twenumerationmacosx = default;
// twenumerationmacosx.ItemType = (uint)itemType;
// twenumerationmacosx.NumItems = (uint)value.Items.Length;
// twenumerationmacosx.CurrentIndex = (uint)value.CurrentIndex;
// twenumerationmacosx.DefaultIndex = (uint)value.DefaultIndex;
// Marshal.StructureToPtr(twenumerationmacosx, lockedPtr, false);
// // Get the pointer to the ItemList...
// lockedPtr += Marshal.SizeOf(twenumerationmacosx);
// }
// // Windows or the 2.4+ Linux DSM...
// else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
// (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
// ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
// {
// // Allocate...
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// // Set the meta data...
// TW_ENUMERATION twenumeration = default;
// twenumeration.ItemType = itemType;
// twenumeration.NumItems = (uint)value.Items.Length;
// twenumeration.CurrentIndex = (uint)value.CurrentIndex;
// twenumeration.DefaultIndex = (uint)value.CurrentIndex;
// Marshal.StructureToPtr(twenumeration, lockedPtr, false);
// // Get the pointer to the ItemList...
// lockedPtr += Marshal.SizeOf(twenumeration);
// }
// // The -2.3 Linux DSM...
// else
// {
// // Allocate...
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_LINUX64)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// // Set the meta data...
// TW_ENUMERATION_LINUX64 twenumerationlinux64 = default;
// twenumerationlinux64.ItemType = itemType;
// twenumerationlinux64.NumItems = (ulong)value.Items.Length;
// twenumerationlinux64.CurrentIndex = (ulong)value.CurrentIndex;
// twenumerationlinux64.DefaultIndex = (ulong)value.CurrentIndex;
// Marshal.StructureToPtr(twenumerationlinux64, lockedPtr, false);
// // Get the pointer to the ItemList...
// lockedPtr += Marshal.SizeOf(twenumerationlinux64);
// }
// // Set the ItemList...
// for (var i = 0; i < value.Items.Length; i++)
// {
// WriteContainerData(lockedPtr, itemType, value.Items[i], i);
// }
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(twCap.hContainer);
// }
//}
//public static void WriteRangeContainer<TValue>(IMemoryManager memMgr, ref TW_CAPABILITY twCap, Range<TValue> value) where TValue : struct
//{
// IntPtr lockedPtr = IntPtr.Zero;
// try
// {
// if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer);
// TWTY itemType = GetItemType<TValue>();
// // Allocate the container (go for worst case, which is TW_STR255)...
// if (TwainPlatform.IsMacOSX)
// {
// // Allocate...
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_RANGE_MACOSX))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// }
// // Windows or the 2.4+ Linux DSM...
// else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
// (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
// ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
// {
// // Allocate...
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_RANGE))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// }
// // The -2.3 Linux DSM...
// else
// {
// // Allocate...
// twCap.hContainer = memMgr.Alloc((uint)(Marshal.SizeOf(default(TW_RANGE_LINUX64))));
// lockedPtr = memMgr.Lock(twCap.hContainer);
// }
// // Set the Item...
// WriteRangeValues(twain, lockedPtr, itemType, value);
// }
// finally
// {
// if (lockedPtr != IntPtr.Zero) memMgr.Unlock(twCap.hContainer);
// }
//}
//static void WriteRangeValues<TValue>(IMemoryManager memMgr, IntPtr lockedPtr, TWTY itemType, Range<TValue> value) where TValue : struct
//{
// // TODO: reduce this later
// TW_RANGE twrange = default;
// TW_RANGE_MACOSX twrangemacosx = default;
// TW_RANGE_LINUX64 twrangelinux64 = default;
// switch (itemType)
// {
// default:
// throw new NotSupportedException($"{itemType} is not supported for range.");
// case TWTY.INT8:
// if (TwainPlatform.IsMacOSX)
// {
// twrangemacosx.ItemType = (uint)itemType;
// twrangemacosx.MinValue = (uint)Convert.ToSByte(value.MinValue);
// twrangemacosx.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
// twrangemacosx.StepSize = (uint)Convert.ToSByte(value.StepSize);
// twrangemacosx.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
// twrangemacosx.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
// Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
// }
// else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
// {
// twrange.ItemType = itemType;
// twrange.MinValue = (uint)Convert.ToSByte(value.MinValue);
// twrange.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
// twrange.StepSize = (uint)Convert.ToSByte(value.StepSize);
// twrange.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
// twrange.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
// Marshal.StructureToPtr(twrange, lockedPtr, false);
// }
// else
// {
// twrangelinux64.ItemType = itemType;
// twrangelinux64.MinValue = (uint)Convert.ToSByte(value.MinValue);
// twrangelinux64.MaxValue = (uint)Convert.ToSByte(value.MaxValue);
// twrangelinux64.StepSize = (uint)Convert.ToSByte(value.StepSize);
// twrangelinux64.DefaultValue = (uint)Convert.ToSByte(value.DefaultValue);
// twrangelinux64.CurrentValue = (uint)Convert.ToSByte(value.CurrentValue);
// Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
// }
// break;
// case TWTY.UINT8:
// if (TwainPlatform.IsMacOSX)
// {
// twrangemacosx.ItemType = (uint)itemType;
// twrangemacosx.MinValue = Convert.ToByte(value.MinValue);
// twrangemacosx.MaxValue = Convert.ToByte(value.MaxValue);
// twrangemacosx.StepSize = Convert.ToByte(value.StepSize);
// twrangemacosx.DefaultValue = Convert.ToByte(value.DefaultValue);
// twrangemacosx.CurrentValue = Convert.ToByte(value.CurrentValue);
// Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
// }
// else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
// {
// twrange.ItemType = itemType;
// twrange.MinValue = Convert.ToByte(value.MinValue);
// twrange.MaxValue = Convert.ToByte(value.MaxValue);
// twrange.StepSize = Convert.ToByte(value.StepSize);
// twrange.DefaultValue = Convert.ToByte(value.DefaultValue);
// twrange.CurrentValue = Convert.ToByte(value.CurrentValue);
// Marshal.StructureToPtr(twrange, lockedPtr, false);
// }
// else
// {
// twrangelinux64.ItemType = itemType;
// twrangelinux64.MinValue = Convert.ToByte(value.MinValue);
// twrangelinux64.MaxValue = Convert.ToByte(value.MaxValue);
// twrangelinux64.StepSize = Convert.ToByte(value.StepSize);
// twrangelinux64.DefaultValue = Convert.ToByte(value.DefaultValue);
// twrangelinux64.CurrentValue = Convert.ToByte(value.CurrentValue);
// Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
// }
// break;
// case TWTY.INT16:
// if (TwainPlatform.IsMacOSX)
// {
// twrangemacosx.ItemType = (uint)itemType;
// twrangemacosx.MinValue = (uint)Convert.ToInt16(value.MinValue);
// twrangemacosx.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
// twrangemacosx.StepSize = (uint)Convert.ToInt16(value.StepSize);
// twrangemacosx.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
// twrangemacosx.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
// Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
// }
// else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
// {
// twrange.ItemType = itemType;
// twrange.MinValue = (uint)Convert.ToInt16(value.MinValue);
// twrange.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
// twrange.StepSize = (uint)Convert.ToInt16(value.StepSize);
// twrange.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
// twrange.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
// Marshal.StructureToPtr(twrange, lockedPtr, false);
// }
// else
// {
// twrangelinux64.ItemType = itemType;
// twrangelinux64.MinValue = (uint)Convert.ToInt16(value.MinValue);
// twrangelinux64.MaxValue = (uint)Convert.ToInt16(value.MaxValue);
// twrangelinux64.StepSize = (uint)Convert.ToInt16(value.StepSize);
// twrangelinux64.DefaultValue = (uint)Convert.ToInt16(value.DefaultValue);
// twrangelinux64.CurrentValue = (uint)Convert.ToInt16(value.CurrentValue);
// Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
// }
// break;
// case TWTY.BOOL:
// case TWTY.UINT16:
// if (TwainPlatform.IsMacOSX)
// {
// twrangemacosx.ItemType = (uint)itemType;
// twrangemacosx.MinValue = Convert.ToUInt16(value.MinValue);
// twrangemacosx.MaxValue = Convert.ToUInt16(value.MaxValue);
// twrangemacosx.StepSize = Convert.ToUInt16(value.StepSize);
// twrangemacosx.DefaultValue = Convert.ToUInt16(value.DefaultValue);
// twrangemacosx.CurrentValue = Convert.ToUInt16(value.CurrentValue);
// Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
// }
// else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
// {
// twrange.ItemType = itemType;
// twrange.MinValue = Convert.ToUInt16(value.MinValue);
// twrange.MaxValue = Convert.ToUInt16(value.MaxValue);
// twrange.StepSize = Convert.ToUInt16(value.StepSize);
// twrange.DefaultValue = Convert.ToUInt16(value.DefaultValue);
// twrange.CurrentValue = Convert.ToUInt16(value.CurrentValue);
// Marshal.StructureToPtr(twrange, lockedPtr, false);
// }
// else
// {
// twrangelinux64.ItemType = itemType;
// twrangelinux64.MinValue = Convert.ToUInt16(value.MinValue);
// twrangelinux64.MaxValue = Convert.ToUInt16(value.MaxValue);
// twrangelinux64.StepSize = Convert.ToUInt16(value.StepSize);
// twrangelinux64.DefaultValue = Convert.ToUInt16(value.DefaultValue);
// twrangelinux64.CurrentValue = Convert.ToUInt16(value.CurrentValue);
// Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
// }
// break;
// case TWTY.INT32:
// if (TwainPlatform.IsMacOSX)
// {
// twrangemacosx.ItemType = (uint)itemType;
// twrangemacosx.MinValue = (uint)Convert.ToInt32(value.MinValue);
// twrangemacosx.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
// twrangemacosx.StepSize = (uint)Convert.ToInt32(value.StepSize);
// twrangemacosx.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
// twrangemacosx.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
// Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
// }
// else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
// {
// twrange.ItemType = itemType;
// twrange.MinValue = (uint)Convert.ToInt32(value.MinValue);
// twrange.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
// twrange.StepSize = (uint)Convert.ToInt32(value.StepSize);
// twrange.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
// twrange.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
// Marshal.StructureToPtr(twrange, lockedPtr, false);
// }
// else
// {
// twrangelinux64.ItemType = itemType;
// twrangelinux64.MinValue = (uint)Convert.ToInt32(value.MinValue);
// twrangelinux64.MaxValue = (uint)Convert.ToInt32(value.MaxValue);
// twrangelinux64.StepSize = (uint)Convert.ToInt32(value.StepSize);
// twrangelinux64.DefaultValue = (uint)Convert.ToInt32(value.DefaultValue);
// twrangelinux64.CurrentValue = (uint)Convert.ToInt32(value.CurrentValue);
// Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
// }
// break;
// case TWTY.UINT32:
// if (TwainPlatform.IsMacOSX)
// {
// twrangemacosx.ItemType = (uint)itemType;
// twrangemacosx.MinValue = Convert.ToUInt32(value.MinValue);
// twrangemacosx.MaxValue = Convert.ToUInt32(value.MaxValue);
// twrangemacosx.StepSize = Convert.ToUInt32(value.StepSize);
// twrangemacosx.DefaultValue = Convert.ToUInt32(value.DefaultValue);
// twrangemacosx.CurrentValue = Convert.ToUInt32(value.CurrentValue);
// Marshal.StructureToPtr(twrangemacosx, lockedPtr, false);
// }
// else if ((twain.m_linuxdsm == TWAIN.LinuxDsm.Unknown) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm))
// {
// twrange.ItemType = itemType;
// twrange.MinValue = Convert.ToUInt32(value.MinValue);
// twrange.MaxValue = Convert.ToUInt32(value.MaxValue);
// twrange.StepSize = Convert.ToUInt32(value.StepSize);
// twrange.DefaultValue = Convert.ToUInt32(value.DefaultValue);
// twrange.CurrentValue = Convert.ToUInt32(value.CurrentValue);
// Marshal.StructureToPtr(twrange, lockedPtr, false);
// }
// else
// {
// twrangelinux64.ItemType = itemType;
// twrangelinux64.MinValue = Convert.ToUInt32(value.MinValue);
// twrangelinux64.MaxValue = Convert.ToUInt32(value.MaxValue);
// twrangelinux64.StepSize = Convert.ToUInt32(value.StepSize);
// twrangelinux64.DefaultValue = Convert.ToUInt32(value.DefaultValue);
// twrangelinux64.CurrentValue = Convert.ToUInt32(value.CurrentValue);
// Marshal.StructureToPtr(twrangelinux64, lockedPtr, false);
// }
// break;
// case TWTY.FIX32:
// double min = Convert.ToDouble(value.MinValue);
// double max = Convert.ToDouble(value.MaxValue);
// double step = Convert.ToDouble(value.StepSize);
// double def = Convert.ToDouble(value.DefaultValue);
// double current = Convert.ToDouble(value.CurrentValue);
// if (TwainPlatform.IsMacOSX)
// {
// TW_RANGE_FIX32_MACOSX twrangefix32macosx = default;
// twrangefix32macosx.ItemType = (uint)itemType;
// twrangefix32macosx.MinValue = new TW_FIX32(min);
// twrangefix32macosx.MaxValue = new TW_FIX32(max);
// twrangefix32macosx.StepSize = new TW_FIX32(step);
// twrangefix32macosx.DefaultValue = new TW_FIX32(def);
// twrangefix32macosx.CurrentValue = new TW_FIX32(current);
// Marshal.StructureToPtr(twrangefix32macosx, lockedPtr, false);
// }
// else
// {
// TW_RANGE_FIX32 twrangefix32 = default;
// twrangefix32.ItemType = itemType;
// twrangefix32.MinValue = new TW_FIX32(min);
// twrangefix32.MaxValue = new TW_FIX32(max);
// twrangefix32.StepSize = new TW_FIX32(step);
// twrangefix32.DefaultValue = new TW_FIX32(def);
// twrangefix32.CurrentValue = new TW_FIX32(current);
// Marshal.StructureToPtr(twrangefix32, lockedPtr, false);
// }
// break;
// }
//}
//static TWTY GetItemType<TValue>() where TValue : struct
//{
// var type = typeof(TValue);
// if (type == typeof(BoolType)) return TWTY.BOOL;
// if (type == typeof(TW_FIX32)) return TWTY.FIX32;
// if (type == typeof(TW_STR32)) return TWTY.STR32;
// if (type == typeof(TW_STR64)) return TWTY.STR64;
// if (type == typeof(TW_STR128)) return TWTY.STR128;
// if (type == typeof(TW_STR255)) return TWTY.STR255;
// if (type == typeof(TW_FRAME)) return TWTY.FRAME;
// if (type.IsEnum)
// {
// type = type.GetEnumUnderlyingType();
// }
// if (type == typeof(ushort)) return TWTY.UINT16;
// if (type == typeof(short)) return TWTY.INT16;
// if (type == typeof(uint)) return TWTY.UINT32;
// if (type == typeof(int)) return TWTY.INT32;
// if (type == typeof(byte)) return TWTY.UINT8;
// if (type == typeof(sbyte)) return TWTY.INT8;
// throw new NotSupportedException($"{type.Name} is not supported for writing.");
//}
///// <summary>
///// Writes single piece of value to the container pointer.
///// </summary>
///// <typeparam name="TValue"></typeparam>
///// <param name="intptr">A locked pointer to the container's data pointer. If data is array this is the 0th item.</param>
///// <param name="type">The twain type.</param>
///// <param name="value"></param>
///// <param name="itemIndex">Index of the item if pointer is array.</param>
//static void WriteContainerData<TValue>(IntPtr intptr, TWTY type, TValue value, int itemIndex) where TValue : struct
//{
// switch (type)
// {
// default:
// throw new NotSupportedException($"Unsupported item type {type} for writing.");
// // TODO: for small types needs to fill whole int32 before writing?
// case TWTY.INT8:
// intptr += 1 * itemIndex;
// //int intval = Convert.ToSByte(value);
// //Marshal.StructureToPtr(intval, intptr, false);
// Marshal.StructureToPtr(Convert.ToSByte(value), intptr, false);
// break;
// case TWTY.UINT8:
// intptr += 1 * itemIndex;
// //uint uintval = Convert.ToByte(value);
// //Marshal.StructureToPtr(uintval, intptr, false);
// Marshal.StructureToPtr(Convert.ToByte(value), intptr, false);
// break;
// case TWTY.INT16:
// intptr += 2 * itemIndex;
// //intval = Convert.ToInt16(value);
// //Marshal.StructureToPtr(intval, intptr, false);
// Marshal.StructureToPtr(Convert.ToInt16(value), intptr, false);
// break;
// case TWTY.BOOL:
// case TWTY.UINT16:
// intptr += 2 * itemIndex;
// //uintval = Convert.ToUInt16(value);
// //Marshal.StructureToPtr(uintval, intptr, false);
// Marshal.StructureToPtr(Convert.ToUInt16(value), intptr, false);
// break;
// case TWTY.INT32:
// intptr += 4 * itemIndex;
// Marshal.StructureToPtr(Convert.ToInt32(value), intptr, false);
// break;
// case TWTY.UINT32:
// intptr += 4 * itemIndex;
// Marshal.StructureToPtr(Convert.ToUInt32(value), intptr, false);
// break;
// case TWTY.FIX32:
// intptr += 4 * itemIndex;
// Marshal.StructureToPtr(value, intptr, false);
// break;
// case TWTY.FRAME:
// intptr += 16 * itemIndex;
// Marshal.StructureToPtr(value, intptr, false);
// break;
// case TWTY.STR32:
// intptr += TW_STR32.Size * itemIndex;
// Marshal.StructureToPtr(value, intptr, false);
// break;
// case TWTY.STR64:
// intptr += TW_STR64.Size * itemIndex;
// Marshal.StructureToPtr(value, intptr, false);
// break;
// case TWTY.STR128:
// intptr += TW_STR128.Size * itemIndex;
// Marshal.StructureToPtr(value, intptr, false);
// break;
// case TWTY.STR255:
// intptr += TW_STR255.Size * itemIndex;
// Marshal.StructureToPtr(value, intptr, false);
// break;
// }
//}
}
}