Added reading of supported caps.

This commit is contained in:
Eugene Wang
2021-04-24 22:24:24 -04:00
parent 0416b281ba
commit e0f1f96947
5 changed files with 228 additions and 4 deletions

View File

@@ -2546,6 +2546,7 @@ namespace TWAINWorkingGroup
/// <summary>
/// Flags used in TW_MEMORY structure.
/// </summary>
[Flags]
public enum TWMF : ushort
{
APPOWNS = 0x0001,
@@ -3753,6 +3754,7 @@ namespace TWAINWorkingGroup
/// <summary>
/// Data Groups...
/// </summary>
[Flags]
public enum DG : uint
{
CONTROL = 0x1,
@@ -4273,6 +4275,7 @@ namespace TWAINWorkingGroup
/// bit patterns: for query the operation that are supported by the data source on a capability
/// Application gets these through DG_CONTROL/DAT_CAPABILITY/MSG_QUERYSUPPORT
/// </summary>
[Flags]
public enum TWQC : ushort
{
GET = 0x0001,

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace TWAINWorkingGroup
{
// contains my additions
// contains my additions that makes twain types easier to work with.
partial struct TW_FIX32 : IEquatable<TW_FIX32>
{
@@ -15,7 +15,11 @@ namespace TWAINWorkingGroup
float ToFloat()
{
return (float)Whole + Frac / 65536f;
return Whole + Frac / 65536f;
}
double ToDouble()
{
return Whole + Frac / 65536.0;
}
TW_FIX32(float value)
{
@@ -55,7 +59,7 @@ namespace TWAINWorkingGroup
public static implicit operator float(TW_FIX32 value) => value.ToFloat();
public static implicit operator TW_FIX32(float value) => new TW_FIX32(value);
public static implicit operator double(TW_FIX32 value) => value.ToFloat();
public static implicit operator double(TW_FIX32 value) => value.ToDouble();
public static implicit operator TW_FIX32(double value) => new TW_FIX32((float)value);
public static bool operator ==(TW_FIX32 value1, TW_FIX32 value2) => value1.Equals(value2);
@@ -64,9 +68,33 @@ namespace TWAINWorkingGroup
partial struct TW_FRAME : IEquatable<TW_FRAME>
{
/// <summary>
/// Creates <see cref="TW_FRAME"/> from a string representation of it.
/// </summary>
/// <param name="value"></param>
public TW_FRAME(string value) : this()
{
var parts = value.Split(',');
if (parts.Length == 4)
{
Left = float.Parse(parts[0]);
Top = float.Parse(parts[1]);
Right = float.Parse(parts[2]);
Bottom = float.Parse(parts[3]);
}
else
{
throw new ArgumentException($"Cannot create frame from \"{value}\".");
}
}
/// <summary>
/// String representation of Left,Top,Right,Bottom.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"L={Left}, T={Top}, R={Right}, B={Bottom}";
return $"{Left},{Top},{Right},{Bottom}";
}
public bool Equals(TW_FRAME other)

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
@@ -285,6 +286,62 @@ namespace NTwain
}
}
/// <summary>
/// Queries current device for supported capabilities.
/// Not all devices supports this.
/// </summary>
/// <returns></returns>
public IEnumerable<CAP> SupportedCaps()
{
List<CAP> caps = null;
if (State >= STATE.S4)
{
TW_CAPABILITY cap = default;
// get list of supported caps
cap.Cap = CAP.CAP_SUPPORTEDCAPS;
var sts = _twain.DatCapability(DG.CONTROL, MSG.GET, ref cap);
if (sts == STS.SUCCESS)
{
var csv = TWAIN.CapabilityToCsv(cap, true);
caps = csv.Split(',').Skip(4).Select(val =>
{
if (Enum.TryParse(val, out CAP c))
{
return c;
}
else if (val.StartsWith("0x"))
{
return (CAP)Convert.ToUInt16(val, 16);
}
else if (ushort.TryParse(val, out ushort num))
{
return (CAP)num;
}
return (CAP)0;
}).ToList();
}
//foreach (CAP capId in Enum.GetValues(typeof(CAP)))
//{
// cap.ConType = TWON.ONEVALUE;
// cap.Cap = capId;
// var sts = _twain.DatCapability(DG.CONTROL, MSG.QUERYSUPPORT, ref cap);
// if (sts == STS.SUCCESS)
// {
// if (Enum.TryParse(_twain.CapabilityOneValueToString(cap), out TWQC qc))
// {
// }
// }
//}
}
return caps ?? Enumerable.Empty<CAP>();
}
/// <summary>
/// Attempts to show the current device's settings dialog if supported.
/// </summary>

115
NTwain/ValueReader.cs Normal file
View File

@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using TWAINWorkingGroup;
namespace NTwain
{
/// <summary>
/// Contains extension methods for reading pointers into various things.
/// </summary>
public static class ValueReader
{
/// <summary>
/// Read capability's container content as ToString()'d one value.
/// </summary>
/// <param name="twain">Low-level twain object.</param>
/// <param name="cap">Cap to read from.</param>
/// <returns></returns>
public static string CapabilityOneValueToString(this TWAIN twain, TW_CAPABILITY cap)
{
if (cap.hContainer == IntPtr.Zero) return null;
var lockedPtr = twain.DsmMemLock(cap.hContainer);
try
{
TWTY itemType;
// Mac has a level of indirection and a different structure (ick)...
if (PlatformTools.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var onevalue = lockedPtr.MarshalTo<TW_ONEVALUE_MACOSX>();
itemType = (TWTY)onevalue.ItemType;
lockedPtr += Marshal.SizeOf(onevalue);
}
else
{
// Crack the container...
var onevalue = lockedPtr.MarshalTo<TW_ONEVALUE>();
itemType = onevalue.ItemType;
lockedPtr += Marshal.SizeOf(onevalue);
}
return lockedPtr.ContainerToString(itemType);
}
finally
{
// All done...
twain.DsmMemUnlock(cap.hContainer);
}
}
/// <summary>
/// Read the container pointer content as a string. Numeric values are ToString()'d.
/// </summary>
/// <param name="intptr">A locked pointer to the container data. 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 string ContainerToString(this IntPtr intptr, TWTY type, int itemIndex = 0)
{
switch (type)
{
default:
throw new NotSupportedException($"Unknown item type {type} to read as string.");
case TWTY.INT8:
intptr += 1 * itemIndex;
return intptr.MarshalToString<sbyte>();
case TWTY.INT16:
intptr += 2 * itemIndex;
return intptr.MarshalToString<short>();
case TWTY.INT32:
intptr += 4 * itemIndex;
return intptr.MarshalToString<int>();
case TWTY.UINT8:
intptr += 1 * itemIndex;
return intptr.MarshalToString<byte>();
case TWTY.BOOL:
case TWTY.UINT16:
intptr += 2 * itemIndex;
return intptr.MarshalToString<ushort>();
case TWTY.UINT32:
intptr += 4 * itemIndex;
return intptr.MarshalToString<uint>();
case TWTY.FIX32:
intptr += 4 * itemIndex;
return intptr.MarshalToString<TW_FIX32>();
case TWTY.FRAME:
intptr += 16 * itemIndex;
return intptr.MarshalToString<TW_FRAME>();
case TWTY.STR32:
intptr += TW_STR32.Size * itemIndex;
return intptr.MarshalToString<TW_STR32>();
case TWTY.STR64:
intptr += TW_STR64.Size * itemIndex;
return intptr.MarshalToString<TW_STR64>();
case TWTY.STR128:
intptr += TW_STR128.Size * itemIndex;
return intptr.MarshalToString<TW_STR128>();
case TWTY.STR255:
intptr += TW_STR255.Size * itemIndex;
return intptr.MarshalToString<TW_STR255>();
case TWTY.HANDLE:
intptr += IntPtr.Size * itemIndex;
return Marshal.ReadIntPtr(intptr).ToString();
}
}
static string MarshalToString<T>(this IntPtr ptr) => Marshal.PtrToStructure(ptr, typeof(T)).ToString();
static T MarshalTo<T>(this IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T));
}
}

View File

@@ -1,5 +1,6 @@
using NTwain;
using System;
using System.Linq;
using System.Reflection;
using System.Threading;
using TWAINWorkingGroup;
@@ -12,6 +13,7 @@ namespace Net5Console
static void Main(string[] args)
{
Console.WriteLine("Starting twain test in console...");
Console.WriteLine();
using (var session = new TwainSession(Assembly.GetExecutingAssembly(), null, IntPtr.Zero))
using (var hold = new ManualResetEventSlim())
@@ -19,10 +21,12 @@ namespace Net5Console
session.DeviceEvent += (sender, e) =>
{
Console.WriteLine($"Got device event " + (TWDE)e.Event);
Console.WriteLine();
};
session.ScanEvent += (sender, closing) =>
{
Console.WriteLine($"Got scan event " + closing);
Console.WriteLine();
// don't care, just end it
TW_PENDINGXFERS pending = default;
@@ -32,10 +36,12 @@ namespace Net5Console
if (session.TWAIN.DatUserinterface(DG.CONTROL, MSG.DISABLEDS, ref twuserinterface) == STS.SUCCESS)
{
Console.WriteLine("Disabled device.");
Console.WriteLine();
}
else
{
Console.Error.WriteLine("Failed to disabled device.");
Console.WriteLine();
}
hold.Set();
};
@@ -43,9 +49,11 @@ namespace Net5Console
if (session.Open() == TWAINWorkingGroup.STS.SUCCESS)
{
Console.WriteLine("Opened DSM");
Console.WriteLine();
Console.WriteLine("Default device:");
Console.WriteLine($"\t{session.DefaultDevice}");
Console.WriteLine();
Console.WriteLine("All devices:");
TW_IDENTITY dsToUse = default;
@@ -57,28 +65,41 @@ namespace Net5Console
dsToUse = dev;
}
}
Console.WriteLine();
session.CurrentDevice = dsToUse;
if (session.CurrentDevice.HasValue)
{
Console.WriteLine("Current device after opening attempt:");
Console.WriteLine($"\t{session.CurrentDevice}");
Console.WriteLine();
var caps = session.SupportedCaps();
Console.WriteLine("Device supports these caps:");
foreach (var cap in caps.OrderBy(c => c))
{
Console.WriteLine($"\t{cap}");
}
Console.WriteLine();
var sts = session.StartCapture(false);
if (sts == STS.SUCCESS)
{
Console.Error.WriteLine("Waiting for capture to complete.");
Console.WriteLine();
while (!hold.IsSet) Thread.Sleep(100);
}
else
{
Console.Error.WriteLine("Failed to start capture: " + sts);
Console.WriteLine();
}
}
else
{
Console.WriteLine("No devices opened.");
Console.WriteLine();
}
}
else