mirror of
https://github.com/soukoku/ntwain.git
synced 2025-09-19 01:57:56 +08:00
Added reading of supported caps.
This commit is contained in:
@@ -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,
|
||||
|
@@ -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)
|
||||
|
@@ -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
115
NTwain/ValueReader.cs
Normal 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));
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
Reference in New Issue
Block a user