From aea7ff4f05f6384826370de782fbdd44c51d1b92 Mon Sep 17 00:00:00 2001 From: Eugene Wang <8755753+soukoku@users.noreply.github.com> Date: Mon, 3 Apr 2023 23:06:10 -0400 Subject: [PATCH] Started on caps support. --- src/NTwain/Data/TWAINH.cs | 5 +- src/NTwain/Data/TWAINH_EXTRAS.cs | 47 ++++- src/NTwain/IMemoryManager.cs | 16 ++ src/NTwain/Triplets/ControlDATs/Capability.cs | 2 + src/NTwain/TwainSession.Caps.cs | 175 ++++++++++++++++++ src/NTwain/TwainSession.Memory.cs | 2 +- src/NTwain/TwainSession.cs | 2 +- 7 files changed, 236 insertions(+), 13 deletions(-) create mode 100644 src/NTwain/IMemoryManager.cs create mode 100644 src/NTwain/TwainSession.Caps.cs diff --git a/src/NTwain/Data/TWAINH.cs b/src/NTwain/Data/TWAINH.cs index a21cf07..464b7fa 100644 --- a/src/NTwain/Data/TWAINH.cs +++ b/src/NTwain/Data/TWAINH.cs @@ -1148,7 +1148,7 @@ namespace NTwain.Data /// Used by application to get/set capability from/in a data source. /// [StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Ansi)] - public struct TW_CAPABILITY + public partial struct TW_CAPABILITY { public CAP Cap; public TWON ConType; @@ -2557,6 +2557,7 @@ namespace NTwain.Data /// /// Flags used in TW_MEMORY structure. /// + [Flags] public enum TWMF : ushort { APPOWNS = 0x0001, @@ -3778,6 +3779,7 @@ namespace NTwain.Data /// /// Data Groups... /// + [Flags] public enum DG : uint { CONTROL = 0x1, @@ -4327,6 +4329,7 @@ namespace NTwain.Data /// 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 /// + [Flags] public enum TWQC : ushort { Unknown = 0, diff --git a/src/NTwain/Data/TWAINH_EXTRAS.cs b/src/NTwain/Data/TWAINH_EXTRAS.cs index 1745f52..00e217d 100644 --- a/src/NTwain/Data/TWAINH_EXTRAS.cs +++ b/src/NTwain/Data/TWAINH_EXTRAS.cs @@ -606,16 +606,28 @@ namespace NTwain.Data partial struct TW_STATUSUTF8 { /// - /// Tries to read the text content and frees the memory. + /// Frees the memory if necessary. /// - /// + /// + public void Free(IMemoryManager mgr) + { + // session already checks for zero + mgr.Free(UTF8string); + UTF8string = IntPtr.Zero; + } + + /// + /// Tries to read the text content and optionally frees the memory. + /// + /// + /// Whether to free the pointer after reads. /// - public string? ReadAndFree(TwainSession session) + public string? Read(IMemoryManager mgr, bool freeMemory = true) { string? val = null; if (UTF8string != IntPtr.Zero && Size > 0) { - var locked = session.Lock(UTF8string); + var locked = mgr.Lock(UTF8string); if (locked != IntPtr.Zero) { // does this work? who knows. @@ -637,22 +649,37 @@ namespace NTwain.Data } finally { - session.Unlock(UTF8string); + mgr.Unlock(UTF8string); } } } - Free(session); + if (freeMemory) Free(mgr); return val; } + } + + partial struct TW_CAPABILITY + { + public TW_CAPABILITY(CAP cap) + { + Cap = cap; + ConType = (TWON)TwainConst.TWON_DONTCARE16; + } /// /// Frees the memory if necessary. /// - /// - public void Free(TwainSession session) + /// + public void Free(IMemoryManager mgr) { - session.Free(UTF8string); - UTF8string = IntPtr.Zero; + // session already checks for zero + mgr.Free(hContainer); + hContainer = IntPtr.Zero; + } + + public void Read(IMemoryManager mgr, bool freeMemory = true) + { + if (freeMemory) Free(mgr); } } diff --git a/src/NTwain/IMemoryManager.cs b/src/NTwain/IMemoryManager.cs new file mode 100644 index 0000000..252a9dc --- /dev/null +++ b/src/NTwain/IMemoryManager.cs @@ -0,0 +1,16 @@ +using System; + +namespace NTwain +{ + /// + /// Something that can do the 4 memory mgmt + /// things required by TWAIN. + /// + public interface IMemoryManager + { + IntPtr Alloc(uint size); + void Free(IntPtr handle); + IntPtr Lock(IntPtr handle); + void Unlock(IntPtr handle); + } +} \ No newline at end of file diff --git a/src/NTwain/Triplets/ControlDATs/Capability.cs b/src/NTwain/Triplets/ControlDATs/Capability.cs index 668cef6..2915c81 100644 --- a/src/NTwain/Triplets/ControlDATs/Capability.cs +++ b/src/NTwain/Triplets/ControlDATs/Capability.cs @@ -28,6 +28,8 @@ namespace NTwain.Triplets.ControlDATs => DoIt(ref app, ref ds, MSG.RESETALL, ref data); public STS Set(ref TW_IDENTITY_LEGACY app, ref TW_IDENTITY_LEGACY ds, ref TW_CAPABILITY data) => DoIt(ref app, ref ds, MSG.SET, ref data); + public STS SetConstraint(ref TW_IDENTITY_LEGACY app, ref TW_IDENTITY_LEGACY ds, ref TW_CAPABILITY data) + => DoIt(ref app, ref ds, MSG.SETCONSTRAINT, ref data); static STS DoIt(ref TW_IDENTITY_LEGACY app, ref TW_IDENTITY_LEGACY ds, MSG msg, ref TW_CAPABILITY data) { diff --git a/src/NTwain/TwainSession.Caps.cs b/src/NTwain/TwainSession.Caps.cs new file mode 100644 index 0000000..844913b --- /dev/null +++ b/src/NTwain/TwainSession.Caps.cs @@ -0,0 +1,175 @@ +using NTwain.Data; +using NTwain.Triplets; +using System.Collections.Generic; +using System.Linq; + +namespace NTwain +{ + // this file contains capability mgmt methods + + partial class TwainSession + { + ///// + ///// Gets all the supported caps for the current source. + ///// + ///// + //public IEnumerable GetAllCaps() + //{ + // // just as a sample of how to read cap values + + // if (GetCapValues(CAP.CAP_SUPPORTEDCAPS, out TW_CAPABILITY value) == STS.SUCCESS) + // { + // value.Read(this); + // } + // return Enumerable.Empty(); + //} + + /// + /// Gets a CAP's actual supported operations. + /// This is not supported by all sources. + /// + /// + /// + public TWQC QueryCapSupport(CAP cap) + { + var value = new TW_CAPABILITY(cap); + if (DGControl.Capability.QuerySupport(ref _appIdentity, ref _currentDS, ref value) == STS.SUCCESS) + { + value.Read(this); + } + return TWQC.Unknown; + } + + /// + /// Gets a CAP's current value. + /// Caller will need to free the memory. + /// + /// + /// + /// + public STS GetCapCurrent(CAP cap, out TW_CAPABILITY value) + { + value = new TW_CAPABILITY(cap); + return DGControl.Capability.Get(ref _appIdentity, ref _currentDS, ref value); + } + + /// + /// Gets a CAP's default value. + /// Caller will need to free the memory. + /// + /// + /// + /// + public STS GetCapDefault(CAP cap, out TW_CAPABILITY value) + { + value = new TW_CAPABILITY(cap); + return DGControl.Capability.GetDefault(ref _appIdentity, ref _currentDS, ref value); + } + + /// + /// Gets a CAP's supported values. + /// Caller will need to free the memory. + /// + /// + /// + /// + public STS GetCapValues(CAP cap, out TW_CAPABILITY value) + { + value = new TW_CAPABILITY(cap); + return DGControl.Capability.Get(ref _appIdentity, ref _currentDS, ref value); + } + + /// + /// Gets a CAP's help text (description). + /// + /// + /// + /// + public STS GetCapHelp(CAP cap, out string? help) + { + help = null; + var value = new TW_CAPABILITY(cap); + var rc = DGControl.Capability.GetHelp(ref _appIdentity, ref _currentDS, ref value); + value.Free(this); + return rc; + } + + /// + /// Gets a CAP's text name label. + /// + /// + /// + /// + public STS GetCapLabel(CAP cap, out string? label) + { + label = null; + var value = new TW_CAPABILITY(cap); + var rc = DGControl.Capability.GetLabel(ref _appIdentity, ref _currentDS, ref value); + value.Free(this); + return rc; + } + + /// + /// Gets a CAP's value label texts. + /// + /// + /// + /// + public STS GetCapLabelEnum(CAP cap, out string[]? labels) + { + labels = null; + var value = new TW_CAPABILITY(cap); + var rc = DGControl.Capability.GetLabelEnum(ref _appIdentity, ref _currentDS, ref value); + value.Free(this); + return rc; + } + + /// + /// Sets a CAP's current value. + /// + /// + /// + public STS SetCap(ref TW_CAPABILITY value) + { + var rc = DGControl.Capability.Set(ref _appIdentity, ref _currentDS, ref value); + value.Free(this); + return rc; + } + + /// + /// Sets a CAP's constraint values. + /// + /// + /// + public STS SetConstraint(ref TW_CAPABILITY value) + { + var rc = DGControl.Capability.SetConstraint(ref _appIdentity, ref _currentDS, ref value); + value.Free(this); + return rc; + } + + /// + /// Resets a CAP's current value to power-on default. + /// Caller will need to free the memory. + /// + /// + /// + /// + public STS ResetCap(CAP cap, out TW_CAPABILITY value) + { + value = new TW_CAPABILITY(cap); + return DGControl.Capability.Reset(ref _appIdentity, ref _currentDS, ref value); + } + + /// + /// Resets all CAP values and constraint to power-on defaults. + /// + /// + public STS ResetAllCaps() + { + var value = new TW_CAPABILITY(CAP.CAP_SUPPORTEDCAPS); + var rc = DGControl.Capability.ResetAll(ref _appIdentity, ref _currentDS, ref value); + return rc; + } + } +} diff --git a/src/NTwain/TwainSession.Memory.cs b/src/NTwain/TwainSession.Memory.cs index 595a11c..597974a 100644 --- a/src/NTwain/TwainSession.Memory.cs +++ b/src/NTwain/TwainSession.Memory.cs @@ -7,7 +7,7 @@ namespace NTwain { // this file contains memory methods - partial class TwainSession + partial class TwainSession : IMemoryManager { internal TW_ENTRYPOINT_DELEGATES _entryPoint; diff --git a/src/NTwain/TwainSession.cs b/src/NTwain/TwainSession.cs index 2759fb6..0ea4682 100644 --- a/src/NTwain/TwainSession.cs +++ b/src/NTwain/TwainSession.cs @@ -256,7 +256,7 @@ namespace NTwain { if (DGControl.StatusUtf8.Get(ref _appIdentity, status, out TW_STATUSUTF8 extendedStatus) == STS.SUCCESS) { - return extendedStatus.ReadAndFree(this); + return extendedStatus.Read(this); } return null; }