Another attempt, starting with only the defined types.

This commit is contained in:
Eugene Wang 2023-03-31 21:59:59 -04:00
parent 1610e39d2d
commit 64e631bd2a
23 changed files with 50126 additions and 24040 deletions

View File

@ -11,14 +11,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_common", "_common", "{4CE0
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTwain", "src\NTwain\NTwain.csproj", "{B391C1B7-5647-4B7A-9079-81E835E633DD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Net5Console", "samples\Net5Console\Net5Console.csproj", "{9F6C1B39-D0C9-4466-96A0-AB41C58762A9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{707B4313-8EF8-4D0F-A95E-590783422187}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTwain.Win", "src\NTwain.Win\NTwain.Win.csproj", "{F836149E-E64D-476E-A325-478D18BE1CC7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_twain-doc", "_twain-doc", "{0C94E5AD-E226-4A30-92B4-C28FE5B7FC23}"
ProjectSection(SolutionItems) = preProject
twain-doc\TWAIN-2.5-Features.pdf = twain-doc\TWAIN-2.5-Features.pdf
@ -26,31 +20,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_twain-doc", "_twain-doc",
twain-doc\twain2.5.h = twain-doc\twain2.5.h
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTwain", "src\NTwain\NTwain.csproj", "{3C8A3CF9-A60D-4F21-B866-D291A7AABD4A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B391C1B7-5647-4B7A-9079-81E835E633DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B391C1B7-5647-4B7A-9079-81E835E633DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B391C1B7-5647-4B7A-9079-81E835E633DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B391C1B7-5647-4B7A-9079-81E835E633DD}.Release|Any CPU.Build.0 = Release|Any CPU
{9F6C1B39-D0C9-4466-96A0-AB41C58762A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F6C1B39-D0C9-4466-96A0-AB41C58762A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F6C1B39-D0C9-4466-96A0-AB41C58762A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F6C1B39-D0C9-4466-96A0-AB41C58762A9}.Release|Any CPU.Build.0 = Release|Any CPU
{F836149E-E64D-476E-A325-478D18BE1CC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F836149E-E64D-476E-A325-478D18BE1CC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F836149E-E64D-476E-A325-478D18BE1CC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F836149E-E64D-476E-A325-478D18BE1CC7}.Release|Any CPU.Build.0 = Release|Any CPU
{3C8A3CF9-A60D-4F21-B866-D291A7AABD4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C8A3CF9-A60D-4F21-B866-D291A7AABD4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C8A3CF9-A60D-4F21-B866-D291A7AABD4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C8A3CF9-A60D-4F21-B866-D291A7AABD4A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9F6C1B39-D0C9-4466-96A0-AB41C58762A9} = {707B4313-8EF8-4D0F-A95E-590783422187}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7459323B-44F6-4E07-8574-E1B4B525086B}
EndGlobalSection

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>NTwain</PackageId>
<Description>Library containing the TWAIN API for dotnet.</Description>
<TargetFrameworks>net462;netcoreapp3.1;net5.0;net6.0;net7.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>11</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
<PackageReference Include="System.Security.Permissions" Version="6.0.0" />
</ItemGroup>
<!--<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
</ItemGroup>-->
</Project>

View File

@ -0,0 +1,4 @@
This namespace contains types and utilities from the [twaincs project](https://github.com/twain/twain-cs)
that's been modified with partials.
Version initially used is 2.5.0.0.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -29,22 +29,22 @@ namespace NTwain
object Invoke(Delegate work, params object[] args);
}
/// <summary>
/// Async calls are marshalled to threadpool thread.
/// Should only be used in non-UI apps.
/// </summary>
public class ThreadPoolMarshaller : IThreadMarshaller
{
public bool InvokeRequired => throw new NotImplementedException();
///// <summary>
///// Async calls are marshalled to threadpool thread.
///// Should only be used in non-UI apps.
///// </summary>
//public class ThreadPoolMarshaller : IThreadMarshaller
//{
// public bool InvokeRequired => throw new NotImplementedException();
public void BeginInvoke(Delegate work, params object[] args)
{
Task.Run(() => work.DynamicInvoke(args));
}
// public void BeginInvoke(Delegate work, params object[] args)
// {
// Task.Run(() => work.DynamicInvoke(args));
// }
public object Invoke(Delegate work, params object[] args)
{
return work.DynamicInvoke(args);
}
}
// public object Invoke(Delegate work, params object[] args)
// {
// return work.DynamicInvoke(args);
// }
//}
}

View File

@ -105,7 +105,7 @@ namespace NTwain
private void HandleUIThreadAction(Action action)
{
DebugThreadInfo("begin");
DebugThreadInfo("begin UI thread action");
_threadMarshaller.Invoke(action);
}
@ -118,7 +118,7 @@ namespace NTwain
// Drain the event queue...
while (true)
{
DebugThreadInfo("in loop");
DebugThreadInfo("in device event loop");
// Try to get an event...
twdeviceevent = default;
@ -143,92 +143,92 @@ namespace NTwain
private STS HandleScanEvent(bool closing)
{
DebugThreadInfo("begin");
DebugThreadInfo("scan event begin");
// the scan event needs to return asap since it can come from msg loop
// so fire off the handling work to another thread
_threadMarshaller.BeginInvoke(new Action<bool>(HandleScanEventReal), closing);
//_threadMarshaller.BeginInvoke(new Action<bool>(HandleScanEventReal), closing);
return STS.SUCCESS;
}
void HandleScanEventReal(bool closing)
{
DebugThreadInfo("begin");
//void HandleScanEventReal(bool closing)
//{
// DebugThreadInfo("begin");
if (_twain == null || State <= STATE.S4 || closing) return;
// if (_twain == null || State <= STATE.S4 || closing) return;
if (_twain.IsMsgCloseDsReq() || _twain.IsMsgCloseDsOk())
{
_twain.Rollback(STATE.S4);
return;
}
// if (_twain.IsMsgCloseDsReq() || _twain.IsMsgCloseDsOk())
// {
// _twain.Rollback(STATE.S4);
// return;
// }
// all except mem xfer will run this once and raise event.
// mem xfer will run this multiple times until complete image is assembled
if (_twain.IsMsgXferReady())
{
TW_PENDINGXFERS pending = default;
var sts = _twain.DatPendingxfers(DG.CONTROL, MSG.GET, ref pending);
if (sts != STS.SUCCESS)
{
try
{
TransferError?.Invoke(this, new TransferErrorEventArgs(sts));
}
catch { }
return; // do more?
}
// // all except mem xfer will run this once and raise event.
// // mem xfer will run this multiple times until complete image is assembled
// if (_twain.IsMsgXferReady())
// {
// TW_PENDINGXFERS pending = default;
// var sts = _twain.DatPendingxfers(DG.CONTROL, MSG.GET, ref pending);
// if (sts != STS.SUCCESS)
// {
// try
// {
// TransferError?.Invoke(this, new TransferErrorEventArgs(sts));
// }
// catch { }
// return; // do more?
// }
var xferMech = Capabilities.ICAP_XFERMECH.GetCurrent();
// var xferMech = Capabilities.ICAP_XFERMECH.GetCurrent();
var readyArgs = new TransferReadyEventArgs(_twain, pending.Count, (TWEJ)pending.EOJ);
try
{
TransferReady?.Invoke(this, readyArgs);
}
catch { }
// var readyArgs = new TransferReadyEventArgs(_twain, pending.Count, (TWEJ)pending.EOJ);
// try
// {
// TransferReady?.Invoke(this, readyArgs);
// }
// catch { }
if (readyArgs.CancelCapture == CancelType.Immediate)
{
sts = _twain.DatPendingxfers(DG.CONTROL, MSG.RESET, ref pending);
}
else
{
if (readyArgs.CancelCapture == CancelType.Graceful) StopCapture();
// if (readyArgs.CancelCapture == CancelType.Immediate)
// {
// sts = _twain.DatPendingxfers(DG.CONTROL, MSG.RESET, ref pending);
// }
// else
// {
// if (readyArgs.CancelCapture == CancelType.Graceful) StopCapture();
if (!readyArgs.SkipCurrent)
{
switch (xferMech)
{
case TWSX.NATIVE:
RunImageNativeXfer();
break;
case TWSX.MEMFILE:
RunImageMemFileXfer();
break;
case TWSX.FILE:
RunImageFileXfer();
break;
case TWSX.MEMORY:
RunImageMemoryXfer();
break;
}
}
sts = _twain.DatPendingxfers(DG.CONTROL, MSG.ENDXFER, ref pending);
}
// if (!readyArgs.SkipCurrent)
// {
// switch (xferMech)
// {
// case TWSX.NATIVE:
// RunImageNativeXfer();
// break;
// case TWSX.MEMFILE:
// RunImageMemFileXfer();
// break;
// case TWSX.FILE:
// RunImageFileXfer();
// break;
// case TWSX.MEMORY:
// RunImageMemoryXfer();
// break;
// }
// }
// sts = _twain.DatPendingxfers(DG.CONTROL, MSG.ENDXFER, ref pending);
// }
// TODO: may be wrong for now
if (pending.Count == 0 || sts == STS.CANCEL || sts == STS.XFERDONE)
{
_twain.Rollback(STATE.S4);
}
else
{
HandleScanEvent(State <= STATE.S3);
}
}
// // TODO: may be wrong for now
// if (pending.Count == 0 || sts == STS.CANCEL || sts == STS.XFERDONE)
// {
// _twain.Rollback(STATE.S4);
// }
// else
// {
// HandleScanEvent(State <= STATE.S3);
// }
// }
}
//}
[Conditional("DEBUG")]
private void DebugThreadInfo(string description, [CallerMemberName] string callerName = "")

View File

@ -51,7 +51,7 @@ namespace NTwain
{
TWTY itemType;
// Mac has a level of indirection and a different structure (ick)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var onevalue = MarshalTo<TW_ONEVALUE_MACOSX>(lockedPtr);
@ -88,7 +88,7 @@ namespace NTwain
int count = 0;
// Mac has a level of indirection and a different structure (ick)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var twenumerationmacosx = MarshalTo<TW_ENUMERATION_MACOSX>(lockedPtr);
@ -99,7 +99,7 @@ namespace NTwain
lockedPtr += Marshal.SizeOf(twenumerationmacosx);
}
// Windows or the 2.4+ Linux DSM...
else if ((PlatformInfo.IsWindows) || ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
else if (TWAIN.GetPlatform() == Platform.WINDOWS || ((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
{
// Crack the container...
var twenumeration = MarshalTo<TW_ENUMERATION>(lockedPtr);
@ -153,7 +153,7 @@ namespace NTwain
uint count;
// Mac has a level of indirection and a different structure (ick)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var twarraymacosx = MarshalTo<TW_ARRAY_MACOSX>(lockedPtr);
@ -197,7 +197,7 @@ namespace NTwain
TW_RANGE_FIX32 twrangefix32 = default;
// Mac has a level of indirection and a different structure (ick)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
var twrangemacosx = MarshalTo<TW_RANGE_MACOSX>(lockedPtr);
var twrangefix32macosx = MarshalTo<TW_RANGE_FIX32_MACOSX>(lockedPtr);
@ -215,7 +215,7 @@ namespace NTwain
twrangefix32.CurrentValue = twrangefix32macosx.CurrentValue;
}
// Windows or the 2.4+ Linux DSM...
else if ((PlatformInfo.IsWindows) || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
else if (TWAIN.GetPlatform() == Platform.WINDOWS || (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
{
twrange = MarshalTo<TW_RANGE>(lockedPtr);
@ -295,7 +295,7 @@ namespace NTwain
{
TWTY itemType;
// Mac has a level of indirection and a different structure (ick)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Crack the container...
var onevalue = MarshalTo<TW_ONEVALUE_MACOSX>(lockedPtr);

View File

@ -72,7 +72,7 @@ namespace NTwain
TWTY itemType = GetItemType<TValue>();
// Allocate the container (go for worst case, which is TW_STR255)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ONEVALUE_MACOSX)) + Marshal.SizeOf(default(TW_STR255))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
@ -113,7 +113,7 @@ namespace NTwain
TWTY itemType = GetItemType<TValue>();
// Allocate the container (go for worst case, which is TW_STR255)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ARRAY_MACOSX)) + ((values.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
@ -166,7 +166,7 @@ namespace NTwain
TWTY itemType = GetItemType<TValue>();
// Allocate the container (go for worst case, which is TW_STR255)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_ENUMERATION_MACOSX)) + ((value.Items.Length + 1) * Marshal.SizeOf(default(TW_STR255)))));
@ -184,7 +184,7 @@ namespace NTwain
lockedPtr += Marshal.SizeOf(twenumerationmacosx);
}
// Windows or the 2.4+ Linux DSM...
else if ((PlatformInfo.IsWindows) ||
else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
(twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
{
@ -244,14 +244,14 @@ namespace NTwain
TWTY itemType = GetItemType<TValue>();
// Allocate the container (go for worst case, which is TW_STR255)...
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
// Allocate...
twCap.hContainer = twain.DsmMemAlloc((uint)(Marshal.SizeOf(default(TW_RANGE_MACOSX))));
lockedPtr = twain.DsmMemLock(twCap.hContainer);
}
// Windows or the 2.4+ Linux DSM...
else if ((PlatformInfo.IsWindows) ||
else if (TWAIN.GetPlatform() == Platform.WINDOWS ||
(twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm) ||
((twain.m_blFoundLatestDsm || twain.m_blFoundLatestDsm64) && (twain.m_linuxdsm == TWAIN.LinuxDsm.IsLatestDsm)))
{
@ -289,7 +289,7 @@ namespace NTwain
default:
throw new NotSupportedException($"{itemType} is not supported for range.");
case TWTY.INT8:
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = (uint)Convert.ToSByte(value.MinValue);
@ -321,7 +321,7 @@ namespace NTwain
}
break;
case TWTY.UINT8:
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = Convert.ToByte(value.MinValue);
@ -353,7 +353,7 @@ namespace NTwain
}
break;
case TWTY.INT16:
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = (uint)Convert.ToInt16(value.MinValue);
@ -386,7 +386,7 @@ namespace NTwain
break;
case TWTY.BOOL:
case TWTY.UINT16:
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = Convert.ToUInt16(value.MinValue);
@ -418,7 +418,7 @@ namespace NTwain
}
break;
case TWTY.INT32:
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = (uint)Convert.ToInt32(value.MinValue);
@ -450,7 +450,7 @@ namespace NTwain
}
break;
case TWTY.UINT32:
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
twrangemacosx.ItemType = (uint)itemType;
twrangemacosx.MinValue = Convert.ToUInt32(value.MinValue);
@ -487,7 +487,7 @@ namespace NTwain
double step = Convert.ToDouble(value.StepSize);
double def = Convert.ToDouble(value.DefaultValue);
double current = Convert.ToDouble(value.CurrentValue);
if (PlatformInfo.IsMacOSX)
if (TWAIN.GetPlatform() == Platform.MACOSX)
{
TW_RANGE_FIX32_MACOSX twrangefix32macosx = default;
twrangefix32macosx.ItemType = (uint)itemType;

View File

@ -1,43 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NTwain
{
/// <summary>
/// Contains info on current platform, process, and TWAIN stuff.
/// </summary>
public static class PlatformInfo
{
/// <summary>
/// Whether the current OS is windows.
/// </summary>
public static bool IsWindows { get; }
/// <summary>
/// Whether the current OS is linux.
/// </summary>
public static bool IsLinux { get; }
/// <summary>
/// Whether the current OS is MacOSX.
/// </summary>
public static bool IsMacOSX { get; }
/// <summary>
/// Whether the application is running in 64-bit.
/// </summary>
public static bool IsApp64Bit { get; set; }
static PlatformInfo()
{
var platform = Environment.OSVersion.Platform;
IsWindows = platform == PlatformID.Win32NT;
IsLinux = platform == PlatformID.Unix;
IsMacOSX = platform == PlatformID.MacOSX;
IsApp64Bit = IntPtr.Size == 8;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
This namespace contains types and utilities from the [twaincs project](https://github.com/twain/twain-cs)
that's been modified with partials.
This namespace contains types and utilities that were modified
from the [twaincs project](https://github.com/twain/twain-cs).
Version initially used is 2.5.0.0.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,535 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
namespace TWAINWorkingGroup
{
// this contains my additions under the TWAINWorkingGroup namespace
// that makes some twain types easier to work with.
/// <summary>
/// Contains platform info for twain use.
/// </summary>
public static class TwainPlatform
{
static TwainPlatform()
{
Is64bit = IntPtr.Size == 8;
#if NETFRAMEWORK
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
IsWindows = true;
}
else if (System.IO.Directory.Exists("/Library/Application Support"))
{
IsMacOSX = true;
}
else if (Environment.OSVersion.Platform == PlatformID.Unix)
{
IsLinux = true;
}
#else
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
IsWindows = true;
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
IsMacOSX = true;
}
else
{
IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
}
#endif
}
/// <summary>
/// Whether the code is running under Linux.
/// </summary>
public static bool IsLinux { get; }
/// <summary>
/// Whether the code is running under MacOSX.
/// </summary>
public static bool IsMacOSX { get; }
/// <summary>
/// Whether the code is running under Windows.
/// </summary>
public static bool IsWindows { get; }
/// <summary>
/// Whether the code is running in 64bit or 32bit.
/// </summary>
public static bool Is64bit { get; }
}
/// <summary>
/// Contains value that don't fit into enums nicely.
/// </summary>
public class TwainConst
{
/// <summary>
/// Don't care values...
/// </summary>
public const byte TWON_DONTCARE8 = 0xff;
public const ushort TWON_DONTCARE16 = 0xff;
public const uint TWON_DONTCARE32 = 0xffffffff;
/// <summary>
/// We're departing from a strict translation of H so that
/// we can achieve a unified status return type.
/// </summary>
public const int STSCC = 0x10000; // get us past the custom space
}
/// <summary>
/// TWAIN's boolean values.
/// </summary>
public enum BoolType : ushort
{
/// <summary>
/// The false value (0).
/// </summary>
False = 0,
/// <summary>
/// The true value (1).
/// </summary>
True = 1
}
/// <summary>
/// A more dotnet-friendly representation of <see cref="TW_METRICS"/>.
/// </summary>
public struct Metrics
{
/// <summary>
/// Return code of querying the metrics.
/// </summary>
public STS ReturnCode;
/// <summary>
/// The number of sheets of paper processed by the scanner.
/// </summary>
public int Sheets;
/// <summary>
/// The number of images made available for transfer by the driver. This is not
/// necessarily the same as the number of images actually transferred, since the
/// application may opt to skip transfers or to end without transferring all images.
/// </summary>
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>
/// <typeparam name="TValue"></typeparam>
public class Enumeration<TValue> where TValue : struct
{
public int CurrentIndex;
public int DefaultIndex;
public TValue[] Items;
}
/// <summary>
/// A more dotnet-friendly representation of <see cref="TW_RANGE"/>.
/// </summary>
/// <typeparam name="TValue"></typeparam>
public partial class Range<TValue> : IEnumerable<TValue> where TValue : struct
{
public TValue MinValue;
public TValue MaxValue;
public TValue StepSize;
public TValue DefaultValue;
public TValue CurrentValue;
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
{
if (!(MinValue is IConvertible))
throw new NotSupportedException($"The value type {typeof(TValue).Name} is not supported for range enumeration.");
return new DynamicEnumerator(MinValue, MaxValue, StepSize);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<TValue>)this).GetEnumerator();
}
// dynamic is a cheap hack to sidestep the compiler restrictions if I know TValue is numeric
class DynamicEnumerator : IEnumerator<TValue>
{
private readonly TValue _min;
private readonly TValue _max;
private readonly TValue _step;
private TValue _cur;
bool started = false;
public DynamicEnumerator(TValue min, TValue max, TValue step)
{
_min = min;
_max = max;
_step = step;
_cur = min;
}
public TValue Current => _cur;
object IEnumerator.Current => this.Current;
public void Dispose() { }
public bool MoveNext()
{
if (!started)
{
started = true;
return true;
}
var next = _cur + (dynamic)_step;
if (next == _cur || next < _min || next > _max) return false;
_cur = next;
return true;
}
public void Reset()
{
_cur = _min;
started = false;
}
}
}
partial struct TW_FIX32 : IEquatable<TW_FIX32>, IConvertible
{
// this conversion logic is found in the twain spec.
float ToFloat()
{
return Whole + Frac / 65536f;
}
double ToDouble()
{
return Whole + Frac / 65536.0;
}
public TW_FIX32(double value)
{
Whole = (short)value;
Frac = (ushort)((value - Whole) * 65536.0);
}
public TW_FIX32(float value)
{
//int temp = (int)(value * 65536.0 + 0.5);
//Whole = (short)(temp >> 16);
//Fraction = (ushort)(temp & 0x0000ffff);
// different version from twain faq
bool sign = value < 0;
int temp = (int)(value * 65536.0 + (sign ? (-0.5) : 0.5));
Whole = (short)(temp >> 16);
Frac = (ushort)(temp & 0x0000ffff);
}
public override string ToString()
{
return ToFloat().ToString();
}
public bool Equals(TW_FIX32 other)
{
return Whole == other.Whole && Frac == other.Frac;
}
public override bool Equals(object obj)
{
if (obj is TW_FIX32 other)
{
return Equals(other);
}
return false;
}
public override int GetHashCode()
{
return Whole ^ Frac;
}
#region IConvertable
TypeCode IConvertible.GetTypeCode()
{
return TypeCode.Single;
}
bool IConvertible.ToBoolean(IFormatProvider provider)
{
return this != 0;
}
byte IConvertible.ToByte(IFormatProvider provider)
{
return Convert.ToByte((float)this);
}
char IConvertible.ToChar(IFormatProvider provider)
{
return Convert.ToChar((float)this);
}
DateTime IConvertible.ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime((float)this);
}
decimal IConvertible.ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal((float)this);
}
double IConvertible.ToDouble(IFormatProvider provider)
{
return Convert.ToDouble((float)this);
}
short IConvertible.ToInt16(IFormatProvider provider)
{
return Convert.ToInt16((float)this);
}
int IConvertible.ToInt32(IFormatProvider provider)
{
return Convert.ToInt32((float)this);
}
long IConvertible.ToInt64(IFormatProvider provider)
{
return Convert.ToInt64((float)this);
}
sbyte IConvertible.ToSByte(IFormatProvider provider)
{
return Convert.ToSByte((float)this);
}
float IConvertible.ToSingle(IFormatProvider provider)
{
return Convert.ToSingle((float)this);
}
string IConvertible.ToString(IFormatProvider provider)
{
return this.ToString();
}
object IConvertible.ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType((float)this, conversionType, CultureInfo.InvariantCulture);
}
ushort IConvertible.ToUInt16(IFormatProvider provider)
{
return Convert.ToUInt16((float)this);
}
uint IConvertible.ToUInt32(IFormatProvider provider)
{
return Convert.ToUInt32((float)this);
}
ulong IConvertible.ToUInt64(IFormatProvider provider)
{
return Convert.ToUInt64((float)this);
}
#endregion
public static implicit operator float(TW_FIX32 value) => value.ToFloat();
public static implicit operator TW_FIX32(float value) => new TW_FIX32(value);
public static implicit operator double(TW_FIX32 value) => value.ToDouble();
public static implicit operator TW_FIX32(double value) => new TW_FIX32((float)value);
public static bool operator ==(TW_FIX32 value1, TW_FIX32 value2) => value1.Equals(value2);
public static bool operator !=(TW_FIX32 value1, TW_FIX32 value2) => !value1.Equals(value2);
}
partial struct TW_FRAME : IEquatable<TW_FRAME>
{
/// <summary>
/// Creates <see cref="TW_FRAME"/> from a string representation of it.
/// </summary>
/// <param name="value"></param>
public TW_FRAME(string value) : this()
{
var parts = value.Split(',');
if (parts.Length == 4)
{
Left = float.Parse(parts[0]);
Top = float.Parse(parts[1]);
Right = float.Parse(parts[2]);
Bottom = float.Parse(parts[3]);
}
else
{
throw new ArgumentException($"Cannot create frame from \"{value}\".");
}
}
/// <summary>
/// String representation of Left,Top,Right,Bottom.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"{Left},{Top},{Right},{Bottom}";
}
public bool Equals(TW_FRAME other)
{
return Left == other.Left && Top == other.Top &&
Right == other.Right && Bottom == other.Bottom;
}
public override bool Equals(object obj)
{
if (obj is TW_FRAME other)
{
return Equals(other);
}
return false;
}
public override int GetHashCode()
{
return Left.GetHashCode() ^ Top.GetHashCode() ^
Right.GetHashCode() ^ Bottom.GetHashCode();
}
public static bool operator ==(TW_FRAME value1, TW_FRAME value2)
{
return value1.Equals(value2);
}
public static bool operator !=(TW_FRAME value1, TW_FRAME value2)
{
return !value1.Equals(value2);
}
}
partial struct TW_STR32
{
public const int Size = 34;
public TW_STR32(string value) : this()
{
Set(value);
}
public override string ToString()
{
return Get();
}
public static implicit operator string(TW_STR32 value) => value.ToString();
public static explicit operator TW_STR32(string value) => new TW_STR32(value);
}
partial struct TW_STR64
{
public const int Size = 66;
public TW_STR64(string value) : this()
{
Set(value);
}
public override string ToString()
{
return Get();
}
public static implicit operator string(TW_STR64 value) => value.ToString();
public static explicit operator TW_STR64(string value) => new TW_STR64(value);
}
partial struct TW_STR128
{
public const int Size = 130;
public TW_STR128(string value) : this()
{
Set(value);
}
public override string ToString()
{
return Get();
}
public static implicit operator string(TW_STR128 value) => value.ToString();
public static explicit operator TW_STR128(string value) => new TW_STR128(value);
}
partial struct TW_STR255
{
public const int Size = 256;
public TW_STR255(string value) : this()
{
Set(value);
}
public override string ToString()
{
return Get();
}
public static implicit operator string(TW_STR255 value) => value.ToString();
public static explicit operator TW_STR255(string value) => new TW_STR255(value);
}
partial struct TW_IDENTITY
{
public override string ToString()
{
return $"{Manufacturer} - {ProductFamily} - {ProductName} {Version} (TWAIN {ProtocolMajor}.{ProtocolMinor})";
}
}
partial struct TW_VERSION
{
public override string ToString()
{
return $"{MajorNum}.{MinorNum}";
}
}
//partial struct TW_DEVICEEVENT
//{
// public TWDE Event { get { return (TWDE)_event; } }
// public TWFL FlashUsed2 { get { return (TWFL)_flashUsed2; } }
//}
}