From c6708687c8976564b7672bb464f9ffc89a023ef4 Mon Sep 17 00:00:00 2001 From: Yang Feixiang Date: Fri, 4 Sep 2020 02:22:45 +0000 Subject: [PATCH] 1. change getall device source name there no need new DataSource, just only productnme 2. add check device online 3. add one ext. prarameter when starting scan 4. add protocol version dictionary --- src/TwainDotNet/DataSource.cs | 84 +++++++- src/TwainDotNet/DataSourceManager.cs | 12 +- src/TwainDotNet/ProtocolVersions.cs | 209 +++++++++++++++++++ src/TwainDotNet/ScanningCompleteEventArgs.cs | 4 +- src/TwainDotNet/TransferImageEventArgs.cs | 12 +- src/TwainDotNet/Twain.cs | 20 +- src/TwainDotNet/TwainDotNet.csproj | 1 + src/TwainDotNet/TwainNative/Capabilities.cs | 36 +++- 8 files changed, 340 insertions(+), 38 deletions(-) create mode 100644 src/TwainDotNet/ProtocolVersions.cs diff --git a/src/TwainDotNet/DataSource.cs b/src/TwainDotNet/DataSource.cs index cb93fde..071c40c 100644 --- a/src/TwainDotNet/DataSource.cs +++ b/src/TwainDotNet/DataSource.cs @@ -146,6 +146,27 @@ public bool SupportsDuplex } } + public bool CheckDeviceOnline() + { + try + { + var sourceVersion = new Version(SourceId.ProtocolMajor, SourceId.ProtocolMinor); + var minVer = ProtocolVersions.GetMinimumVersion(Capabilities.DeviceOnline); + if (sourceVersion >= minVer) + { + //var cap = new Capability(Capabilities.DeviceOnline, TwainType.Bool, _applicationId, SourceId); + var cap = Capability.GetBoolCapability(Capabilities.DeviceOnline, _applicationId, SourceId); + if (!cap) + throw new TwainException($"{SourceId.ProductName} is offline."); + } + return true; + } + catch + { + return false; + } + } + public void NegotiateColour(ScanSettings scanSettings) { try @@ -301,6 +322,7 @@ public void NegotiateProgressIndicator(ScanSettings scanSettings) public bool Open(ScanSettings settings) { OpenSource(); + CheckDeviceOnline(); if (settings.AbortWhenNoPaperDetectable && !PaperDetectable) throw new FeederEmptyException(); @@ -464,10 +486,9 @@ public static DataSource UserSelected(Identity applicationId, IWindowsMessageHoo return new DataSource(applicationId, defaultSourceId, messageHook); } - - public static List GetAllSources(Identity applicationId, IWindowsMessageHook messageHook) + public static List GetAllSourceNames(Identity applicationId) { - var sources = new List(); + var sources = new List(); Identity id = new Identity(); // Get the first source @@ -489,11 +510,12 @@ public static List GetAllSources(Identity applicationId, IWindowsMes } else { - sources.Add(new DataSource(applicationId, id, messageHook)); + sources.Add(id.ProductName); } while (true) { + id = new Identity(); // Get the next source result = Twain32Native.DsmIdentity( applicationId, @@ -512,20 +534,62 @@ public static List GetAllSources(Identity applicationId, IWindowsMes throw new TwainException("Error enumerating sources.", result); } - sources.Add(new DataSource(applicationId, id, messageHook)); + sources.Add(id.ProductName); } return sources; } - + public static DataSource GetSource(string sourceProductName, Identity applicationId, IWindowsMessageHook messageHook) { - // A little slower than it could be, if enumerating unnecessary sources is slow. But less code duplication. - foreach (var source in GetAllSources(applicationId, messageHook)) + Identity id = new Identity(); + + // Get the first source + var result = Twain32Native.DsmIdentity( + applicationId, + IntPtr.Zero, + DataGroup.Control, + DataArgumentType.Identity, + Message.GetFirst, + id); + + if (result == TwainResult.EndOfList) + { + return null; + } + else if (result != TwainResult.Success) + { + throw new TwainException("Error getting first source.", result); + } + else if (id.ProductName == sourceProductName) + { + return new DataSource(applicationId, id, messageHook); + } + + while (true) { - if (sourceProductName.Equals(source.SourceId.ProductName, StringComparison.InvariantCultureIgnoreCase)) + id = new Identity(); + // Get the next source + result = Twain32Native.DsmIdentity( + applicationId, + IntPtr.Zero, + DataGroup.Control, + DataArgumentType.Identity, + Message.GetNext, + id); + + if (result == TwainResult.EndOfList) + { + break; + } + else if (result != TwainResult.Success) + { + throw new TwainException("Error enumerating sources.", result); + } + + else if (id.ProductName == sourceProductName) { - return source; + return new DataSource(applicationId, id, messageHook); } } diff --git a/src/TwainDotNet/DataSourceManager.cs b/src/TwainDotNet/DataSourceManager.cs index 19b11bb..0841a12 100644 --- a/src/TwainDotNet/DataSourceManager.cs +++ b/src/TwainDotNet/DataSourceManager.cs @@ -18,6 +18,7 @@ public class DataSourceManager : IDisposable IWindowsMessageHook _messageHook; Event _eventMessage; + private object _extTag = null; public Identity ApplicationId { get; private set; } public DataSource DataSource { get; private set; } @@ -72,14 +73,15 @@ public DataSourceManager(Identity applicationId, IWindowsMessageHook messageHook public IWindowsMessageHook MessageHook { get { return _messageHook; } } - public void StartScan(ScanSettings settings) - { + public bool StartScan(ScanSettings settings, object extTag) + { bool scanning = false; - try { + _extTag = extTag; _messageHook.UseFilter = true; scanning = DataSource.Open(settings); + return scanning; } catch (TwainException e) { @@ -235,7 +237,7 @@ protected void TransferPictures() { using (var renderer = new BitmapRenderer(hbitmap)) { - TransferImageEventArgs args = new TransferImageEventArgs(renderer.RenderToBitmap(), pendingTransfer.Count != 0); + TransferImageEventArgs args = new TransferImageEventArgs(renderer.RenderToBitmap(), pendingTransfer.Count, this._extTag); TransferImage(this, args); if (!args.ContinueScanning) break; @@ -263,7 +265,7 @@ protected void CloseDsAndCompleteScanning(Exception exception) DataSource.Close(); try { - ScanningComplete(this, new ScanningCompleteEventArgs(exception)); + ScanningComplete(this, new ScanningCompleteEventArgs(exception,this._extTag)); } catch { diff --git a/src/TwainDotNet/ProtocolVersions.cs b/src/TwainDotNet/ProtocolVersions.cs new file mode 100644 index 0000000..c38fc5f --- /dev/null +++ b/src/TwainDotNet/ProtocolVersions.cs @@ -0,0 +1,209 @@ + +using System; +using System.Collections.Generic; +using TwainDotNet.TwainNative; + +namespace TwainDotNet +{ + /// + /// Contains the minimum TWAIN protocol version for various things. + /// + public static class ProtocolVersions + { + internal static readonly Version v10 = new Version(1, 0); + internal static readonly Version v11 = new Version(1, 1); + internal static readonly Version v15 = new Version(1, 5); + internal static readonly Version v16 = new Version(1, 6); + internal static readonly Version v17 = new Version(1, 7); + internal static readonly Version v18 = new Version(1, 8); + internal static readonly Version v19 = new Version(1, 9); + internal static readonly Version v20 = new Version(2, 0); + internal static readonly Version v21 = new Version(2, 1); + internal static readonly Version v22 = new Version(2, 2); + internal static readonly Version v23 = new Version(2, 3); + + + static readonly Dictionary __capMinVersions = new Dictionary + { + { Capabilities.AXferMech , v18 }, + { Capabilities.Alarms, v18 }, + { Capabilities.AlarmVolume, v18 }, + { Capabilities.Author, v10 }, + { Capabilities.AutoFeed, v10 }, + { Capabilities.AutomaticCapture, v18 }, + { Capabilities.AutomaticSenseMedium, v21 }, + { Capabilities.AutoScan, v16 }, + { Capabilities.BatteryMinutes, v18 }, + { Capabilities.BatteryPercentage, v18 }, + { Capabilities.CameraEnabled, v20 }, + { Capabilities.CameraOrder, v20 }, + { Capabilities.CameraPreviewUI, v18 }, + { Capabilities.CameraSide, v19 }, + { Capabilities.Caption, v10 }, + { Capabilities.ClearBuffers, v18 }, + { Capabilities.ClearPage, v10 }, + { Capabilities.CustomDSData, v17 }, + { Capabilities.CustomInterfaceGuid, v21 }, + { Capabilities.DeviceEvent, v18 }, + { Capabilities.DeviceOnline, v16 }, + { Capabilities.DeviceTimeDate, v18 }, + { Capabilities.DoubleFeedDetection, v22 }, + { Capabilities.DoubleFeedDetectionLength, v22 }, + { Capabilities.DoubleFeedDetectionResponse, v22 }, + { Capabilities.DoubleFeedDetectionSensitivity, v22 }, + { Capabilities.Duplex, v17 }, + { Capabilities.DuplexEnabled, v17 }, + { Capabilities.Enabledsuionly, v17 }, + { Capabilities.Endorser, v17 }, + { Capabilities.Extendedcaps, v10 }, + { Capabilities.FeederAlignment, v18 }, + { Capabilities.FeederEnabled, v10 }, + { Capabilities.FeederLoaded, v10 }, + { Capabilities.FeederOrder, v18 }, + { Capabilities.Feederpocket, v20 }, + { Capabilities.FeederPrep, v20}, + { Capabilities.FeedPage, v10 }, + { Capabilities.Indicators, v11 }, + { Capabilities.IndicatorsMode, v22 }, + { Capabilities.JobControl, v17 }, + { Capabilities.Language, v18 }, + { Capabilities.MaxBatchBuffers, v18 }, + { Capabilities.MicrEnabled, v20 }, + { Capabilities.PaperDetectable, v16 }, + { Capabilities.PaperHandling, v22 }, + { Capabilities.PowerSaveTime, v18 }, + { Capabilities.PowerSupply, v18 }, + { Capabilities.Printer, v18 }, + { Capabilities.PrinterEnabled, v18 }, + { Capabilities.PrinterCharRotation, v23 }, + { Capabilities.PrinterFontStyle, v23 }, + { Capabilities.PrinterIndex, v18 }, + { Capabilities.PrinterIndexLeadChar, v23 }, + { Capabilities.PrinterIndexMaxValue, v23 }, + { Capabilities.PrinterIndexNumDigits, v23 }, + { Capabilities.PrinterIndexStep, v23 }, + { Capabilities.PrinterIndexTrigger, v23 }, + { Capabilities.PrinterMode, v18 }, + { Capabilities.PrinterString, v18 }, + { Capabilities.PrinterStringPreview, v23 }, + { Capabilities.PrinterSuffix, v18 }, + { Capabilities.PrinterVerticalOffset, v22 }, + { Capabilities.ReAcquireAllowed, v18 }, + { Capabilities.RewindPage, v10 }, + { Capabilities.Segmented, v19 }, + { Capabilities.SerialNumber, v18 }, + { Capabilities.SupportedCapabilities, v10 }, + { Capabilities.SupportedCapsSegmentUnique, v22 }, + { Capabilities.SupportedDATs, v22 }, + { Capabilities.TimeBeforeFirstCapture, v18 }, + { Capabilities.TimeBetweenCaptures, v18 }, + { Capabilities.Timedate, v10 }, + { Capabilities.ThumbnailsEnabled, v17 }, + { Capabilities.UIControllable, v16 }, + { Capabilities.XferCount, v10 }, + + { Capabilities.Autobright, v10 }, + { Capabilities.AutoDiscardBlankPages, v20 }, + { Capabilities.Automaticborderdetection, v18 }, + { Capabilities.AutomaticColorEnabled, v21 }, + { Capabilities.AutomaticColorNonColorPixelType, v18 }, + { Capabilities.AutomaticCropUsesFrame, v21 }, + { Capabilities.Automaticdeskew, v18 }, + { Capabilities.AutomaticLengthDetection, v21 }, + { Capabilities.Automaticrotate, v18 }, + { Capabilities.Autosize, v20 }, + { Capabilities.Barcodedetectionenabled, v18 }, + { Capabilities.Barcodemaxretries, v18 }, + { Capabilities.Barcodemaxsearchpriorities, v18 }, + { Capabilities.Barcodesearchmode, v18 }, + { Capabilities.Barcodesearchpriorities, v18 }, + { Capabilities.Barcodetimeout, v18 }, + { Capabilities.BitDepth, v10 }, + { Capabilities.Bitdepthreduction, v15 }, + { Capabilities.Bitorder, v10 }, + { Capabilities.Bitordercodes, v10 }, + { Capabilities.Brightness, v10 }, + { Capabilities.Ccittkfactor, v10 }, + { Capabilities.ColorManagementEnabled, v21 }, + { Capabilities.ICompression, v10 }, + { Capabilities.Contrast, v10 }, + { Capabilities.CustHalftone, v10 }, + { Capabilities.ExposureTime, v10 }, + { Capabilities.Extimageinfo, v17 }, + { Capabilities.Feedertype, v19 }, + { Capabilities.FilmType, v22 }, + { Capabilities.Filter, v10 }, + { Capabilities.Flashused, v16 }, // maybe + { Capabilities.Flashused2, v18 }, + { Capabilities.Fliprotation, v18 }, + { Capabilities.Frames, v10 }, + { Capabilities.Gamma, v10 }, + { Capabilities.Halftones, v10 }, + { Capabilities.Highlight, v10 }, + { Capabilities.Iccprofile, v19 }, + { Capabilities.Imagedataset, v17 }, + { Capabilities.ImageFileFormat, v10 }, + { Capabilities.Imagefilter, v18 }, + { Capabilities.ImageMerge, v21 }, + { Capabilities.ImageMergeHeightThreshold, v21 }, + { Capabilities.Jpegpixeltype, v10 }, + { Capabilities.Jpegquality, v19 }, + { Capabilities.JpegSubsampling, v22 }, + { Capabilities.LampState, v10 }, + { Capabilities.Lightpath, v10 }, + { Capabilities.LightSource, v10 }, + { Capabilities.MaxFrames, v10 }, + { Capabilities.Minimumheight, v17 }, + { Capabilities.Minimumwidth, v17 }, + { Capabilities.Mirror, v22 }, + { Capabilities.Noisefilter, v18 }, + { Capabilities.Orientation, v10 }, + { Capabilities.Overscan, v18 }, + { Capabilities.Patchcodedetectionenabled, v18 }, + { Capabilities.Patchcodemaxretries, v18 }, + { Capabilities.Patchcodemaxsearchpriorities, v18 }, + { Capabilities.Patchcodesearchmode, v18 }, + { Capabilities.Patchcodesearchpriorities, v18 }, + { Capabilities.Patchcodetimeout, v18 }, + { Capabilities.PhysicalHeight, v10 }, + { Capabilities.PhysicalWidth, v10 }, + { Capabilities.Pixelflavor, v10 }, + { Capabilities.Pixelflavorcodes, v10 }, + { Capabilities.IPixelType, v10 }, + { Capabilities.Planarchunky, v10 }, + { Capabilities.Rotation, v10 }, + { Capabilities.Shadow, v10 }, + { Capabilities.Supportedbarcodetypes, v18 }, + { Capabilities.SupportedExtImageInfo, v21 }, + { Capabilities.Supportedpatchcodetypes, v18 }, + { Capabilities.Supportedsizes, v10 }, + { Capabilities.Threshold, v10 }, + { Capabilities.Tiles, v10 }, + { Capabilities.Timefill, v10 }, + { Capabilities.Undefinedimagesize, v16 }, + { Capabilities.IUnits, v10 }, + { Capabilities.IXferMech, v10 }, + { Capabilities.XNativeResolution, v10 }, + { Capabilities.XResolution, v10 }, + { Capabilities.Xscaling, v10 }, + { Capabilities.YNativeResolution, v10 }, + { Capabilities.YResolution, v10 }, + { Capabilities.Yscaling, v10 }, + { Capabilities.Zoomfactor, v18 }, + }; + + /// + /// Gets the minimum TWAIN protocol version for a capability. + /// + /// The capability type. + /// + public static Version GetMinimumVersion(Capabilities id) + { + if (__capMinVersions.ContainsKey(id)) + { + return __capMinVersions[id]; + } + return v10; + } + } +} diff --git a/src/TwainDotNet/ScanningCompleteEventArgs.cs b/src/TwainDotNet/ScanningCompleteEventArgs.cs index fcc8d90..18e739b 100644 --- a/src/TwainDotNet/ScanningCompleteEventArgs.cs +++ b/src/TwainDotNet/ScanningCompleteEventArgs.cs @@ -5,9 +5,11 @@ namespace TwainDotNet public class ScanningCompleteEventArgs : EventArgs { public Exception Exception { get; private set; } + public object ExtTag { private set; get; } - public ScanningCompleteEventArgs(Exception exception) + public ScanningCompleteEventArgs(Exception exception,object extTag) { + this.ExtTag = extTag; this.Exception = exception; } } diff --git a/src/TwainDotNet/TransferImageEventArgs.cs b/src/TwainDotNet/TransferImageEventArgs.cs index 259c515..8b47bd4 100644 --- a/src/TwainDotNet/TransferImageEventArgs.cs +++ b/src/TwainDotNet/TransferImageEventArgs.cs @@ -6,12 +6,18 @@ namespace TwainDotNet public class TransferImageEventArgs : EventArgs { public Bitmap Image { get; private set; } - public bool ContinueScanning { get; set; } + public bool ContinueScanning { get; private set; } + public int Count { get; set; } - public TransferImageEventArgs(Bitmap image, bool continueScanning) + public object ExtTag { set; get; } + + + public TransferImageEventArgs(Bitmap image, int count,object extTag) { this.Image = image; - this.ContinueScanning = continueScanning; + this.Count = count; + this.ContinueScanning = count != 0; + this.ExtTag = extTag; } } } diff --git a/src/TwainDotNet/Twain.cs b/src/TwainDotNet/Twain.cs index 9671912..9244d94 100644 --- a/src/TwainDotNet/Twain.cs +++ b/src/TwainDotNet/Twain.cs @@ -39,9 +39,9 @@ public Twain(IWindowsMessageHook messageHook) /// /// Starts scanning. /// - public void StartScanning(ScanSettings settings) + public bool StartScanning(ScanSettings settings, object extTag ) { - _dataSourceManager.StartScan(settings); + return _dataSourceManager.StartScan(settings, extTag); } /// @@ -86,19 +86,9 @@ public string DefaultSourceName public IList SourceNames { get - { - var result = new List(); - var sources = DataSource.GetAllSources( - _dataSourceManager.ApplicationId, - _dataSourceManager.MessageHook); - - foreach (var source in sources) - { - result.Add(source.SourceId.ProductName); - source.Dispose(); - } - - return result; + { + var sources = DataSource.GetAllSourceNames(_dataSourceManager.ApplicationId); + return sources; } } } diff --git a/src/TwainDotNet/TwainDotNet.csproj b/src/TwainDotNet/TwainDotNet.csproj index 23145d3..a641101 100644 --- a/src/TwainDotNet/TwainDotNet.csproj +++ b/src/TwainDotNet/TwainDotNet.csproj @@ -58,6 +58,7 @@ + diff --git a/src/TwainDotNet/TwainNative/Capabilities.cs b/src/TwainDotNet/TwainNative/Capabilities.cs index 293e9f9..4d06ee6 100644 --- a/src/TwainDotNet/TwainNative/Capabilities.cs +++ b/src/TwainDotNet/TwainNative/Capabilities.cs @@ -28,7 +28,8 @@ public enum Capabilities : short ClearPage = 0x1008, FeedPage = 0x1009, RewindPage = 0x100a, - + CustomDSData = 0xc, + [Description("Controls progress indicator window during transfer and acquisition")] Indicators = 0x100b, SupportedCapsExt = 0x100c, @@ -74,6 +75,20 @@ public enum Capabilities : short MicrEnabled = 0x1038, FeederPrep = 0x1039, Feederpocket = 0x103a, + SupportedCapsSegmentUnique = 0x103d, + SupportedDATs = 0x103e, + PaperHandling = 0x1043, + IndicatorsMode = 0x1044, + PrinterVerticalOffset = 0x1045, + PowerSaveTime = 0x1046, + PrinterCharRotation = 0x1047, + PrinterFontStyle = 0x1048, + PrinterIndexLeadChar = 0x1049, + PrinterIndexMaxValue = 0x104A, + PrinterIndexNumDigits = 0x104B, + PrinterIndexStep = 0x104C, + PrinterIndexTrigger = 0x104D, + PrinterStringPreview = 0x104E, // image data sources MAY support these capabilities Autobright = 0x1100, @@ -122,6 +137,7 @@ public enum Capabilities : short Extimageinfo = 0x112f, Minimumheight = 0x1130, Minimumwidth = 0x1131, + AutoDiscardBlankPages = 0x1134, /* Added 2.0 */ Fliprotation = 0x1136, Barcodedetectionenabled = 0x1137, Supportedbarcodetypes = 0x1138, @@ -155,9 +171,21 @@ public enum Capabilities : short AutomaticColorNonColorPixelType = 0x115a, /* Added 2.1 */ ColorManagementEnabled = 0x115b, /* Added 2.1 */ ImageMerge = 0x115c, /* Added 2.1 */ - ImageMergeHeightThreshold = 0x115d, /* Added 2.1 */ - SupoortedExtImageInfo = 0x115e, /* Added 2.1 */ + ImageMergeHeightThreshold = 0x115d, /* Added 2.1 */ + SupportedExtImageInfo = 0x115e, /* Added 2.1 */ + FilmType = 0x115f, + Mirror = 0x1160, + JpegSubsampling = 0x1161, Audiofileformat = 0x1201, - Xfermech = 0x1202 + + AutomaticSenseMedium = 0x103b, /* Added 2.1 */ + CustomInterfaceGuid = 0x103c, /* Added 2.1 */ + DoubleFeedDetection = 0x103f, + DoubleFeedDetectionLength = 0x1040, + DoubleFeedDetectionSensitivity = 0x1041, + DoubleFeedDetectionResponse = 0x1042, + + /* image data sources MAY support these audio caps */ + AXferMech = 0x1202, /* Added 1.8 */ } }