From 9e59e2355df1747c5a8e8a344d1f690d3e826253 Mon Sep 17 00:00:00 2001 From: Eugene Wang <8755753+soukoku@users.noreply.github.com> Date: Tue, 4 Apr 2023 08:17:46 -0400 Subject: [PATCH] Start resurrecting old value reader/writer. --- src/NTwain-temp/ValueReader.cs | 444 ---------------------- src/NTwain-temp/ValueWriter.cs | 617 ------------------------------- src/NTwain/Data/TWAINH_EXTRAS.cs | 25 +- src/NTwain/Data/ValueReader.cs | 454 +++++++++++++++++++++++ src/NTwain/Data/ValueWriter.cs | 609 ++++++++++++++++++++++++++++++ 5 files changed, 1064 insertions(+), 1085 deletions(-) delete mode 100644 src/NTwain-temp/ValueReader.cs delete mode 100644 src/NTwain-temp/ValueWriter.cs create mode 100644 src/NTwain/Data/ValueReader.cs create mode 100644 src/NTwain/Data/ValueWriter.cs diff --git a/src/NTwain-temp/ValueReader.cs b/src/NTwain-temp/ValueReader.cs deleted file mode 100644 index 95bdb31..0000000 --- a/src/NTwain-temp/ValueReader.cs +++ /dev/null @@ -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 -{ - /// - /// Contains methods for reading pointers into various things. - /// - public static class ValueReader - { - /// - /// Reads pointer as UTF8 string. - /// - /// Pointer to string. - /// Number of bytes to read. - /// - 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(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(lockedPtr); - itemType = (TWTY)onevalue.ItemType; - lockedPtr += Marshal.SizeOf(onevalue); - } - else - { - // Crack the container... - var onevalue = MarshalTo(lockedPtr); - itemType = onevalue.ItemType; - lockedPtr += Marshal.SizeOf(onevalue); - } - - return ReadContainerData(lockedPtr, itemType, 0); - } - finally - { - if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer); - if (freeMemory) twain.DsmMemFree(ref cap.hContainer); - } - } - public static Enumeration ReadEnumerationContainer(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct - { - Enumeration retVal = new Enumeration(); - - 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(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(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(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(lockedPtr, itemType, i); - } - } - finally - { - if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer); - if (freeMemory) twain.DsmMemFree(ref cap.hContainer); - } - return retVal; - } - public static IList ReadArrayContainer(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct - { - if (cap.hContainer == IntPtr.Zero) return EmptyArray.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(lockedPtr); - itemType = (TWTY)twarraymacosx.ItemType; - count = twarraymacosx.NumItems; - lockedPtr += Marshal.SizeOf(twarraymacosx); - } - else - { - // Crack the container... - var twarray = MarshalTo(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(lockedPtr, itemType, i); - } - return arr; - } - finally - { - if (lockedPtr != IntPtr.Zero) twain.DsmMemUnlock(cap.hContainer); - if (freeMemory) twain.DsmMemFree(ref cap.hContainer); - } - } - public static Range ReadRangeContainer(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct - { - var retVal = new Range(); - - 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(lockedPtr); - var twrangefix32macosx = MarshalTo(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(lockedPtr); - twrangefix32 = MarshalTo(lockedPtr); - } - // The -2.3 Linux DSM... - else - { - var twrangelinux64 = MarshalTo(lockedPtr); - var twrangefix32macosx = MarshalTo(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); - } - } - - /// - /// Read the one value of a cap as string. Only STR* and HANDLE types are supported. - /// - /// - /// - /// - /// - 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(lockedPtr); - itemType = (TWTY)onevalue.ItemType; - lockedPtr += Marshal.SizeOf(onevalue); - } - else - { - // Crack the container... - var onevalue = MarshalTo(lockedPtr); - itemType = onevalue.ItemType; - lockedPtr += Marshal.SizeOf(onevalue); - } - - switch (itemType) - { - case TWTY.STR32: - return MarshalTo(lockedPtr).ToString(); - case TWTY.STR64: - return MarshalTo(lockedPtr).ToString(); - case TWTY.STR128: - return MarshalTo(lockedPtr).ToString(); - case TWTY.STR255: - return MarshalTo(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; - } - /// - /// Read the container pointer content. - /// - /// A locked pointer to the container's data pointer. If data is array this is the 0th item. - /// The twain type. - /// Index of the item if pointer is array. - /// - static TValue ReadContainerData(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(MarshalTo(intptr)); - } - return MarshalTo(intptr); - case TWTY.UINT8: - intptr += 1 * itemIndex; - if (isEnum) - { - return NumericToEnum(MarshalTo(intptr)); - } - return MarshalTo(intptr); - case TWTY.INT16: - intptr += 2 * itemIndex; - if (isEnum) - { - return NumericToEnum(MarshalTo(intptr)); - } - return MarshalTo(intptr); - case TWTY.BOOL: - case TWTY.UINT16: - intptr += 2 * itemIndex; - if (isEnum) - { - return NumericToEnum(MarshalTo(intptr)); - } - return MarshalTo(intptr); - case TWTY.INT32: - intptr += 4 * itemIndex; - if (isEnum) - { - return NumericToEnum(MarshalTo(intptr)); - } - return MarshalTo(intptr); - case TWTY.UINT32: - intptr += 4 * itemIndex; - if (isEnum) - { - return NumericToEnum(MarshalTo(intptr)); - } - return MarshalTo(intptr); - case TWTY.FIX32: - intptr += 4 * itemIndex; - return MarshalTo(intptr); - case TWTY.FRAME: - intptr += 16 * itemIndex; - return MarshalTo(intptr); - case TWTY.STR32: - intptr += TW_STR32.Size * itemIndex; - return MarshalTo(intptr); - case TWTY.STR64: - intptr += TW_STR64.Size * itemIndex; - return MarshalTo(intptr); - case TWTY.STR128: - intptr += TW_STR128.Size * itemIndex; - return MarshalTo(intptr); - case TWTY.STR255: - intptr += TW_STR255.Size * itemIndex; - return MarshalTo(intptr); - } - } - - static TEnum NumericToEnum(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(IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T)); - } -} diff --git a/src/NTwain-temp/ValueWriter.cs b/src/NTwain-temp/ValueWriter.cs deleted file mode 100644 index 981b584..0000000 --- a/src/NTwain-temp/ValueWriter.cs +++ /dev/null @@ -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 -{ - /// - /// Contains methods for writing vairous things to pointers. - /// - public static class ValueWriter - { - /// - /// Allocates and copies the string value into a pointer in UTF8 that's null-terminated. - /// - /// - /// - /// Actual number of bytes used to encode the string without the null. - /// - 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(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(); - - // 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(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(); - - // 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(TWAIN twain, ref TW_CAPABILITY twCap, Enumeration value) where TValue : struct - { - IntPtr lockedPtr = IntPtr.Zero; - try - { - if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer); - - TWTY itemType = GetItemType(); - - // 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(TWAIN twain, ref TW_CAPABILITY twCap, Range value) where TValue : struct - { - IntPtr lockedPtr = IntPtr.Zero; - try - { - if (twCap.hContainer != IntPtr.Zero) twain.DsmMemFree(ref twCap.hContainer); - - TWTY itemType = GetItemType(); - - // 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(TWAIN twain, IntPtr lockedPtr, TWTY itemType, Range 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() 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."); - } - - /// - /// Writes single piece of value to the container pointer. - /// - /// - /// A locked pointer to the container's data pointer. If data is array this is the 0th item. - /// The twain type. - /// - /// Index of the item if pointer is array. - static void WriteContainerData(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; - } - } - } -} diff --git a/src/NTwain/Data/TWAINH_EXTRAS.cs b/src/NTwain/Data/TWAINH_EXTRAS.cs index 44e105f..5770886 100644 --- a/src/NTwain/Data/TWAINH_EXTRAS.cs +++ b/src/NTwain/Data/TWAINH_EXTRAS.cs @@ -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; diff --git a/src/NTwain/Data/ValueReader.cs b/src/NTwain/Data/ValueReader.cs new file mode 100644 index 0000000..14a87b3 --- /dev/null +++ b/src/NTwain/Data/ValueReader.cs @@ -0,0 +1,454 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace NTwain.Data +{ + /// + /// Contains methods for reading pointers into various things. + /// + static class ValueReader + { + /// + /// Reads pointer as UTF8 string. + /// + /// Pointer to string. + /// Number of bytes to read. + /// + 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(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(lockedPtr); + // itemType = (TWTY)onevalue.ItemType; + // lockedPtr += Marshal.SizeOf(onevalue); + // } + // else + // { + // // Crack the container... + // var onevalue = MarshalTo(lockedPtr); + // itemType = onevalue.ItemType; + // lockedPtr += Marshal.SizeOf(onevalue); + // } + + // return ReadContainerData(lockedPtr, itemType, 0); + // } + // finally + // { + // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer); + // if (freeMemory) memMgr.Free(ref cap.hContainer); + // } + //} + //public static Enumeration ReadEnumerationContainer(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct + //{ + // Enumeration retVal = new Enumeration(); + + // 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(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(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(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(lockedPtr, itemType, i); + // } + // } + // finally + // { + // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer); + // if (freeMemory) memMgr.Free(ref cap.hContainer); + // } + // return retVal; + //} + //public static IList ReadArrayContainer(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct + //{ + // if (cap.hContainer == IntPtr.Zero) return EmptyArray.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(lockedPtr); + // itemType = (TWTY)twarraymacosx.ItemType; + // count = twarraymacosx.NumItems; + // lockedPtr += Marshal.SizeOf(twarraymacosx); + // } + // else + // { + // // Crack the container... + // var twarray = MarshalTo(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(lockedPtr, itemType, i); + // } + // return arr; + // } + // finally + // { + // if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer); + // if (freeMemory) memMgr.Free(ref cap.hContainer); + // } + //} + //public static Range ReadRangeContainer(IMemoryManager memMgr, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct + //{ + // var retVal = new Range(); + + // 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(lockedPtr); + // var twrangefix32macosx = MarshalTo(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(lockedPtr); + // twrangefix32 = MarshalTo(lockedPtr); + // } + // // The -2.3 Linux DSM... + // else + // { + // var twrangelinux64 = MarshalTo(lockedPtr); + // var twrangefix32macosx = MarshalTo(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); + // } + //} + + ///// + ///// Read the one value of a cap as string. Only STR* and HANDLE types are supported. + ///// + ///// + ///// + ///// + ///// + //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(lockedPtr); + // itemType = (TWTY)onevalue.ItemType; + // lockedPtr += Marshal.SizeOf(onevalue); + // } + // else + // { + // // Crack the container... + // var onevalue = MarshalTo(lockedPtr); + // itemType = onevalue.ItemType; + // lockedPtr += Marshal.SizeOf(onevalue); + // } + + // switch (itemType) + // { + // case TWTY.STR32: + // return MarshalTo(lockedPtr).ToString(); + // case TWTY.STR64: + // return MarshalTo(lockedPtr).ToString(); + // case TWTY.STR128: + // return MarshalTo(lockedPtr).ToString(); + // case TWTY.STR255: + // return MarshalTo(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; + //} + ///// + ///// Read the container pointer content. + ///// + ///// A locked pointer to the container's data pointer. If data is array this is the 0th item. + ///// The twain type. + ///// Index of the item if pointer is array. + ///// + //static TValue ReadContainerData(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(MarshalTo(intptr)); + // } + // return MarshalTo(intptr); + // case TWTY.UINT8: + // intptr += 1 * itemIndex; + // if (isEnum) + // { + // return NumericToEnum(MarshalTo(intptr)); + // } + // return MarshalTo(intptr); + // case TWTY.INT16: + // intptr += 2 * itemIndex; + // if (isEnum) + // { + // return NumericToEnum(MarshalTo(intptr)); + // } + // return MarshalTo(intptr); + // case TWTY.BOOL: + // case TWTY.UINT16: + // intptr += 2 * itemIndex; + // if (isEnum) + // { + // return NumericToEnum(MarshalTo(intptr)); + // } + // return MarshalTo(intptr); + // case TWTY.INT32: + // intptr += 4 * itemIndex; + // if (isEnum) + // { + // return NumericToEnum(MarshalTo(intptr)); + // } + // return MarshalTo(intptr); + // case TWTY.UINT32: + // intptr += 4 * itemIndex; + // if (isEnum) + // { + // return NumericToEnum(MarshalTo(intptr)); + // } + // return MarshalTo(intptr); + // case TWTY.FIX32: + // intptr += 4 * itemIndex; + // return MarshalTo(intptr); + // case TWTY.FRAME: + // intptr += 16 * itemIndex; + // return MarshalTo(intptr); + // case TWTY.STR32: + // intptr += TW_STR32.Size * itemIndex; + // return MarshalTo(intptr); + // case TWTY.STR64: + // intptr += TW_STR64.Size * itemIndex; + // return MarshalTo(intptr); + // case TWTY.STR128: + // intptr += TW_STR128.Size * itemIndex; + // return MarshalTo(intptr); + // case TWTY.STR255: + // intptr += TW_STR255.Size * itemIndex; + // return MarshalTo(intptr); + // } + //} + + //static TEnum NumericToEnum(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(IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T)); + } +} diff --git a/src/NTwain/Data/ValueWriter.cs b/src/NTwain/Data/ValueWriter.cs new file mode 100644 index 0000000..92c5125 --- /dev/null +++ b/src/NTwain/Data/ValueWriter.cs @@ -0,0 +1,609 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace NTwain.Data +{ + /// + /// Contains methods for writing vairous things to pointers. + /// + static class ValueWriter + { + ///// + ///// Allocates and copies the string value into a pointer in UTF8 that's null-terminated. + ///// + ///// + ///// + ///// Actual number of bytes used to encode the string without the null. + ///// + //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(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(); + + // // 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(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(); + + // // 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(IMemoryManager memMgr, ref TW_CAPABILITY twCap, Enumeration value) where TValue : struct + //{ + // IntPtr lockedPtr = IntPtr.Zero; + // try + // { + // if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer); + + // TWTY itemType = GetItemType(); + + // // 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(IMemoryManager memMgr, ref TW_CAPABILITY twCap, Range value) where TValue : struct + //{ + // IntPtr lockedPtr = IntPtr.Zero; + // try + // { + // if (twCap.hContainer != IntPtr.Zero) memMgr.Free(ref twCap.hContainer); + + // TWTY itemType = GetItemType(); + + // // 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(IMemoryManager memMgr, IntPtr lockedPtr, TWTY itemType, Range 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() 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."); + //} + + ///// + ///// Writes single piece of value to the container pointer. + ///// + ///// + ///// A locked pointer to the container's data pointer. If data is array this is the 0th item. + ///// The twain type. + ///// + ///// Index of the item if pointer is array. + //static void WriteContainerData(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; + // } + //} + } +}