From 65a07e0254bde3332b374850121cb96a66ccb359 Mon Sep 17 00:00:00 2001 From: Eugene Wang <8755753+soukoku@users.noreply.github.com> Date: Sun, 25 Apr 2021 14:43:15 -0400 Subject: [PATCH] Added GetLabel/GetHelp for caps as experiment. --- samples/Net5Console/Program.cs | 21 ++- src/NTwain/CapWrapper.cs | 75 ++++++++--- .../{TWAINWorkingGroup => }/TWAINH_EXTRAS.cs | 0 src/NTwain/ValueReader.cs | 124 +++++++++++++++++- 4 files changed, 193 insertions(+), 27 deletions(-) rename src/NTwain/{TWAINWorkingGroup => }/TWAINH_EXTRAS.cs (100%) diff --git a/samples/Net5Console/Program.cs b/samples/Net5Console/Program.cs index 2778f63..cdf35f2 100644 --- a/samples/Net5Console/Program.cs +++ b/samples/Net5Console/Program.cs @@ -76,10 +76,10 @@ namespace Net5Console var caps = session.Capabilities; Console.WriteLine("Device supports these caps:"); - //foreach (var cap in caps.Keys.OrderBy(c => c)) - //{ - // Console.WriteLine($"\t{cap}: {caps[cap].Supports}"); - //} + foreach (var cap in caps.CAP_SUPPORTEDCAPS.GetValues()) + { + WriteCapInfo(caps, cap); + } Console.WriteLine(); //if (caps.TryGetValue(CAP.ICAP_PIXELTYPE, out CapWrapper wrapper)) @@ -123,5 +123,18 @@ namespace Net5Console } } + + private static void WriteCapInfo(Capabilities caps, CAP cap) + { + // use reflection due to generics + var propInfo = typeof(Capabilities).GetProperty(cap.ToString()); + if (propInfo == null) return; + + var capWrapper = propInfo.GetValue(caps); + var label = (string)capWrapper.GetType().GetMethod(nameof(CapWrapper.GetLabel)).Invoke(capWrapper, null); + var supports = (TWQC)capWrapper.GetType().GetMethod(nameof(CapWrapper.QuerySupport)).Invoke(capWrapper, null); + + Console.WriteLine($"\t{label ?? cap.ToString()}: {supports}"); + } } } diff --git a/src/NTwain/CapWrapper.cs b/src/NTwain/CapWrapper.cs index 715b8a6..eb410cd 100644 --- a/src/NTwain/CapWrapper.cs +++ b/src/NTwain/CapWrapper.cs @@ -17,31 +17,32 @@ namespace NTwain { _twain = twain; Cap = cap; - - var twCap = new TW_CAPABILITY - { - Cap = cap - }; - - var sts = _twain.DatCapability(DG.CONTROL, MSG.QUERYSUPPORT, ref twCap); - if (sts == STS.SUCCESS && twCap.ConType == TWON.ONEVALUE) - { - Supports = ValueReader.ReadOneValue(_twain, twCap); - } } - /// - /// The operations supported by the cap. - /// Not all sources supports this so it may be unknown. - /// - public TWQC Supports { get; } - - /// /// The cap being targeted. /// public CAP Cap { get; } + /// + /// Gets the operations supported by the cap. + /// Not all sources supports this so it may be unknown. + /// + public TWQC QuerySupport() + { + var twCap = new TW_CAPABILITY + { + Cap = Cap + }; + + var sts = _twain.DatCapability(DG.CONTROL, MSG.QUERYSUPPORT, ref twCap); + if (sts == STS.SUCCESS && twCap.ConType == TWON.ONEVALUE) + { + return ValueReader.ReadOneValue(_twain, twCap); + } + return TWQC.Uknown; + } + /// /// Try to get list of the cap's supported values. /// @@ -125,6 +126,44 @@ namespace NTwain return default(TValue); } + /// + /// Try to get the cap's label text. + /// + /// + public string GetLabel() + { + var twCap = new TW_CAPABILITY + { + Cap = Cap + }; + + var sts = _twain.DatCapability(DG.CONTROL, MSG.GETLABEL, ref twCap); + if (sts == STS.SUCCESS) + { + return ValueReader.ReadOneString(_twain, twCap); + } + return null; + } + + /// + /// Try to get the cap's description text. + /// + /// + public string GetHelp() + { + var twCap = new TW_CAPABILITY + { + Cap = Cap + }; + + var sts = _twain.DatCapability(DG.CONTROL, MSG.GETHELP, ref twCap); + if (sts == STS.SUCCESS) + { + return ValueReader.ReadOneString(_twain, twCap); + } + return null; + } + /// /// Resets the cap's current value to power-on default. /// diff --git a/src/NTwain/TWAINWorkingGroup/TWAINH_EXTRAS.cs b/src/NTwain/TWAINH_EXTRAS.cs similarity index 100% rename from src/NTwain/TWAINWorkingGroup/TWAINH_EXTRAS.cs rename to src/NTwain/TWAINH_EXTRAS.cs diff --git a/src/NTwain/ValueReader.cs b/src/NTwain/ValueReader.cs index 6a31b35..31f44c5 100644 --- a/src/NTwain/ValueReader.cs +++ b/src/NTwain/ValueReader.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -13,7 +14,7 @@ namespace NTwain /// public static class ValueReader { - public static TValue ReadOneValue(TWAIN twain, TW_CAPABILITY cap) where TValue : struct + public static TValue ReadOneValue(TWAIN twain, TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct { if (cap.hContainer == IntPtr.Zero) return default(TValue); @@ -43,21 +44,134 @@ namespace NTwain finally { twain.DsmMemUnlock(cap.hContainer); + if (freeMemory) twain.DsmMemFree(ref cap.hContainer); } } - public static IList ReadEnumeration(TWAIN twain, TW_CAPABILITY twCap) where TValue : struct + public static IList ReadEnumeration(TWAIN twain, TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct { throw new NotImplementedException(); } - public static IList ReadArray(TWAIN twain, TW_CAPABILITY twCap) where TValue : struct + public static IList ReadArray(TWAIN twain, TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct { - throw new NotImplementedException(); + var list = new List(); + + if (cap.hContainer == IntPtr.Zero) return list; + + var lockedPtr = twain.DsmMemLock(cap.hContainer); + + try + { + TWTY itemType; + uint count; + + // Mac has a level of indirection and a different structure (ick)... + if (PlatformTools.GetPlatform() == Platform.MACOSX) + { + // Crack the container... + TW_ARRAY_MACOSX twarraymacosx = default(TW_ARRAY_MACOSX); + twarraymacosx = MarshalTo(lockedPtr); + itemType = (TWTY)twarraymacosx.ItemType; + count = twarraymacosx.NumItems; + lockedPtr += Marshal.SizeOf(twarraymacosx); + } + else + { + // Crack the container... + TW_ARRAY twarray = default(TW_ARRAY); + twarray = MarshalTo(lockedPtr); + itemType = twarray.ItemType; + count = twarray.NumItems; + lockedPtr += Marshal.SizeOf(twarray); + } + + for (var i = 0; i < count; i++) + { + list.Add(ReadContainerData(lockedPtr, itemType, i)); + } + } + finally + { + twain.DsmMemUnlock(cap.hContainer); + if (freeMemory) twain.DsmMemFree(ref cap.hContainer); + } + return list; } - public static (TValue defaultVal, TValue currentVal, IEnumerable values) ReadRange(TWAIN twain, TW_CAPABILITY twCap) where TValue : struct + public static (TValue defaultVal, TValue currentVal, IEnumerable values) + ReadRange(TWAIN twain, TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct { throw new NotImplementedException(); } + /// + /// Read the one value of a cap as string. Only STR* and HANDLE types are supported. + /// + /// + /// + /// + /// + public static string ReadOneString(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 (PlatformTools.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 + { + twain.DsmMemUnlock(cap.hContainer); + if (freeMemory) twain.DsmMemFree(ref cap.hContainer); + } + return null; + } /// /// Read the container pointer content. ///