diff --git a/samples/WinForm32/Form1.Designer.cs b/samples/WinForm32/Form1.Designer.cs index 1ee4b54..37d4f58 100644 --- a/samples/WinForm32/Form1.Designer.cs +++ b/samples/WinForm32/Form1.Designer.cs @@ -41,11 +41,17 @@ lblState = new System.Windows.Forms.Label(); label3 = new System.Windows.Forms.Label(); btnOpenDef = new System.Windows.Forms.Button(); - listCaps = new System.Windows.Forms.ListBox(); label4 = new System.Windows.Forms.Label(); btnStart = new System.Windows.Forms.Button(); btnShowSettings = new System.Windows.Forms.Button(); btnClose = new System.Windows.Forms.Button(); + capListView = new System.Windows.Forms.ListView(); + colCap = new System.Windows.Forms.ColumnHeader(); + colType = new System.Windows.Forms.ColumnHeader(); + colCur = new System.Windows.Forms.ColumnHeader(); + colDef = new System.Windows.Forms.ColumnHeader(); + colSupport = new System.Windows.Forms.ColumnHeader(); + colExtended = new System.Windows.Forms.ColumnHeader(); ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); splitContainer1.Panel1.SuspendLayout(); splitContainer1.Panel2.SuspendLayout(); @@ -160,7 +166,7 @@ // // splitContainer1.Panel2 // - splitContainer1.Panel2.Controls.Add(listCaps); + splitContainer1.Panel2.Controls.Add(capListView); splitContainer1.Panel2.Controls.Add(label4); splitContainer1.Panel2.Controls.Add(btnStart); splitContainer1.Panel2.Controls.Add(btnShowSettings); @@ -199,15 +205,6 @@ btnOpenDef.UseVisualStyleBackColor = true; btnOpenDef.Click += btnOpenDef_Click; // - // listCaps - // - listCaps.FormattingEnabled = true; - listCaps.ItemHeight = 15; - listCaps.Location = new System.Drawing.Point(13, 87); - listCaps.Name = "listCaps"; - listCaps.Size = new System.Drawing.Size(234, 469); - listCaps.TabIndex = 8; - // // label4 // label4.AutoSize = true; @@ -247,11 +244,54 @@ btnClose.UseVisualStyleBackColor = true; btnClose.Click += btnClose_Click; // + // capListView + // + capListView.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + capListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { colCap, colType, colCur, colDef, colExtended, colSupport }); + capListView.FullRowSelect = true; + capListView.Location = new System.Drawing.Point(11, 87); + capListView.MultiSelect = false; + capListView.Name = "capListView"; + capListView.Size = new System.Drawing.Size(671, 462); + capListView.TabIndex = 8; + capListView.UseCompatibleStateImageBehavior = false; + capListView.View = System.Windows.Forms.View.Details; + // + // colCap + // + colCap.Text = "CAP"; + colCap.Width = 230; + // + // colType + // + colType.Text = "Type"; + colType.Width = 80; + // + // colCur + // + colCur.Text = "Current"; + colCur.Width = 80; + // + // colDef + // + colDef.Text = "Default"; + colDef.Width = 80; + // + // colSupport + // + colSupport.Text = "Supports"; + colSupport.Width = 330; + // + // colExtended + // + colExtended.Text = "Extended"; + colExtended.Width = 80; + // // Form1 // AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - ClientSize = new System.Drawing.Size(1023, 564); + ClientSize = new System.Drawing.Size(1123, 564); Controls.Add(splitContainer1); Name = "Form1"; Text = "TWAIN Test"; @@ -282,7 +322,13 @@ private System.Windows.Forms.Label label3; private System.Windows.Forms.Button btnShowSettings; private System.Windows.Forms.Button btnStart; - private System.Windows.Forms.ListBox listCaps; private System.Windows.Forms.Label label4; + private System.Windows.Forms.ListView capListView; + private System.Windows.Forms.ColumnHeader colCap; + private System.Windows.Forms.ColumnHeader colType; + private System.Windows.Forms.ColumnHeader colCur; + private System.Windows.Forms.ColumnHeader colDef; + private System.Windows.Forms.ColumnHeader colSupport; + private System.Windows.Forms.ColumnHeader colExtended; } } \ No newline at end of file diff --git a/samples/WinForm32/Form1.cs b/samples/WinForm32/Form1.cs index 63c2bb4..00ab4a8 100644 --- a/samples/WinForm32/Form1.cs +++ b/samples/WinForm32/Form1.cs @@ -26,9 +26,19 @@ namespace WinFormSample twain.DefaultSourceChanged += Twain_DefaultSourceChanged; twain.CurrentSourceChanged += Twain_CurrentSourceChanged; + SetDoubleBuffered(capListView); + this.Disposed += Form1_Disposed; } + static void SetDoubleBuffered(Control control) + { + if (SystemInformation.TerminalServerSession) return; + + var dbprop = control.GetType().GetProperty(nameof(DoubleBuffered), BindingFlags.NonPublic | BindingFlags.Instance); + dbprop!.SetValue(control, true); + } + private void Form1_Disposed(object? sender, EventArgs e) { twain.Dispose(); @@ -39,9 +49,7 @@ namespace WinFormSample lblCurrent.Text = ds.ProductName; if (twain.State == STATE.S4) { - twain.GetCapValues(CAP.CAP_SUPPORTEDCAPS, out IList caps); - foreach (var c in caps) - listCaps.Items.Add(c); + LoadCapInfoList(); // never seen a driver support these but here it is var sts = twain.GetCapLabel(CAP.ICAP_SUPPORTEDSIZES, out string? test); @@ -55,10 +63,112 @@ namespace WinFormSample } else { - listCaps.Items.Clear(); + capListView.Items.Clear(); } } + private void LoadCapInfoList() + { + twain.GetCapValues(CAP.CAP_SUPPORTEDCAPS, out IList caps); + twain.GetCapValues(CAP.CAP_EXTENDEDCAPS, out IList extended); + foreach (var c in caps) + { + ListViewItem it = new(c.ToString()); + + if (twain.GetCapCurrent(c, out TW_CAPABILITY twcap).RC == TWRC.SUCCESS) + { + var type = twcap.DetermineValueType(twain); + it.SubItems.Add(type.ToString()); + it.SubItems.Add(ReadTypedValue(c, type, forCurrent: true)); + it.SubItems.Add(ReadTypedValue(c, type, forCurrent: false)); + } + else + { + it.SubItems.Add(""); + it.SubItems.Add(""); + } + it.SubItems.Add(extended.Contains(c).ToString()); + it.SubItems.Add(twain.QueryCapSupport(c).ToString()); + capListView.Items.Add(it); + } + } + + // there may be a better way... + private string ReadTypedValue(CAP cap, TWTY type, bool forCurrent) + { + switch (type) + { + case TWTY.UINT8: + var sts = forCurrent ? + twain.GetCapCurrent(cap, out byte ubval) : + twain.GetCapDefault(cap, out ubval); + return ubval.ToString(); + case TWTY.INT8: + sts = forCurrent ? + twain.GetCapCurrent(cap, out sbyte sbval) : + twain.GetCapDefault(cap, out sbval); + return sbval.ToString(); + case TWTY.UINT16: + sts = forCurrent ? + twain.GetCapCurrent(cap, out ushort usval) : + twain.GetCapDefault(cap, out usval); + return usval.ToString(); + case TWTY.INT16: + sts = forCurrent ? + twain.GetCapCurrent(cap, out short ssval) : + twain.GetCapDefault(cap, out ssval); + return ssval.ToString(); + case TWTY.UINT32: + sts = forCurrent ? + twain.GetCapCurrent(cap, out uint uival) : + twain.GetCapDefault(cap, out uival); + return uival.ToString(); + case TWTY.INT32: + sts = forCurrent ? + twain.GetCapCurrent(cap, out int sival) : + twain.GetCapDefault(cap, out sival); + return sival.ToString(); + case TWTY.BOOL: + sts = forCurrent ? + twain.GetCapCurrent(cap, out usval) : + twain.GetCapDefault(cap, out usval); + return usval.ToString(); + case TWTY.FIX32: + sts = forCurrent ? + twain.GetCapCurrent(cap, out TW_FIX32 fxval) : + twain.GetCapDefault(cap, out fxval); + return fxval.ToString(); + case TWTY.FRAME: + sts = forCurrent ? + twain.GetCapCurrent(cap, out TW_FRAME frval) : + twain.GetCapDefault(cap, out frval); + return frval.ToString(); + case TWTY.STR32: + sts = forCurrent ? + twain.GetCapCurrent(cap, out TW_STR32 s32val) : + twain.GetCapDefault(cap, out s32val); + return s32val.ToString(); + case TWTY.STR64: + sts = forCurrent ? + twain.GetCapCurrent(cap, out TW_STR64 s64val) : + twain.GetCapDefault(cap, out s64val); + return s64val.ToString(); + case TWTY.STR128: + sts = forCurrent ? + twain.GetCapCurrent(cap, out TW_STR128 s128val) : + twain.GetCapDefault(cap, out s128val); + return s128val.ToString(); + case TWTY.STR255: + sts = forCurrent ? + twain.GetCapCurrent(cap, out TW_STR255 s255val) : + twain.GetCapDefault(cap, out s255val); + return s255val.ToString(); + case TWTY.HANDLE: + break; + } + return ""; + } + private void Twain_DefaultSourceChanged(TwainAppSession arg1, TW_IDENTITY_LEGACY ds) { lblDefault.Text = ds.ProductName; diff --git a/src/NTwain/Data/TWAINH.cs b/src/NTwain/Data/TWAINH.cs index 1b04d76..c639b27 100644 --- a/src/NTwain/Data/TWAINH.cs +++ b/src/NTwain/Data/TWAINH.cs @@ -2576,6 +2576,8 @@ namespace NTwain.Data /// public enum TWTY : ushort { + Invalid = 0xffff, + INT8 = 0x0000, INT16 = 0x0001, INT32 = 0x0002, diff --git a/src/NTwain/Data/ValueReader.cs b/src/NTwain/Data/ValueReader.cs index c5a1703..78c3c3e 100644 --- a/src/NTwain/Data/ValueReader.cs +++ b/src/NTwain/Data/ValueReader.cs @@ -10,7 +10,7 @@ namespace NTwain.Data /// /// Contains methods for reading pointers into various things. /// - static class ValueReader + public static class ValueReader { /// /// Reads pointer as UTF8 string. @@ -52,6 +52,39 @@ namespace NTwain.Data // these contain parts from the original TWAIN.CapabilityToCsv() + public static TWTY DetermineValueType(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true) + { + var type = TWTY.Invalid; + + + var lockedPtr = memMgr.Lock(cap.hContainer); + + try + { + if (TwainPlatform.IsMacOSX) + { + type = (TWTY)(ushort)(uint)Marshal.ReadInt32(lockedPtr); + + } + else + { + type = (TWTY)(ushort)Marshal.ReadInt16(lockedPtr); + } + } + finally + { + if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer); + if (freeMemory) + { + memMgr.Free(cap.hContainer); + cap.hContainer = IntPtr.Zero; + } + } + + return type; + } + + /// /// Reads a one value out of a cap. This can only be done once if memory is freed. ///