Added SetTwainDirectTask method to session.

This commit is contained in:
Eugene Wang 2021-04-27 07:37:52 -04:00
parent d9e56794e5
commit 714caf4935
5 changed files with 117 additions and 17 deletions

View File

@ -4,6 +4,7 @@
<PackageId>NTwain</PackageId>
<Description>Library containing the TWAIN API for dotnet.</Description>
<TargetFrameworks>net45;netstandard2.0;</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>

View File

@ -49,6 +49,19 @@ namespace TWAINWorkingGroup
public int Images;
}
public struct TwainDirectTaskResult
{
/// <summary>
/// Return code of task.
/// </summary>
public STS ReturnCode;
/// <summary>
/// The response of the task in JSON if successful.
/// </summary>
public string ResponseJson;
}
/// <summary>
/// A more dotnet-friendly representation of <see cref="TW_ENUMERATION"/>.
/// </summary>

View File

@ -131,16 +131,16 @@ namespace NTwain
get { return _twain.GetState(); }
}
/// <summary>
/// Gets the manager status. Useful after getting a non-success return code.
/// </summary>
/// <returns></returns>
public TW_STATUS GetStatus()
{
TW_STATUS stat = default;
_ = _twain.DatStatus(DG.CONTROL, MSG.GET, ref stat);
return stat;
}
///// <summary>
///// Gets the manager status. Useful after getting a non-success return code.
///// </summary>
///// <returns></returns>
//public TW_STATUS GetStatus()
//{
// TW_STATUS stat = default;
// _ = _twain.DatStatus(DG.CONTROL, MSG.GET, ref stat);
// return stat;
//}
/// <summary>
/// Opens the TWAIN data source manager.
@ -352,12 +352,36 @@ namespace NTwain
return new Metrics { ReturnCode = sts };
}
//public sts SetTwainDirectTask()
//{
// TW_TWAINDIRECT task = default;
// var sts = _twain.DatTwaindirect(DG.CONTROL, MSG.SETTASK, ref task);
// return sts;
//}
/// <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 = STS.FAILURE };
TW_TWAINDIRECT task = default;
try
{
task.SizeOf = (uint)Marshal.SizeOf(typeof(TW_TWAINDIRECT));
task.CommunicationManager = communicationManager;
task.Send = ValueWriter.StringToPtrUTF8(_twain, taskJson, out int length);
task.SendSize = (uint)length;
result.ReturnCode = _twain.DatTwaindirect(DG.CONTROL, MSG.SETTASK, ref task);
if (result.ReturnCode == STS.SUCCESS && task.ReceiveSize > 0 && task.Receive != IntPtr.Zero)
{
result.ResponseJson = ValueReader.PtrToStringUTF8(task.Receive, (int)task.ReceiveSize);
}
}
finally
{
if (task.Send != IntPtr.Zero) _twain.DsmMemFree(ref task.Send); // just in case
if (task.Receive != IntPtr.Zero) _twain.DsmMemFree(ref task.Receive);
}
return result;
}
#endregion
}

View File

@ -14,6 +14,30 @@ namespace NTwain
/// </summary>
public static class ValueReader
{
/// <summary>
/// Reads pointer as UTF8 string.
/// </summary>
/// <param name="intPtr">Pointer to string.</param>
/// <param name="length">Number of bytes to read.</param>
/// <returns></returns>
public static unsafe string PtrToStringUTF8(IntPtr intPtr, int length)
{
if (intPtr == IntPtr.Zero) throw new ArgumentNullException(nameof(intPtr));
if (length == 0) throw new ArgumentOutOfRangeException(nameof(length), length, "Length must be greater than 0.");
//// safe method with 2 copies
//var bytes = new byte[length];
//Marshal.Copy(intPtr, bytes, 0, length);
//return Encoding.UTF8.GetString(bytes);
// unsafe method with 1 copy (does it work?)
sbyte* bytes = (sbyte*)intPtr;
var str = new string(bytes, 0, length, Encoding.UTF8);
return str;
}
// most of these are modified from the original TWAIN.CapabilityToCsv()
public static TValue ReadOneValueContainer<TValue>(TWAIN twain, ref TW_CAPABILITY cap, bool freeMemory = true) where TValue : struct

View File

@ -13,6 +13,45 @@ namespace NTwain
/// </summary>
public 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>
internal static unsafe IntPtr StringToPtrUTF8(TWAIN twain, string value, out int length)
{
var utf8 = Encoding.UTF8;
length = utf8.GetByteCount(value);
var ptr = twain.DsmMemAlloc((uint)length + 1); // +1 for null-terminated
// TODO: test if this works
int written;
byte* bytes = (byte*)ptr;
try
{
fixed (char* firstChar = value)
{
written = Encoding.UTF8.GetBytes(firstChar, value.Length, bytes, length);
}
bytes[written] = 0;
}
catch
{
// just in case
if (ptr != IntPtr.Zero) twain.DsmMemFree(ref ptr);
throw;
}
return ptr;
}
// most of these are modified from the original TWAIN.CsvToCapability()
public static void WriteOneValueContainer<TValue>(TWAIN twain, ref TW_CAPABILITY twCap, TValue value) where TValue : struct
@ -470,7 +509,6 @@ namespace NTwain
}
}
static TWTY GetItemType<TValue>() where TValue : struct
{
var type = typeof(TValue);