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 */ } }