mirror of
https://github.com/soukoku/ntwain.git
synced 2026-02-25 13:04:07 +08:00
Resurrected metrics and twaindirect task calls.
This commit is contained in:
@@ -168,6 +168,13 @@ namespace NTwain.DSM
|
||||
DG dg, DAT dat, MSG msg, ref TW_SETUPFILEXFER filexfer
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
ref <#= file.identityClass #> origin, ref <#= file.identityClass #> dest,
|
||||
DG dg, DAT dat, MSG msg, ref TW_METRICS metrics
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
|
||||
@@ -148,6 +148,13 @@ namespace NTwain.DSM
|
||||
DG dg, DAT dat, MSG msg, ref TW_SETUPFILEXFER filexfer
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
ref TW_IDENTITY_LEGACY origin, ref TW_IDENTITY_LEGACY dest,
|
||||
DG dg, DAT dat, MSG msg, ref TW_METRICS metrics
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
|
||||
@@ -148,6 +148,13 @@ namespace NTwain.DSM
|
||||
DG dg, DAT dat, MSG msg, ref TW_SETUPFILEXFER filexfer
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
ref TW_IDENTITY origin, ref TW_IDENTITY dest,
|
||||
DG dg, DAT dat, MSG msg, ref TW_METRICS metrics
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
|
||||
@@ -148,6 +148,13 @@ namespace NTwain.DSM
|
||||
DG dg, DAT dat, MSG msg, ref TW_SETUPFILEXFER filexfer
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
ref TW_IDENTITY_LEGACY origin, ref TW_IDENTITY_LEGACY dest,
|
||||
DG dg, DAT dat, MSG msg, ref TW_METRICS metrics
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
|
||||
@@ -148,6 +148,13 @@ namespace NTwain.DSM
|
||||
DG dg, DAT dat, MSG msg, ref TW_SETUPFILEXFER filexfer
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
ref TW_IDENTITY_MACOSX origin, ref TW_IDENTITY_MACOSX dest,
|
||||
DG dg, DAT dat, MSG msg, ref TW_METRICS metrics
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
|
||||
@@ -148,6 +148,13 @@ namespace NTwain.DSM
|
||||
DG dg, DAT dat, MSG msg, ref TW_SETUPFILEXFER filexfer
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
ref TW_IDENTITY_MACOSX origin, ref TW_IDENTITY_MACOSX dest,
|
||||
DG dg, DAT dat, MSG msg, ref TW_METRICS metrics
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
|
||||
@@ -148,6 +148,13 @@ namespace NTwain.DSM
|
||||
DG dg, DAT dat, MSG msg, ref TW_SETUPFILEXFER filexfer
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
ref TW_IDENTITY_LEGACY origin, ref TW_IDENTITY_LEGACY dest,
|
||||
DG dg, DAT dat, MSG msg, ref TW_METRICS metrics
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
|
||||
@@ -148,6 +148,13 @@ namespace NTwain.DSM
|
||||
DG dg, DAT dat, MSG msg, ref TW_SETUPFILEXFER filexfer
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
ref TW_IDENTITY_LEGACY origin, ref TW_IDENTITY_LEGACY dest,
|
||||
DG dg, DAT dat, MSG msg, ref TW_METRICS metrics
|
||||
);
|
||||
|
||||
[DllImport(DsmName, CharSet = CharSet.Ansi)]
|
||||
public static extern TWRC DSM_Entry
|
||||
(
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace NTwain.Data
|
||||
/// Don't care values...
|
||||
/// </summary>
|
||||
public const byte TWON_DONTCARE8 = 0xff;
|
||||
public const ushort TWON_DONTCARE16 = 0xff;
|
||||
public const ushort TWON_DONTCARE16 = 0xffff;
|
||||
public const uint TWON_DONTCARE32 = 0xffffffff;
|
||||
/// <summary>
|
||||
/// We're departing from a strict translation of H so that
|
||||
@@ -144,10 +144,15 @@ namespace NTwain.Data
|
||||
/// </summary>
|
||||
public TWRC ReturnCode;
|
||||
|
||||
/// <summary>
|
||||
/// Status if code is failure.
|
||||
/// </summary>
|
||||
public TW_STATUS Status;
|
||||
|
||||
/// <summary>
|
||||
/// The response of the task in JSON if successful.
|
||||
/// </summary>
|
||||
public string ResponseJson;
|
||||
public string? ResponseJson;
|
||||
}
|
||||
|
||||
public enum TWRC : ushort
|
||||
@@ -173,6 +178,7 @@ namespace NTwain.Data
|
||||
{
|
||||
// Condition codes (always associated with TWRC_FAILURE)...
|
||||
CUSTOMBASE = 0x8000,
|
||||
None = 0,
|
||||
BUMMER = 1,
|
||||
LOWMEMORY = 2,
|
||||
NODS = 3,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -17,24 +18,22 @@ namespace NTwain.Data
|
||||
/// <param name="data">Pointer to string.</param>
|
||||
/// <param name="length">Number of bytes to read.</param>
|
||||
/// <returns></returns>
|
||||
public static string? PtrToStringUTF8(IMemoryManager memMgr, IntPtr data, int length)
|
||||
public static unsafe string? PtrToStringUTF8(IMemoryManager memMgr, IntPtr data, int length)
|
||||
{
|
||||
string? val = null;
|
||||
var locked = memMgr.Lock(data);
|
||||
if (locked != IntPtr.Zero)
|
||||
{
|
||||
// does this work? who knows.
|
||||
try
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
// safe method but with 2 copies (arr and parsed string)
|
||||
var bytes = new byte[length];
|
||||
Marshal.Copy(locked, bytes, 0, bytes.Length);
|
||||
val = Encoding.UTF8.GetString(bytes);
|
||||
//var bytes = new byte[length];
|
||||
//Marshal.Copy(locked, bytes, 0, bytes.Length);
|
||||
//val = Encoding.UTF8.GetString(bytes);
|
||||
|
||||
//// unsafe method with 1 copy (does it work?)
|
||||
//sbyte* bytes = (sbyte*)locked;
|
||||
//val = new string(bytes, 0, length, Encoding.UTF8);
|
||||
// does this work?
|
||||
val = Encoding.UTF8.GetString((byte*)locked, length);
|
||||
#else
|
||||
val = Marshal.PtrToStringUTF8(locked, length);
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -9,46 +10,29 @@ namespace NTwain.Data
|
||||
/// </summary>
|
||||
static class ValueWriter
|
||||
{
|
||||
///// <summary>
|
||||
///// Allocates and copies the string value into a pointer in UTF8 that's null-terminated.
|
||||
///// </summary>
|
||||
///// <param name="twain"></param>
|
||||
///// <param name="value"></param>
|
||||
///// <param name="length">Actual number of bytes used to encode the string without the null.</param>
|
||||
///// <returns></returns>
|
||||
//public static unsafe IntPtr StringToPtrUTF8(IMemoryManager memMgr, string value, out int length)
|
||||
//{
|
||||
// if (value == null)
|
||||
// {
|
||||
// length = 0;
|
||||
// return IntPtr.Zero;
|
||||
// }
|
||||
/// <summary>
|
||||
/// Allocates and copies the string value into a pointer in UTF8 that's null-terminated.
|
||||
/// </summary>
|
||||
/// <param name="memMgr"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="finalLength">Final length to use with the pointer (includes the null).</param>
|
||||
/// <returns></returns>
|
||||
public static unsafe IntPtr StringToPtrUTF8(IMemoryManager memMgr, string? value, out uint finalLength)
|
||||
{
|
||||
finalLength = 0;
|
||||
if (value == null) return IntPtr.Zero;
|
||||
|
||||
// var utf8 = Encoding.UTF8;
|
||||
// length = utf8.GetByteCount(value);
|
||||
|
||||
// var ptr = memMgr.Alloc((uint)length + 1); // +1 for null-terminated
|
||||
|
||||
// // TODO: test if this works
|
||||
// int written;
|
||||
// byte* bytes = (byte*)ptr;
|
||||
// try
|
||||
// {
|
||||
// // fixed for managed pointer
|
||||
// fixed (char* firstChar = value)
|
||||
// {
|
||||
// written = Encoding.UTF8.GetBytes(firstChar, value.Length, bytes, length);
|
||||
// }
|
||||
|
||||
// bytes[written] = 0;
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// if (ptr != IntPtr.Zero) memMgr.Free(ptr);
|
||||
// }
|
||||
|
||||
// return ptr;
|
||||
//}
|
||||
fixed (char* pInput = value)
|
||||
{
|
||||
var len = Encoding.UTF8.GetByteCount(pInput, value.Length);
|
||||
finalLength = (uint)len + 1;
|
||||
var pResult = (byte*)memMgr.Alloc(finalLength);
|
||||
var bytesWritten = Encoding.UTF8.GetBytes(pInput, value.Length, pResult, len);
|
||||
Trace.Assert(len == bytesWritten);
|
||||
pResult[len] = 0;
|
||||
return (IntPtr)pResult;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Description>Library containing the TWAIN API for dotnet.</Description>
|
||||
<TargetFrameworks>net6.0;net6.0-windows;net462;</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<!--<AllowUnsafeBlocks>true</AllowUnsafeBlocks>-->
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' OR '$(TargetFramework)' == 'net6.0-windows'">
|
||||
|
||||
45
src/NTwain/Triplets/ControlDATs/Metrics.cs
Normal file
45
src/NTwain/Triplets/ControlDATs/Metrics.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using NTwain.Data;
|
||||
using NTwain.DSM;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NTwain.Triplets.ControlDATs
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains calls used with <see cref="DG.CONTROL"/> and <see cref="DAT.METRICS"/>.
|
||||
/// </summary>
|
||||
public class Metrics
|
||||
{
|
||||
public TWRC Get(ref TW_IDENTITY_LEGACY app, ref TW_IDENTITY_LEGACY ds, out TW_METRICS data)
|
||||
{
|
||||
data = default;
|
||||
data.SizeOf = (uint)Marshal.SizeOf<TW_METRICS>();
|
||||
|
||||
var rc = TWRC.FAILURE;
|
||||
if (TwainPlatform.IsWindows)
|
||||
{
|
||||
if (TwainPlatform.Is32bit && TwainPlatform.PreferLegacyDSM)
|
||||
{
|
||||
rc = WinLegacyDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.METRICS, MSG.GET, ref data);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = WinNewDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.METRICS, MSG.GET, ref data);
|
||||
}
|
||||
}
|
||||
else if (TwainPlatform.IsMacOSX)
|
||||
{
|
||||
TW_IDENTITY_MACOSX app2 = app;
|
||||
TW_IDENTITY_MACOSX ds2 = ds;
|
||||
if (TwainPlatform.PreferLegacyDSM)
|
||||
{
|
||||
rc = OSXLegacyDSM.DSM_Entry(ref app2, ref ds2, DG.CONTROL, DAT.METRICS, MSG.GET, ref data);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = OSXNewDSM.DSM_Entry(ref app2, ref ds2, DG.CONTROL, DAT.METRICS, MSG.GET, ref data);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ namespace NTwain.Triplets
|
||||
|
||||
public static readonly Identity Identity = new();
|
||||
|
||||
public static readonly Metrics Metrics = new();
|
||||
|
||||
public static readonly Parent Parent = new();
|
||||
|
||||
public static readonly Passthru Passthru = new();
|
||||
|
||||
@@ -72,8 +72,8 @@ namespace NTwain
|
||||
{
|
||||
get
|
||||
{
|
||||
var sts = DGControl.CustomDsData.Get(ref _appIdentity, ref _currentDS, out TW_CUSTOMDSDATA data);
|
||||
if (sts == TWRC.SUCCESS)
|
||||
var rc = DGControl.CustomDsData.Get(ref _appIdentity, ref _currentDS, out TW_CUSTOMDSDATA data);
|
||||
if (rc == TWRC.SUCCESS)
|
||||
{
|
||||
if (data.hData != IntPtr.Zero && data.InfoLength > 0)
|
||||
{
|
||||
@@ -105,7 +105,7 @@ namespace NTwain
|
||||
var lockedPtr = Lock(data.hData);
|
||||
Marshal.Copy(value, 0, lockedPtr, value.Length);
|
||||
Unlock(data.hData);
|
||||
var sts = DGControl.CustomDsData.Set(ref _appIdentity, ref _currentDS, ref data);
|
||||
var rc = DGControl.CustomDsData.Set(ref _appIdentity, ref _currentDS, ref data);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using NTwain.Data;
|
||||
using NTwain.Triplets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NTwain
|
||||
{
|
||||
@@ -132,5 +134,49 @@ namespace NTwain
|
||||
}
|
||||
return WrapInSTS(rc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads information relating to the last capture run.
|
||||
/// Only valid on state 4 after a capture.
|
||||
/// </summary>
|
||||
public STS GetMetrics(out TW_METRICS metrics)
|
||||
{
|
||||
return WrapInSTS(DGControl.Metrics.Get(ref _appIdentity, ref _currentDS, out metrics));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a TWAIN Direct task from the application to the driver.
|
||||
/// </summary>
|
||||
/// <param name="taskJson">The TWAIN Direct task in JSON.</param>
|
||||
/// <param name="communicationManager">The current system being used to connect the application to the scanner.</param>
|
||||
/// <returns></returns>
|
||||
public TwainDirectTaskResult SetTwainDirectTask(string taskJson, ushort communicationManager = 0)
|
||||
{
|
||||
var result = new TwainDirectTaskResult { ReturnCode = TWRC.FAILURE };
|
||||
TW_TWAINDIRECT task = default;
|
||||
try
|
||||
{
|
||||
task.SizeOf = (uint)Marshal.SizeOf(typeof(TW_TWAINDIRECT));
|
||||
task.CommunicationManager = communicationManager;
|
||||
task.Send = ValueWriter.StringToPtrUTF8(this, taskJson, out uint length);
|
||||
task.SendSize = length;
|
||||
|
||||
result.ReturnCode = DGControl.TwainDirect.SetTask(ref _appIdentity, ref _currentDS, ref task);
|
||||
if (result.ReturnCode == TWRC.FAILURE)
|
||||
{
|
||||
result.Status = GetLastStatus();
|
||||
}
|
||||
else if (result.ReturnCode == TWRC.SUCCESS && task.ReceiveSize > 0 && task.Receive != IntPtr.Zero)
|
||||
{
|
||||
result.ResponseJson = ValueReader.PtrToStringUTF8(this, task.Receive, (int)task.ReceiveSize);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
//if (task.Send != IntPtr.Zero) Free(task.Send); // does source free the Send?
|
||||
if (task.Receive != IntPtr.Zero) Free(task.Receive);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user