Refactoring xfer logic from twainsession out.

This commit is contained in:
soukoku 2014-04-20 18:42:51 -04:00
parent 1743b8379b
commit 4b08d3bc29
55 changed files with 717 additions and 688 deletions

View File

@ -79,8 +79,8 @@
<Compile Include="..\NTwain\Internals\ICommittable.cs"> <Compile Include="..\NTwain\Internals\ICommittable.cs">
<Link>Internals\ICommittable.cs</Link> <Link>Internals\ICommittable.cs</Link>
</Compile> </Compile>
<Compile Include="..\NTwain\Internals\ITwainStateInternal.cs"> <Compile Include="..\NTwain\Internals\ITwainSessionInternal.cs">
<Link>Internals\ITwainStateInternal.cs</Link> <Link>Internals\ITwainSessionInternal.cs</Link>
</Compile> </Compile>
<Compile Include="..\NTwain\Internals\MessageLoop.cs"> <Compile Include="..\NTwain\Internals\MessageLoop.cs">
<Link>Internals\MessageLoop.cs</Link> <Link>Internals\MessageLoop.cs</Link>
@ -91,6 +91,9 @@
<Compile Include="..\NTwain\Internals\TentativeStateCommitable.cs"> <Compile Include="..\NTwain\Internals\TentativeStateCommitable.cs">
<Link>Internals\TentativeStateCommitable.cs</Link> <Link>Internals\TentativeStateCommitable.cs</Link>
</Compile> </Compile>
<Compile Include="..\NTwain\Internals\TransferLogic.cs">
<Link>Internals\TransferLogic.cs</Link>
</Compile>
<Compile Include="..\NTwain\Internals\WindowsHook.cs"> <Compile Include="..\NTwain\Internals\WindowsHook.cs">
<Link>Internals\WindowsHook.cs</Link> <Link>Internals\WindowsHook.cs</Link>
</Compile> </Compile>
@ -103,6 +106,9 @@
<Compile Include="..\NTwain\ITwainOperation.cs"> <Compile Include="..\NTwain\ITwainOperation.cs">
<Link>ITwainOperation.cs</Link> <Link>ITwainOperation.cs</Link>
</Compile> </Compile>
<Compile Include="..\NTwain\ITwainSession.cs">
<Link>ITwainSession.cs</Link>
</Compile>
<Compile Include="..\NTwain\ITwainState.cs"> <Compile Include="..\NTwain\ITwainState.cs">
<Link>ITwainState.cs</Link> <Link>ITwainState.cs</Link>
</Compile> </Compile>

View File

@ -1,6 +1,7 @@
using NTwain.Properties; using NTwain.Properties;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace NTwain.Data namespace NTwain.Data
@ -55,7 +56,7 @@ namespace NTwain.Data
ContainerType = capability.ContainerType, ContainerType = capability.ContainerType,
}.ReadRangeValue(baseAddr); }.ReadRangeValue(baseAddr);
default: default:
throw new ArgumentException(string.Format(Resources.CapHasBadContainer, capability.ContainerType), "capability"); throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.CapHasBadContainer, capability.ContainerType), "capability");
} }
} }
finally finally

View File

@ -234,7 +234,7 @@ namespace NTwain.Data
object IConvertible.ToType(Type conversionType, IFormatProvider provider) object IConvertible.ToType(Type conversionType, IFormatProvider provider)
{ {
return Convert.ChangeType((float)this, conversionType); return Convert.ChangeType((float)this, conversionType, CultureInfo.InvariantCulture);
} }
ushort IConvertible.ToUInt16(IFormatProvider provider) ushort IConvertible.ToUInt16(IFormatProvider provider)
@ -632,7 +632,6 @@ namespace NTwain.Data
/// </summary> /// </summary>
/// <param name="capability">The capability.</param> /// <param name="capability">The capability.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
public TWCapability(CapabilityId capability, TWOneValue value) public TWCapability(CapabilityId capability, TWOneValue value)
{ {
Capability = capability; Capability = capability;
@ -644,7 +643,6 @@ namespace NTwain.Data
/// </summary> /// </summary>
/// <param name="capability">The capability.</param> /// <param name="capability">The capability.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
public TWCapability(CapabilityId capability, TWEnumeration value) public TWCapability(CapabilityId capability, TWEnumeration value)
{ {
Capability = capability; Capability = capability;
@ -656,7 +654,6 @@ namespace NTwain.Data
/// </summary> /// </summary>
/// <param name="capability">The capability.</param> /// <param name="capability">The capability.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
public TWCapability(CapabilityId capability, TWRange value) public TWCapability(CapabilityId capability, TWRange value)
{ {
Capability = capability; Capability = capability;
@ -684,14 +681,13 @@ namespace NTwain.Data
#region value functions #region value functions
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
void SetOneValue(TWOneValue value) void SetOneValue(TWOneValue value)
{ {
if (value == null) { throw new ArgumentNullException("value"); } if (value == null) { throw new ArgumentNullException("value"); }
ContainerType = ContainerType.OneValue; ContainerType = ContainerType.OneValue;
// since one value can only house UInt32 we will not allow type size > 4 // since one value can only house UInt32 we will not allow type size > 4
if (TypeReader.GetItemTypeSize(value.ItemType) > 4) { throw new ArgumentException(string.Format(Resources.BadValueType, "TWOneValue")); } if (TypeReader.GetItemTypeSize(value.ItemType) > 4) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.BadValueType, "TWOneValue")); }
_hContainer = Platform.MemoryManager.Allocate((uint)Marshal.SizeOf(value)); _hContainer = Platform.MemoryManager.Allocate((uint)Marshal.SizeOf(value));
if (_hContainer != IntPtr.Zero) if (_hContainer != IntPtr.Zero)
@ -700,7 +696,6 @@ namespace NTwain.Data
} }
} }
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
void SetEnumValue(TWEnumeration value) void SetEnumValue(TWEnumeration value)
{ {
if (value == null) { throw new ArgumentNullException("value"); } if (value == null) { throw new ArgumentNullException("value"); }
@ -726,14 +721,13 @@ namespace NTwain.Data
} }
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
void SetRangeValue(TWRange value) void SetRangeValue(TWRange value)
{ {
if (value == null) { throw new ArgumentNullException("value"); } if (value == null) { throw new ArgumentNullException("value"); }
ContainerType = ContainerType.Range; ContainerType = ContainerType.Range;
// since range value can only house UInt32 we will not allow type size > 4 // since range value can only house UInt32 we will not allow type size > 4
if (TypeReader.GetItemTypeSize(value.ItemType) > 4) { throw new ArgumentException(string.Format(Resources.BadValueType, "TWRange")); } if (TypeReader.GetItemTypeSize(value.ItemType) > 4) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.BadValueType, "TWRange")); }
_hContainer = Platform.MemoryManager.Allocate((uint)Marshal.SizeOf(value)); _hContainer = Platform.MemoryManager.Allocate((uint)Marshal.SizeOf(value));
if (_hContainer != IntPtr.Zero) if (_hContainer != IntPtr.Zero)
@ -752,23 +746,22 @@ namespace NTwain.Data
/// <param name="offset"></param> /// <param name="offset"></param>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="value"></param> /// <param name="value"></param>
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
void WriteValue(IntPtr baseAddr, ref int offset, ItemType type, object value) void WriteValue(IntPtr baseAddr, ref int offset, ItemType type, object value)
{ {
switch (type) switch (type)
{ {
case ItemType.Int8: case ItemType.Int8:
case ItemType.UInt8: case ItemType.UInt8:
Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value));// (byte)value); Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value, CultureInfo.InvariantCulture));// (byte)value);
break; break;
case ItemType.Bool: case ItemType.Bool:
case ItemType.Int16: case ItemType.Int16:
case ItemType.UInt16: case ItemType.UInt16:
Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value));//(short)value); Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value, CultureInfo.InvariantCulture));//(short)value);
break; break;
case ItemType.UInt32: case ItemType.UInt32:
case ItemType.Int32: case ItemType.Int32:
Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value));//(int)value); Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value, CultureInfo.InvariantCulture));//(int)value);
break; break;
case ItemType.Fix32: case ItemType.Fix32:
TWFix32 f32 = (TWFix32)value; TWFix32 f32 = (TWFix32)value;
@ -2188,15 +2181,24 @@ namespace NTwain.Data
/// </summary> /// </summary>
public partial class TWStatus public partial class TWStatus
{ {
public TWStatus()
{
}
internal TWStatus(ushort code, ushort data)
{
_conditionCode = code;
_data = data;
}
/// <summary> /// <summary>
/// Condition Code describing the status. /// Condition Code describing the status.
/// </summary> /// </summary>
public ConditionCode ConditionCode { get { return (ConditionCode)_conditionCode; } internal set { _conditionCode = (ushort)value; } } public ConditionCode ConditionCode { get { return (ConditionCode)_conditionCode; } }
/// <summary> /// <summary>
/// Valid for TWAIN 2.1 and later. This field contains additional /// Valid for TWAIN 2.1 and later. This field contains additional
/// scanner-specific data. If there is no data, then this value must be zero. /// scanner-specific data. If there is no data, then this value must be zero.
/// </summary> /// </summary>
public ushort Data { get { return _data; } internal set { _data = Data; } } public ushort Data { get { return _data; } }
} }
/// <summary> /// <summary>
@ -2210,7 +2212,7 @@ namespace NTwain.Data
/// </summary> /// </summary>
public TWStatus Status public TWStatus Status
{ {
get { return new TWStatus { ConditionCode = (ConditionCode)_conditionCode, Data = _data }; } get { return new TWStatus(_conditionCode, _data); }
} }
/// <summary> /// <summary>

View File

@ -1467,7 +1467,7 @@ namespace NTwain.Data
/// <summary> /// <summary>
/// Corresponds to DG_*. /// Corresponds to DG_*.
/// </summary> /// </summary>
[Flags] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags"), Flags]
public enum DataGroups : uint public enum DataGroups : uint
{ {
None = 0, None = 0,

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
namespace NTwain.Data namespace NTwain.Data
@ -36,7 +37,7 @@ namespace NTwain.Data
var rawType = Enum.GetUnderlyingType(returnType); var rawType = Enum.GetUnderlyingType(returnType);
if (typeof(ushort).IsAssignableFrom(rawType)) if (typeof(ushort).IsAssignableFrom(rawType))
{ {
var intVal = Convert.ToUInt32(value); var intVal = Convert.ToUInt32(value, CultureInfo.InvariantCulture);
var enumVal = GetLowerWord(intVal); var enumVal = GetLowerWord(intVal);
if (!Enum.IsDefined(returnType, enumVal)) if (!Enum.IsDefined(returnType, enumVal))
{ {
@ -52,7 +53,7 @@ namespace NTwain.Data
else if (typeof(IConvertible).IsAssignableFrom(returnType)) else if (typeof(IConvertible).IsAssignableFrom(returnType))
{ {
// for regular integers and whatnot // for regular integers and whatnot
return (T)Convert.ChangeType(value, returnType); return (T)Convert.ChangeType(value, returnType, CultureInfo.InvariantCulture);
} }
// return as-is from cap. if caller made a mistake then there should be exceptions // return as-is from cap. if caller made a mistake then there should be exceptions
return (T)value; return (T)value;
@ -78,7 +79,7 @@ namespace NTwain.Data
{ {
return (TWFix32)value; return (TWFix32)value;
} }
return (TWFix32)Convert.ToSingle(value); return (TWFix32)Convert.ToSingle(value, CultureInfo.InvariantCulture);
} }
} }
} }

22
NTwain/ITwainSession.cs Normal file
View File

@ -0,0 +1,22 @@
using NTwain.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NTwain
{
/// <summary>
/// General interface for a TWAIN session.
/// </summary>
public interface ITwainSession : ITwainState, ITwainOperation
{
/// <summary>
/// Gets the supported caps for the currently open source.
/// </summary>
/// <value>
/// The supported caps.
/// </value>
IList<CapabilityId> SupportedCaps { get; }
}
}

View File

@ -1,6 +1,8 @@
using NTwain.Data; using NTwain.Data;
using NTwain.Properties; using NTwain.Properties;
using System; using System;
using System.Globalization;
using System.IO;
namespace NTwain.Internals namespace NTwain.Internals
{ {
@ -30,14 +32,70 @@ namespace NTwain.Internals
/// <param name="dataArgumentType">The triplet data argument type.</param> /// <param name="dataArgumentType">The triplet data argument type.</param>
/// <param name="message">The triplet message.</param> /// <param name="message">The triplet message.</param>
/// <exception cref="TwainStateException"></exception> /// <exception cref="TwainStateException"></exception>
public static void VerifyState(this ITwainStateInternal session, int allowedMinimum, int allowedMaximum, DataGroups group, DataArgumentType dataArgumentType, Message message) public static void VerifyState(this ITwainSessionInternal session, int allowedMinimum, int allowedMaximum, DataGroups group, DataArgumentType dataArgumentType, Message message)
{ {
if (session.EnforceState && (session.State < allowedMinimum || session.State > allowedMaximum)) if (session.EnforceState && (session.State < allowedMinimum || session.State > allowedMaximum))
{ {
throw new TwainStateException(session.State, allowedMinimum, allowedMaximum, group, dataArgumentType, message, throw new TwainStateException(session.State, allowedMinimum, allowedMaximum, group, dataArgumentType, message,
string.Format("TWAIN state {0} does not match required range {1}-{2} for operation {3}-{4}-{5}.", string.Format(CultureInfo.InvariantCulture, "TWAIN state {0} does not match required range {1}-{2} for operation {3}-{4}-{5}.",
session.State, allowedMinimum, allowedMaximum, group, dataArgumentType, message)); session.State, allowedMinimum, allowedMaximum, group, dataArgumentType, message));
} }
} }
public static string ChangeExtensionByFormat(this TWSetupFileXfer fileInfo, string currentFilePath)
{
string finalFile = null;
switch (fileInfo.Format)
{
case FileFormat.Bmp:
finalFile = Path.ChangeExtension(currentFilePath, ".bmp");
break;
case FileFormat.Dejavu:
finalFile = Path.ChangeExtension(currentFilePath, ".dejavu");
break;
case FileFormat.Exif:
finalFile = Path.ChangeExtension(currentFilePath, ".exit");
break;
case FileFormat.Fpx:
finalFile = Path.ChangeExtension(currentFilePath, ".fpx");
break;
case FileFormat.Jfif:
finalFile = Path.ChangeExtension(currentFilePath, ".jpg");
break;
case FileFormat.Jp2:
finalFile = Path.ChangeExtension(currentFilePath, ".jp2");
break;
case FileFormat.Jpx:
finalFile = Path.ChangeExtension(currentFilePath, ".jpx");
break;
case FileFormat.Pdf:
case FileFormat.PdfA:
case FileFormat.PdfA2:
finalFile = Path.ChangeExtension(currentFilePath, ".pdf");
break;
case FileFormat.Pict:
finalFile = Path.ChangeExtension(currentFilePath, ".pict");
break;
case FileFormat.Png:
finalFile = Path.ChangeExtension(currentFilePath, ".png");
break;
case FileFormat.Spiff:
finalFile = Path.ChangeExtension(currentFilePath, ".spiff");
break;
case FileFormat.Tiff:
case FileFormat.TiffMulti:
finalFile = Path.ChangeExtension(currentFilePath, ".tif");
break;
case FileFormat.Xbm:
finalFile = Path.ChangeExtension(currentFilePath, ".xbm");
break;
default:
finalFile = Path.ChangeExtension(currentFilePath, ".unknown");
break;
}
return finalFile;
}
} }
} }

View File

@ -1,11 +1,12 @@
using NTwain.Data; using NTwain.Data;
using System.Collections.Generic;
namespace NTwain.Internals namespace NTwain.Internals
{ {
/// <summary> /// <summary>
/// Internal interface for state management. /// Internal interface for state management.
/// </summary> /// </summary>
interface ITwainStateInternal : ITwainState interface ITwainSessionInternal : ITwainSession
{ {
/// <summary> /// <summary>
/// Gets the app id used for the session. /// Gets the app id used for the session.
@ -37,5 +38,11 @@ namespace NTwain.Internals
ICommittable GetPendingStateChanger(int newState); ICommittable GetPendingStateChanger(int newState);
void ChangeSourceId(TWIdentity sourceId); void ChangeSourceId(TWIdentity sourceId);
ReturnCode DisableSource();
void SafeSyncableRaiseEvent(DataTransferredEventArgs e);
void SafeSyncableRaiseEvent(TransferErrorEventArgs e);
void SafeSyncableRaiseEvent(TransferReadyEventArgs e);
} }
} }

View File

@ -10,17 +10,17 @@ namespace NTwain.Internals
#region mem stuff for twain 1.x #region mem stuff for twain 1.x
[DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalAlloc")] [DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalAlloc")]
internal static extern IntPtr WinGlobalAlloc(uint uFlags, UIntPtr dwBytes); public static extern IntPtr WinGlobalAlloc(uint uFlags, UIntPtr dwBytes);
[DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalFree")] [DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalFree")]
internal static extern IntPtr WinGlobalFree(IntPtr hMem); public static extern IntPtr WinGlobalFree(IntPtr hMem);
[DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalLock")] [DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalLock")]
internal static extern IntPtr WinGlobalLock(IntPtr handle); public static extern IntPtr WinGlobalLock(IntPtr handle);
[DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalUnlock")] [DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalUnlock")]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool WinGlobalUnlock(IntPtr handle); public static extern bool WinGlobalUnlock(IntPtr handle);
#endregion #endregion
} }

View File

@ -3,10 +3,10 @@
class TentativeStateCommitable : ICommittable class TentativeStateCommitable : ICommittable
{ {
bool _commit; bool _commit;
ITwainStateInternal _session; ITwainSessionInternal _session;
int _origState; int _origState;
int _newState; int _newState;
public TentativeStateCommitable(ITwainStateInternal session, int newState) public TentativeStateCommitable(ITwainSessionInternal session, int newState)
{ {
_session = session; _session = session;
_origState = session.State; _origState = session.State;

View File

@ -0,0 +1,436 @@
using NTwain.Data;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NTwain.Internals
{
/// <summary>
/// Contains the actual data transfer logic since TwainSession is getting too large.
/// </summary>
static class TransferLogic
{
/// <summary>
/// Performs the TWAIN transfer routine at state 6.
/// </summary>
public static void DoTransferRoutine(ITwainSessionInternal session)
{
var pending = new TWPendingXfers();
var rc = ReturnCode.Success;
do
{
#region build and raise xfer ready
TWAudioInfo audInfo;
if (session.DGAudio.AudioInfo.Get(out audInfo) != ReturnCode.Success)
{
audInfo = null;
}
TWImageInfo imgInfo;
if (session.DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
// ask consumer for xfer details
var preXferArgs = new TransferReadyEventArgs
{
AudioInfo = audInfo,
PendingImageInfo = imgInfo,
PendingTransferCount = pending.Count,
EndOfJob = pending.EndOfJob == 0
};
session.SafeSyncableRaiseEvent(preXferArgs);
#endregion
#region actually handle xfer
if (preXferArgs.CancelAll)
{
rc = session.DGControl.PendingXfers.Reset(pending);
}
else if (!preXferArgs.CancelCurrent)
{
DataGroups xferGroup = DataGroups.None;
if (session.DGControl.XferGroup.Get(ref xferGroup) != ReturnCode.Success)
{
xferGroup = DataGroups.None;
}
if ((xferGroup & DataGroups.Image) == DataGroups.Image)
{
var mech = session.GetCurrentCap(CapabilityId.ICapXferMech).ConvertToEnum<XferMech>();
switch (mech)
{
case XferMech.Native:
DoImageNativeXfer(session);
break;
case XferMech.Memory:
DoImageMemoryXfer(session);
break;
case XferMech.File:
DoImageFileXfer(session);
break;
case XferMech.MemFile:
DoImageMemoryFileXfer(session);
break;
}
}
if ((xferGroup & DataGroups.Audio) == DataGroups.Audio)
{
var mech = session.GetCurrentCap(CapabilityId.ACapXferMech).ConvertToEnum<XferMech>();
switch (mech)
{
case XferMech.Native:
DoAudioNativeXfer(session);
break;
case XferMech.File:
DoAudioFileXfer(session);
break;
}
}
}
rc = session.DGControl.PendingXfers.EndXfer(pending);
#endregion
} while (rc == ReturnCode.Success && pending.Count != 0);
session.ChangeState(5, true);
session.DisableSource();
}
#region audio xfers
static void DoAudioNativeXfer(ITwainSessionInternal session)
{
IntPtr dataPtr = IntPtr.Zero;
IntPtr lockedPtr = IntPtr.Zero;
try
{
var xrc = session.DGAudio.AudioNativeXfer.Get(ref dataPtr);
if (xrc == ReturnCode.XferDone)
{
session.ChangeState(7, true);
if (dataPtr != IntPtr.Zero)
{
lockedPtr = Platform.MemoryManager.Lock(dataPtr);
}
session.SafeSyncableRaiseEvent(new DataTransferredEventArgs { NativeData = lockedPtr });
}
else
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.GetSourceStatus() });
}
}
catch (Exception ex)
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { Exception = ex });
}
finally
{
session.ChangeState(6, true);
// data here is allocated by source so needs to use shared mem calls
if (lockedPtr != IntPtr.Zero)
{
Platform.MemoryManager.Unlock(lockedPtr);
lockedPtr = IntPtr.Zero;
}
if (dataPtr != IntPtr.Zero)
{
Platform.MemoryManager.Free(dataPtr);
dataPtr = IntPtr.Zero;
}
}
}
static void DoAudioFileXfer(ITwainSessionInternal session)
{
string filePath = null;
TWSetupFileXfer setupInfo;
if (session.DGControl.SetupFileXfer.Get(out setupInfo) == ReturnCode.Success)
{
filePath = setupInfo.FileName;
}
var xrc = session.DGAudio.AudioFileXfer.Get();
if (xrc == ReturnCode.XferDone)
{
session.SafeSyncableRaiseEvent(new DataTransferredEventArgs { FileDataPath = filePath });
}
else
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.GetSourceStatus() });
}
}
#endregion
#region image xfers
static void DoImageNativeXfer(ITwainSessionInternal session)
{
IntPtr dataPtr = IntPtr.Zero;
IntPtr lockedPtr = IntPtr.Zero;
try
{
var xrc = session.DGImage.ImageNativeXfer.Get(ref dataPtr);
if (xrc == ReturnCode.XferDone)
{
session.ChangeState(7, true);
if (dataPtr != IntPtr.Zero)
{
lockedPtr = Platform.MemoryManager.Lock(dataPtr);
}
DoImageXferredEventRoutine(session, lockedPtr, null, null);
}
else
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.GetSourceStatus() });
}
}
catch (Exception ex)
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { Exception = ex });
}
finally
{
session.ChangeState(6, true);
// data here is allocated by source so needs to use shared mem calls
if (lockedPtr != IntPtr.Zero)
{
Platform.MemoryManager.Unlock(lockedPtr);
lockedPtr = IntPtr.Zero;
}
if (dataPtr != IntPtr.Zero)
{
Platform.MemoryManager.Free(dataPtr);
dataPtr = IntPtr.Zero;
}
}
}
static void DoImageFileXfer(ITwainSessionInternal session)
{
string filePath = null;
TWSetupFileXfer setupInfo;
if (session.DGControl.SetupFileXfer.Get(out setupInfo) == ReturnCode.Success)
{
filePath = setupInfo.FileName;
}
var xrc = session.DGImage.ImageFileXfer.Get();
if (xrc == ReturnCode.XferDone)
{
DoImageXferredEventRoutine(session, IntPtr.Zero, null, filePath);
}
else
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.GetSourceStatus() });
}
}
static void DoImageMemoryXfer(ITwainSessionInternal session)
{
TWSetupMemXfer memInfo;
if (session.DGControl.SetupMemXfer.Get(out memInfo) == ReturnCode.Success)
{
TWImageMemXfer xferInfo = new TWImageMemXfer();
try
{
// how to tell if going to xfer in strip vs tile?
// if tile don't allocate memory in app?
xferInfo.Memory = new TWMemory
{
Flags = MemoryFlags.AppOwns | MemoryFlags.Pointer,
Length = memInfo.Preferred,
TheMem = Platform.MemoryManager.Allocate(memInfo.Preferred)
};
// do the unthinkable and keep all xferred batches in memory,
// possibly defeating the purpose of mem xfer
// unless compression is used.
// todo: use array instead of memory stream?
using (MemoryStream xferredData = new MemoryStream())
{
var xrc = ReturnCode.Success;
do
{
xrc = session.DGImage.ImageMemFileXfer.Get(xferInfo);
if (xrc == ReturnCode.Success ||
xrc == ReturnCode.XferDone)
{
session.ChangeState(7, true);
// optimize and allocate buffer only once instead of inside the loop?
byte[] buffer = new byte[(int)xferInfo.BytesWritten];
IntPtr lockPtr = IntPtr.Zero;
try
{
lockPtr = Platform.MemoryManager.Lock(xferInfo.Memory.TheMem);
Marshal.Copy(lockPtr, buffer, 0, buffer.Length);
xferredData.Write(buffer, 0, buffer.Length);
}
finally
{
if (lockPtr != IntPtr.Zero)
{
Platform.MemoryManager.Unlock(lockPtr);
}
}
}
} while (xrc == ReturnCode.Success);
if (xrc == ReturnCode.XferDone)
{
DoImageXferredEventRoutine(session, IntPtr.Zero, xferredData.ToArray(), null);
}
else
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.GetSourceStatus() });
}
}
}
catch (Exception ex)
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { Exception = ex });
}
finally
{
session.ChangeState(6, true);
if (xferInfo.Memory.TheMem != IntPtr.Zero)
{
Platform.MemoryManager.Free(xferInfo.Memory.TheMem);
}
}
}
}
static void DoImageMemoryFileXfer(ITwainSessionInternal session)
{
// since it's memory-file xfer need info from both (maybe)
TWSetupMemXfer memInfo;
TWSetupFileXfer fileInfo;
if (session.DGControl.SetupMemXfer.Get(out memInfo) == ReturnCode.Success &&
session.DGControl.SetupFileXfer.Get(out fileInfo) == ReturnCode.Success)
{
TWImageMemXfer xferInfo = new TWImageMemXfer();
var tempFile = Path.GetTempFileName();
string finalFile = null;
try
{
// no strip or tile here, just chunks
xferInfo.Memory = new TWMemory
{
Flags = MemoryFlags.AppOwns | MemoryFlags.Pointer,
Length = memInfo.Preferred,
TheMem = Platform.MemoryManager.Allocate(memInfo.Preferred)
};
var xrc = ReturnCode.Success;
using (var outStream = File.OpenWrite(tempFile))
{
do
{
xrc = session.DGImage.ImageMemFileXfer.Get(xferInfo);
if (xrc == ReturnCode.Success ||
xrc == ReturnCode.XferDone)
{
session.ChangeState(7, true);
byte[] buffer = new byte[(int)xferInfo.BytesWritten];
IntPtr lockPtr = IntPtr.Zero;
try
{
lockPtr = Platform.MemoryManager.Lock(xferInfo.Memory.TheMem);
Marshal.Copy(lockPtr, buffer, 0, buffer.Length);
}
finally
{
if (lockPtr != IntPtr.Zero)
{
Platform.MemoryManager.Unlock(lockPtr);
}
}
outStream.Write(buffer, 0, buffer.Length);
}
} while (xrc == ReturnCode.Success);
}
if (xrc == ReturnCode.XferDone)
{
finalFile = fileInfo.ChangeExtensionByFormat(tempFile);
File.Move(tempFile, finalFile);
}
else
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = session.GetSourceStatus() });
}
}
catch (Exception ex)
{
session.SafeSyncableRaiseEvent(new TransferErrorEventArgs { Exception = ex });
}
finally
{
session.ChangeState(6, true);
if (xferInfo.Memory.TheMem != IntPtr.Zero)
{
Platform.MemoryManager.Free(xferInfo.Memory.TheMem);
}
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
}
if (File.Exists(finalFile))
{
DoImageXferredEventRoutine(session, IntPtr.Zero, null, finalFile);
}
}
}
static void DoImageXferredEventRoutine(ITwainSessionInternal session, IntPtr dataPtr, byte[] dataArray, string filePath)
{
TWImageInfo imgInfo;
TWExtImageInfo extInfo = null;
if (session.SupportedCaps.Contains(CapabilityId.ICapExtImageInfo))
{
if (session.DGImage.ExtImageInfo.Get(out extInfo) != ReturnCode.Success)
{
extInfo = null;
}
}
if (session.DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
session.SafeSyncableRaiseEvent(new DataTransferredEventArgs
{
NativeData = dataPtr,
MemData = dataArray,
FileDataPath = filePath,
ImageInfo = imgInfo,
ExImageInfo = extInfo
});
if (extInfo != null) { extInfo.Dispose(); }
}
#endregion
}
}

View File

@ -1,6 +1,7 @@
using NTwain.Data; using NTwain.Data;
using NTwain.Internals; using NTwain.Internals;
using System; using System;
using System.ComponentModel;
namespace NTwain namespace NTwain
{ {
@ -16,7 +17,7 @@ namespace NTwain
if (retVal == IntPtr.Zero) if (retVal == IntPtr.Zero)
{ {
throw new OutOfMemoryException(); throw new Win32Exception();
} }
return retVal; return retVal;
} }

View File

@ -27,7 +27,7 @@
<DocumentationFile> <DocumentationFile>
</DocumentationFile> </DocumentationFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
@ -60,10 +60,12 @@
<Compile Include="DataTransferredEventArgs.cs" /> <Compile Include="DataTransferredEventArgs.cs" />
<Compile Include="IMemoryManager.cs" /> <Compile Include="IMemoryManager.cs" />
<Compile Include="Internals\ICommittable.cs" /> <Compile Include="Internals\ICommittable.cs" />
<Compile Include="Internals\ITwainStateInternal.cs" /> <Compile Include="Internals\ITwainSessionInternal.cs" />
<Compile Include="Internals\TransferLogic.cs" />
<Compile Include="Internals\WindowsHook.cs" /> <Compile Include="Internals\WindowsHook.cs" />
<Compile Include="Internals\WrappedManualResetEvent.cs" /> <Compile Include="Internals\WrappedManualResetEvent.cs" />
<Compile Include="ITwainOperation.cs" /> <Compile Include="ITwainOperation.cs" />
<Compile Include="ITwainSession.cs" />
<Compile Include="ITwainState.cs" /> <Compile Include="ITwainState.cs" />
<Compile Include="Internals\WinMemoryManager.cs" /> <Compile Include="Internals\WinMemoryManager.cs" />
<Compile Include="Internals\MessageLoop.cs" /> <Compile Include="Internals\MessageLoop.cs" />

View File

@ -9,7 +9,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
sealed class AudioFileXfer : OpBase sealed class AudioFileXfer : OpBase
{ {
internal AudioFileXfer(ITwainStateInternal session) : base(session) { } internal AudioFileXfer(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation is used to initiate the transfer of audio from the Source to the application via the /// This operation is used to initiate the transfer of audio from the Source to the application via the
/// disk-file transfer mechanism. It causes the transfer to begin. /// disk-file transfer mechanism. It causes the transfer to begin.

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class AudioInfo : OpBase public sealed class AudioInfo : OpBase
{ {
internal AudioInfo(ITwainStateInternal session) : base(session) { } internal AudioInfo(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Used to get the information of the current audio data ready to transfer. /// Used to get the information of the current audio data ready to transfer.
/// </summary> /// </summary>

View File

@ -9,7 +9,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
sealed class AudioNativeXfer : OpBase sealed class AudioNativeXfer : OpBase
{ {
internal AudioNativeXfer(ITwainStateInternal session) : base(session) { } internal AudioNativeXfer(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Causes the transfer of an audio data from the Source to the application, via the Native /// Causes the transfer of an audio data from the Source to the application, via the Native
/// transfer mechanism, to begin. The resulting data is stored in main memory in a single block. /// transfer mechanism, to begin. The resulting data is stored in main memory in a single block.

View File

@ -8,8 +8,8 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class DGAudio public sealed class DGAudio
{ {
ITwainStateInternal _session; ITwainSessionInternal _session;
internal DGAudio(ITwainStateInternal session) internal DGAudio(ITwainSessionInternal session)
{ {
if (session == null) { throw new ArgumentNullException("session"); } if (session == null) { throw new ArgumentNullException("session"); }
_session = session; _session = session;

View File

@ -5,7 +5,7 @@ namespace NTwain.Triplets
{ {
sealed class Callback : OpBase sealed class Callback : OpBase
{ {
internal Callback(ITwainStateInternal session) : base(session) { } internal Callback(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This triplet is sent to the DSM by the Application to register the applications entry point with /// This triplet is sent to the DSM by the Application to register the applications entry point with
/// the DSM, so that the DSM can use callbacks to inform the application of events generated by the /// the DSM, so that the DSM can use callbacks to inform the application of events generated by the

View File

@ -5,7 +5,7 @@ namespace NTwain.Triplets
{ {
sealed class Callback2 : OpBase sealed class Callback2 : OpBase
{ {
internal Callback2(ITwainStateInternal session) : base(session) { } internal Callback2(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This triplet is sent to the DSM by the Application to register the applications entry point with /// This triplet is sent to the DSM by the Application to register the applications entry point with
/// the DSM, so that the DSM can use callbacks to inform the application of events generated by the /// the DSM, so that the DSM can use callbacks to inform the application of events generated by the

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class Capability : OpBase public sealed class Capability : OpBase
{ {
internal Capability(ITwainStateInternal session) : base(session) { } internal Capability(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Returns the Sources Current, Default and Available Values for a specified capability. /// Returns the Sources Current, Default and Available Values for a specified capability.
/// </summary> /// </summary>

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class CustomDSData : OpBase public sealed class CustomDSData : OpBase
{ {
internal CustomDSData(ITwainStateInternal session) : base(session) { } internal CustomDSData(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation is used by the application to query the data source for its current settings, e.g. /// This operation is used by the application to query the data source for its current settings, e.g.
/// DPI, paper size, color format. The actual format of the data is data source dependent and not /// DPI, paper size, color format. The actual format of the data is data source dependent and not

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class DeviceEvent : OpBase public sealed class DeviceEvent : OpBase
{ {
internal DeviceEvent(ITwainStateInternal session) : base(session) { } internal DeviceEvent(ITwainSessionInternal session) : base(session) { }
public ReturnCode Get(out TWDeviceEvent sourceDeviceEvent) public ReturnCode Get(out TWDeviceEvent sourceDeviceEvent)
{ {
Session.VerifyState(4, 7, DataGroups.Control, DataArgumentType.DeviceEvent, Message.Get); Session.VerifyState(4, 7, DataGroups.Control, DataArgumentType.DeviceEvent, Message.Get);

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
sealed class EntryPoint : OpBase sealed class EntryPoint : OpBase
{ {
internal EntryPoint(ITwainStateInternal session) : base(session) { } internal EntryPoint(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Gets the function entry points for twain 2.0 or higher. /// Gets the function entry points for twain 2.0 or higher.
/// </summary> /// </summary>

View File

@ -5,7 +5,7 @@ namespace NTwain.Triplets
{ {
sealed class Event : OpBase sealed class Event : OpBase
{ {
internal Event(ITwainStateInternal session) : base(session) { } internal Event(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation supports the distribution of events from the application to Sources so that the /// This operation supports the distribution of events from the application to Sources so that the

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class FileSystem : OpBase public sealed class FileSystem : OpBase
{ {
internal FileSystem(ITwainStateInternal session) : base(session) { } internal FileSystem(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation selects the destination directory within the Source (camera, storage, etc), where /// This operation selects the destination directory within the Source (camera, storage, etc), where
/// images captured using CapAutomaticCapture will be stored. This command only selects /// images captured using CapAutomaticCapture will be stored. This command only selects

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class Identity : OpBase public sealed class Identity : OpBase
{ {
internal Identity(ITwainStateInternal session) : base(session) { } internal Identity(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// When an application is finished with a Source, it must formally close the session between them /// When an application is finished with a Source, it must formally close the session between them
/// using this operation. This is necessary in case the Source only supports connection with a single /// using this operation. This is necessary in case the Source only supports connection with a single

View File

@ -9,7 +9,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
sealed class Parent : OpBase sealed class Parent : OpBase
{ {
internal Parent(ITwainStateInternal session) : base(session) { } internal Parent(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// When the application has closed all the Sources it had previously opened, and is finished with /// When the application has closed all the Sources it had previously opened, and is finished with

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class PassThru : OpBase public sealed class PassThru : OpBase
{ {
internal PassThru(ITwainStateInternal session) : base(session) { } internal PassThru(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// PASSTHRU is intended for the use of Source writers writing diagnostic applications. It allows /// PASSTHRU is intended for the use of Source writers writing diagnostic applications. It allows
/// raw communication with the currently selected device in the Source. /// raw communication with the currently selected device in the Source.

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
sealed class PendingXfers : OpBase sealed class PendingXfers : OpBase
{ {
internal PendingXfers(ITwainStateInternal session) : base(session) { } internal PendingXfers(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This triplet is used to cancel or terminate a transfer. Issued in state 6, this triplet cancels the next /// This triplet is used to cancel or terminate a transfer. Issued in state 6, this triplet cancels the next
/// pending transfer, discards the transfer data, and decrements the pending transfers count. In /// pending transfer, discards the transfer data, and decrements the pending transfers count. In

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class SetupFileXfer : OpBase public sealed class SetupFileXfer : OpBase
{ {
internal SetupFileXfer(ITwainStateInternal session) : base(session) { } internal SetupFileXfer(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Returns information about the file into which the Source has or will put the acquired image /// Returns information about the file into which the Source has or will put the acquired image
/// or audio data. /// or audio data.

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class SetupMemXfer : OpBase public sealed class SetupMemXfer : OpBase
{ {
internal SetupMemXfer(ITwainStateInternal session) : base(session) { } internal SetupMemXfer(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Returns the Sources preferred, minimum, and maximum allocation sizes for transfer memory /// Returns the Sources preferred, minimum, and maximum allocation sizes for transfer memory
/// buffers. /// buffers.

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class Status : OpBase public sealed class Status : OpBase
{ {
internal Status(ITwainStateInternal session) : base(session) { } internal Status(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Returns the current Condition Code for the Source Manager. /// Returns the current Condition Code for the Source Manager.
/// </summary> /// </summary>

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class StatusUtf8 : OpBase public sealed class StatusUtf8 : OpBase
{ {
internal StatusUtf8(ITwainStateInternal session) : base(session) { } internal StatusUtf8(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Translate the contents of a TW_STATUS structure received from a Source into a localized UTF-8 /// Translate the contents of a TW_STATUS structure received from a Source into a localized UTF-8
/// encoded string. /// encoded string.

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
sealed class UserInterface : OpBase sealed class UserInterface : OpBase
{ {
internal UserInterface(ITwainStateInternal session) : base(session) { } internal UserInterface(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation causes the Sources user interface, if displayed during the /// This operation causes the Sources user interface, if displayed during the
/// EnableDS operation, to be lowered. The Source is returned to /// EnableDS operation, to be lowered. The Source is returned to

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class XferGroup : OpBase public sealed class XferGroup : OpBase
{ {
internal XferGroup(ITwainStateInternal session) : base(session) { } internal XferGroup(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Returns the Data Group (the type of data) for the upcoming transfer. The Source is required to /// Returns the Data Group (the type of data) for the upcoming transfer. The Source is required to

View File

@ -8,8 +8,8 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class DGControl public sealed class DGControl
{ {
ITwainStateInternal _session; ITwainSessionInternal _session;
internal DGControl(ITwainStateInternal session) internal DGControl(ITwainSessionInternal session)
{ {
if (session == null) { throw new ArgumentNullException("session"); } if (session == null) { throw new ArgumentNullException("session"); }
_session = session; _session = session;

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class CieColor : OpBase public sealed class CieColor : OpBase
{ {
internal CieColor(ITwainStateInternal session) : base(session) { } internal CieColor(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation causes the Source to report the currently active parameters to be used in /// This operation causes the Source to report the currently active parameters to be used in

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class ExtImageInfo : OpBase public sealed class ExtImageInfo : OpBase
{ {
internal ExtImageInfo(ITwainStateInternal session) : base(session) { } internal ExtImageInfo(ITwainSessionInternal session) : base(session) { }
public ReturnCode Get(out TWExtImageInfo info) public ReturnCode Get(out TWExtImageInfo info)
{ {

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class Filter : OpBase public sealed class Filter : OpBase
{ {
internal Filter(ITwainStateInternal session) : base(session) { } internal Filter(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class GrayResponse : OpBase public sealed class GrayResponse : OpBase
{ {
internal GrayResponse(ITwainStateInternal session) : base(session) { } internal GrayResponse(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// The Reset operation causes the Source to use its "identity response curve." The identity /// The Reset operation causes the Source to use its "identity response curve." The identity

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class IccProfile : OpBase public sealed class IccProfile : OpBase
{ {
internal IccProfile(ITwainStateInternal session) : base(session) { } internal IccProfile(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation provides the application with the ICC profile associated with the image which is /// This operation provides the application with the ICC profile associated with the image which is

View File

@ -9,7 +9,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
sealed class ImageFileXfer : OpBase sealed class ImageFileXfer : OpBase
{ {
internal ImageFileXfer(ITwainStateInternal session) : base(session) { } internal ImageFileXfer(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation is used to initiate the transfer of an image from the Source to the application via /// This operation is used to initiate the transfer of an image from the Source to the application via

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class ImageInfo : OpBase public sealed class ImageInfo : OpBase
{ {
internal ImageInfo(ITwainStateInternal session) : base(session) { } internal ImageInfo(ITwainSessionInternal session) : base(session) { }
public ReturnCode Get(out TWImageInfo info) public ReturnCode Get(out TWImageInfo info)
{ {

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class ImageLayout : OpBase public sealed class ImageLayout : OpBase
{ {
internal ImageLayout(ITwainStateInternal session) : base(session) { } internal ImageLayout(ITwainSessionInternal session) : base(session) { }
public ReturnCode Get(out TWImageLayout layout) public ReturnCode Get(out TWImageLayout layout)
{ {

View File

@ -5,7 +5,7 @@ namespace NTwain.Triplets
{ {
sealed class ImageMemFileXfer : OpBase sealed class ImageMemFileXfer : OpBase
{ {
internal ImageMemFileXfer(ITwainStateInternal session) : base(session) { } internal ImageMemFileXfer(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation is used to initiate the transfer of an image from the Source to the application via /// This operation is used to initiate the transfer of an image from the Source to the application via

View File

@ -5,7 +5,7 @@ namespace NTwain.Triplets
{ {
sealed class ImageMemXfer : OpBase sealed class ImageMemXfer : OpBase
{ {
internal ImageMemXfer(ITwainStateInternal session) : base(session) { } internal ImageMemXfer(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation is used to initiate the transfer of an image from the Source to the application via /// This operation is used to initiate the transfer of an image from the Source to the application via

View File

@ -6,7 +6,7 @@ namespace NTwain.Triplets
{ {
sealed class ImageNativeXfer : OpBase sealed class ImageNativeXfer : OpBase
{ {
internal ImageNativeXfer(ITwainStateInternal session) : base(session) { } internal ImageNativeXfer(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Causes the transfer of an images data from the Source to the application, via the Native transfer /// Causes the transfer of an images data from the Source to the application, via the Native transfer

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class JpegCompression : OpBase public sealed class JpegCompression : OpBase
{ {
internal JpegCompression(ITwainStateInternal session) : base(session) { } internal JpegCompression(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Causes the Source to return the parameters that will be used during the compression of data /// Causes the Source to return the parameters that will be used during the compression of data

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class Palette8 : OpBase public sealed class Palette8 : OpBase
{ {
internal Palette8(ITwainStateInternal session) : base(session) { } internal Palette8(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// This operation causes the Source to report its current palette information. /// This operation causes the Source to report its current palette information.

View File

@ -8,7 +8,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class RgbResponse : OpBase public sealed class RgbResponse : OpBase
{ {
internal RgbResponse(ITwainStateInternal session) : base(session) { } internal RgbResponse(ITwainSessionInternal session) : base(session) { }
/// <summary> /// <summary>
/// Causes the Source to use its "identity" response curves for future RGB transfers. The identity /// Causes the Source to use its "identity" response curves for future RGB transfers. The identity

View File

@ -8,8 +8,8 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
public sealed class DGImage public sealed class DGImage
{ {
ITwainStateInternal _session; ITwainSessionInternal _session;
internal DGImage(ITwainStateInternal session) internal DGImage(ITwainSessionInternal session)
{ {
if (session == null) { throw new ArgumentNullException("session"); } if (session == null) { throw new ArgumentNullException("session"); }
_session = session; _session = session;

View File

@ -13,7 +13,7 @@ namespace NTwain.Triplets
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentNullException"></exception>
internal OpBase(ITwainStateInternal session) internal OpBase(ITwainSessionInternal session)
{ {
if (session == null) { throw new ArgumentNullException("session"); } if (session == null) { throw new ArgumentNullException("session"); }
Session = session; Session = session;
@ -25,6 +25,6 @@ namespace NTwain.Triplets
/// <value> /// <value>
/// The session. /// The session.
/// </value> /// </value>
internal ITwainStateInternal Session { get; private set; } internal ITwainSessionInternal Session { get; private set; }
} }
} }

View File

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
@ -15,7 +16,7 @@ namespace NTwain
/// <summary> /// <summary>
/// Basic class for interfacing with TWAIN. You should only have one of this per application process. /// Basic class for interfacing with TWAIN. You should only have one of this per application process.
/// </summary> /// </summary>
public class TwainSession : ITwainStateInternal, ITwainOperation public class TwainSession : ITwainSessionInternal
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TwainSession" /> class. /// Initializes a new instance of the <see cref="TwainSession" /> class.
@ -27,21 +28,22 @@ namespace NTwain
if (appId == null) { throw new ArgumentNullException("appId"); } if (appId == null) { throw new ArgumentNullException("appId"); }
_appId = appId; _appId = appId;
((ITwainStateInternal)this).ChangeState(1, false); ((ITwainSessionInternal)this).ChangeState(1, false);
EnforceState = true; EnforceState = true;
MessageLoop.Instance.EnsureStarted(HandleWndProcMessage); MessageLoop.Instance.EnsureStarted(HandleWndProcMessage);
} }
TWIdentity _appId; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
object _callbackObj; // kept around so it doesn't get gc'ed object _callbackObj; // kept around so it doesn't get gc'ed
TWIdentity _appId;
TWUserInterface _twui; TWUserInterface _twui;
static readonly CapabilityId[] _emptyCapList = new CapabilityId[0]; static readonly CapabilityId[] _emptyCapList = new CapabilityId[0];
private IList<CapabilityId> _supportedCaps; private IList<CapabilityId> _supportedCaps;
/// <summary> /// <summary>
/// Gets the supported caps for the current source. /// Gets the supported caps for the currently open source.
/// </summary> /// </summary>
/// <value> /// <value>
/// The supported caps. /// The supported caps.
@ -64,7 +66,7 @@ namespace NTwain
} }
/// <summary> /// <summary>
/// EXPERIMENTAL. Gets or sets the optional synchronization context. /// Gets or sets the optional synchronization context.
/// This allows events to be raised on the thread /// This allows events to be raised on the thread
/// associated with the context. /// associated with the context.
/// </summary> /// </summary>
@ -74,13 +76,13 @@ namespace NTwain
public SynchronizationContext SynchronizationContext { get; set; } public SynchronizationContext SynchronizationContext { get; set; }
#region ITwainStateInternal Members #region ITwainSessionInternal Members
/// <summary> /// <summary>
/// Gets the app id used for the session. /// Gets the app id used for the session.
/// </summary> /// </summary>
/// <value>The app id.</value> /// <value>The app id.</value>
TWIdentity ITwainStateInternal.AppId { get { return _appId; } } TWIdentity ITwainSessionInternal.AppId { get { return _appId; } }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether calls to triplets will verify the current twain session state. /// Gets or sets a value indicating whether calls to triplets will verify the current twain session state.
@ -90,7 +92,7 @@ namespace NTwain
/// </value> /// </value>
public bool EnforceState { get; set; } public bool EnforceState { get; set; }
void ITwainStateInternal.ChangeState(int newState, bool notifyChange) void ITwainSessionInternal.ChangeState(int newState, bool notifyChange)
{ {
_state = newState; _state = newState;
if (notifyChange) if (notifyChange)
@ -100,18 +102,31 @@ namespace NTwain
} }
} }
ICommittable ITwainStateInternal.GetPendingStateChanger(int newState) ICommittable ITwainSessionInternal.GetPendingStateChanger(int newState)
{ {
return new TentativeStateCommitable(this, newState); return new TentativeStateCommitable(this, newState);
} }
void ITwainStateInternal.ChangeSourceId(TWIdentity sourceId) void ITwainSessionInternal.ChangeSourceId(TWIdentity sourceId)
{ {
SourceId = sourceId; SourceId = sourceId;
RaisePropertyChanged("SourceId"); RaisePropertyChanged("SourceId");
SafeAsyncSyncableRaiseOnEvent(OnSourceChanged, SourceChanged); SafeAsyncSyncableRaiseOnEvent(OnSourceChanged, SourceChanged);
} }
void ITwainSessionInternal.SafeSyncableRaiseEvent(DataTransferredEventArgs e)
{
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, e);
}
void ITwainSessionInternal.SafeSyncableRaiseEvent(TransferErrorEventArgs e)
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, e);
}
void ITwainSessionInternal.SafeSyncableRaiseEvent(TransferReadyEventArgs e)
{
SafeSyncableRaiseOnEvent(OnTransferReady, TransferReady, e);
}
#endregion #endregion
#region ITwainState Members #region ITwainState Members
@ -134,7 +149,7 @@ namespace NTwain
public int State public int State
{ {
get { return _state; } get { return _state; }
protected set internal protected set
{ {
if (value > 0 && value < 8) if (value > 0 && value < 8)
{ {
@ -240,7 +255,7 @@ namespace NTwain
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
MessageLoop.Instance.Invoke(() => MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: OpenManager.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: OpenManager.", Thread.CurrentThread.ManagedThreadId));
rc = DGControl.Parent.OpenDsm(MessageLoop.Instance.LoopHandle); rc = DGControl.Parent.OpenDsm(MessageLoop.Instance.LoopHandle);
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
@ -274,7 +289,7 @@ namespace NTwain
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
MessageLoop.Instance.Invoke(() => MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: CloseManager.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: CloseManager.", Thread.CurrentThread.ManagedThreadId));
rc = DGControl.Parent.CloseDsm(MessageLoop.Instance.LoopHandle); rc = DGControl.Parent.CloseDsm(MessageLoop.Instance.LoopHandle);
}); });
@ -296,7 +311,7 @@ namespace NTwain
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
MessageLoop.Instance.Invoke(() => MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: OpenSource.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: OpenSource.", Thread.CurrentThread.ManagedThreadId));
var source = new TWIdentity(); var source = new TWIdentity();
source.ProductName = sourceProductName; source.ProductName = sourceProductName;
@ -318,7 +333,7 @@ namespace NTwain
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
MessageLoop.Instance.Invoke(() => MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: CloseSource.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: CloseSource.", Thread.CurrentThread.ManagedThreadId));
rc = DGControl.Identity.CloseDS(); rc = DGControl.Identity.CloseDS();
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
@ -343,7 +358,7 @@ namespace NTwain
MessageLoop.Instance.Invoke(() => MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: EnableSource.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: EnableSource.", Thread.CurrentThread.ManagedThreadId));
// app v2.2 or higher uses callback2 // app v2.2 or higher uses callback2
if (_appId.ProtocolMajor >= 2 && _appId.ProtocolMinor >= 2) if (_appId.ProtocolMajor >= 2 && _appId.ProtocolMinor >= 2)
@ -387,17 +402,13 @@ namespace NTwain
return rc; return rc;
} }
/// <summary> ReturnCode ITwainSessionInternal.DisableSource()
/// Disables the source to end data acquisition.
/// </summary>
/// <returns></returns>
protected ReturnCode DisableSource()
{ {
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
MessageLoop.Instance.Invoke(() => MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: DisableSource.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: DisableSource.", Thread.CurrentThread.ManagedThreadId));
rc = DGControl.UserInterface.DisableDS(_twui); rc = DGControl.UserInterface.DisableDS(_twui);
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
@ -416,7 +427,7 @@ namespace NTwain
/// <param name="targetState">State of the target.</param> /// <param name="targetState">State of the target.</param>
public void ForceStepDown(int targetState) public void ForceStepDown(int targetState)
{ {
Debug.WriteLine(string.Format("Thread {0}: ForceStepDown.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: ForceStepDown.", Thread.CurrentThread.ManagedThreadId));
bool origFlag = EnforceState; bool origFlag = EnforceState;
EnforceState = false; EnforceState = false;
@ -448,7 +459,7 @@ namespace NTwain
} }
if (targetState < 5) if (targetState < 5)
{ {
DisableSource(); ((ITwainSessionInternal)this).DisableSource();
} }
if (targetState < 4) if (targetState < 4)
{ {
@ -496,6 +507,38 @@ namespace NTwain
/// </summary> /// </summary>
public event EventHandler<TransferErrorEventArgs> TransferError; public event EventHandler<TransferErrorEventArgs> TransferError;
/// <summary>
/// Raises event and if applicable marshal it asynchronously to the <see cref="SynchronizationContext"/> thread.
/// </summary>
/// <param name="onEventFunc">The on event function.</param>
/// <param name="handler">The handler.</param>
void SafeAsyncSyncableRaiseOnEvent(Action onEventFunc, EventHandler handler)
{
var syncer = SynchronizationContext;
if (syncer == null)
{
try
{
onEventFunc();
if (handler != null) { handler(this, EventArgs.Empty); }
}
catch { }
}
else
{
syncer.Post(o =>
{
try
{
onEventFunc();
if (handler != null) { handler(this, EventArgs.Empty); }
}
catch { }
}, null);
}
}
/// <summary> /// <summary>
/// Raises event and if applicable marshal it synchronously to the <see cref="SynchronizationContext" /> thread. /// Raises event and if applicable marshal it synchronously to the <see cref="SynchronizationContext" /> thread.
/// </summary> /// </summary>
@ -529,37 +572,6 @@ namespace NTwain
} }
} }
/// <summary>
/// Raises event and if applicable marshal it asynchronously to the <see cref="SynchronizationContext"/> thread.
/// </summary>
/// <param name="onEventFunc">The on event function.</param>
/// <param name="handler">The handler.</param>
void SafeAsyncSyncableRaiseOnEvent(Action onEventFunc, EventHandler handler)
{
var syncer = SynchronizationContext;
if (syncer == null)
{
try
{
onEventFunc();
if (handler != null) { handler(this, EventArgs.Empty); }
}
catch { }
}
else
{
syncer.Post(o =>
{
try
{
onEventFunc();
if (handler != null) { handler(this, EventArgs.Empty); }
}
catch { }
}, null);
}
}
/// <summary> /// <summary>
/// Called when <see cref="State"/> changed. /// Called when <see cref="State"/> changed.
/// </summary> /// </summary>
@ -585,25 +597,24 @@ namespace NTwain
/// Called when a data transfer is ready. /// Called when a data transfer is ready.
/// </summary> /// </summary>
/// <param name="e">The <see cref="TransferReadyEventArgs"/> instance containing the event data.</param> /// <param name="e">The <see cref="TransferReadyEventArgs"/> instance containing the event data.</param>
protected virtual void OnTransferReady(TransferReadyEventArgs e) { } internal protected virtual void OnTransferReady(TransferReadyEventArgs e) { }
/// <summary> /// <summary>
/// Called when data has been transferred. /// Called when data has been transferred.
/// </summary> /// </summary>
/// <param name="e">The <see cref="DataTransferredEventArgs"/> instance containing the event data.</param> /// <param name="e">The <see cref="DataTransferredEventArgs"/> instance containing the event data.</param>
protected virtual void OnDataTransferred(DataTransferredEventArgs e) { } internal protected virtual void OnDataTransferred(DataTransferredEventArgs e) { }
/// <summary> /// <summary>
/// Called when an error has been encountered during transfer. /// Called when an error has been encountered during transfer.
/// </summary> /// </summary>
/// <param name="e">The <see cref="TransferErrorEventArgs"/> instance containing the event data.</param> /// <param name="e">The <see cref="TransferErrorEventArgs"/> instance containing the event data.</param>
protected virtual void OnTransferError(TransferErrorEventArgs e) { } internal protected virtual void OnTransferError(TransferErrorEventArgs e) { }
#endregion #endregion
#region TWAIN logic during xfer work #region handle twain ds message
//[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
void HandleWndProcMessage(ref WindowsHook.MESSAGE winMsg, ref bool handled) void HandleWndProcMessage(ref WindowsHook.MESSAGE winMsg, ref bool handled)
{ {
// this handles the message from a typical WndProc message loop and check if it's from the TWAIN source. // this handles the message from a typical WndProc message loop and check if it's from the TWAIN source.
@ -621,7 +632,7 @@ namespace NTwain
evt.pEvent = msgPtr; evt.pEvent = msgPtr;
if (handled = (DGControl.Event.ProcessEvent(evt) == ReturnCode.DSEvent)) if (handled = (DGControl.Event.ProcessEvent(evt) == ReturnCode.DSEvent))
{ {
Debug.WriteLine(string.Format("Thread {0}: HandleWndProcMessage at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, evt.TWMessage)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: HandleWndProcMessage at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, evt.TWMessage));
HandleSourceMsg(evt.TWMessage); HandleSourceMsg(evt.TWMessage);
} }
@ -637,7 +648,7 @@ namespace NTwain
{ {
if (origin != null && SourceId != null && origin.Id == SourceId.Id) if (origin != null && SourceId != null && origin.Id == SourceId.Id)
{ {
Debug.WriteLine(string.Format("Thread {0}: CallbackHandler at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, msg)); Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: CallbackHandler at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, msg));
// spec says we must handle this on the thread that enabled the DS. // spec says we must handle this on the thread that enabled the DS.
// by using the internal dispatcher this will be the case. // by using the internal dispatcher this will be the case.
@ -660,7 +671,7 @@ namespace NTwain
{ {
State = 6; State = 6;
} }
DoTransferRoutine(); TransferLogic.DoTransferRoutine(this);
break; break;
case Message.DeviceEvent: case Message.DeviceEvent:
TWDeviceEvent de; TWDeviceEvent de;
@ -683,530 +694,12 @@ namespace NTwain
else if (State == 5) else if (State == 5)
{ {
// needs this state check since some source sends this more than once // needs this state check since some source sends this more than once
DisableSource(); ((ITwainSessionInternal)this).DisableSource();
} }
break; break;
} }
} }
/// <summary>
/// Performs the TWAIN transfer routine at state 6.
/// </summary>
protected virtual void DoTransferRoutine()
{
var pending = new TWPendingXfers();
var rc = ReturnCode.Success;
do
{
#region build and raise xfer ready
TWAudioInfo audInfo;
if (DGAudio.AudioInfo.Get(out audInfo) != ReturnCode.Success)
{
audInfo = null;
}
TWImageInfo imgInfo;
if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
// ask consumer for xfer details
var preXferArgs = new TransferReadyEventArgs
{
AudioInfo = audInfo,
PendingImageInfo = imgInfo,
PendingTransferCount = pending.Count,
EndOfJob = pending.EndOfJob == 0
};
SafeSyncableRaiseOnEvent(OnTransferReady, TransferReady, preXferArgs);
#endregion
#region actually handle xfer
if (preXferArgs.CancelAll)
{
rc = DGControl.PendingXfers.Reset(pending);
}
else if (!preXferArgs.CancelCurrent)
{
DataGroups xferGroup = DataGroups.None;
if (DGControl.XferGroup.Get(ref xferGroup) != ReturnCode.Success)
{
xferGroup = DataGroups.None;
}
if ((xferGroup & DataGroups.Image) == DataGroups.Image)
{
var mech = this.GetCurrentCap(CapabilityId.ICapXferMech).ConvertToEnum<XferMech>();
switch (mech)
{
case XferMech.Native:
DoImageNativeXfer();
break;
case XferMech.Memory:
DoImageMemoryXfer();
break;
case XferMech.File:
DoImageFileXfer();
break;
case XferMech.MemFile:
DoImageMemoryFileXfer();
break;
}
}
if ((xferGroup & DataGroups.Audio) == DataGroups.Audio)
{
var mech = this.GetCurrentCap(CapabilityId.ACapXferMech).ConvertToEnum<XferMech>();
switch (mech)
{
case XferMech.Native:
DoAudioNativeXfer();
break;
case XferMech.File:
DoAudioFileXfer();
break;
}
}
}
rc = DGControl.PendingXfers.EndXfer(pending);
#endregion
} while (rc == ReturnCode.Success && pending.Count != 0);
State = 5;
DisableSource();
}
#region audio xfers
private void DoAudioNativeXfer()
{
IntPtr dataPtr = IntPtr.Zero;
IntPtr lockedPtr = IntPtr.Zero;
try
{
var xrc = DGAudio.AudioNativeXfer.Get(ref dataPtr);
if (xrc == ReturnCode.XferDone)
{
State = 7;
if (dataPtr != IntPtr.Zero)
{
lockedPtr = Platform.MemoryManager.Lock(dataPtr);
}
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs { NativeData = lockedPtr });
}
else
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
}
}
catch (Exception ex)
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { Exception = ex });
}
finally
{
State = 6;
// data here is allocated by source so needs to use shared mem calls
if (lockedPtr != IntPtr.Zero)
{
Platform.MemoryManager.Unlock(lockedPtr);
lockedPtr = IntPtr.Zero;
}
if (dataPtr != IntPtr.Zero)
{
Platform.MemoryManager.Free(dataPtr);
dataPtr = IntPtr.Zero;
}
}
}
private void DoAudioFileXfer()
{
string filePath = null;
TWSetupFileXfer setupInfo;
if (DGControl.SetupFileXfer.Get(out setupInfo) == ReturnCode.Success)
{
filePath = setupInfo.FileName;
}
var xrc = DGAudio.AudioFileXfer.Get();
if (xrc == ReturnCode.XferDone)
{
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs { FileDataPath = filePath });
}
else
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
}
}
#endregion
#region image xfers
private void DoImageNativeXfer()
{
IntPtr dataPtr = IntPtr.Zero;
IntPtr lockedPtr = IntPtr.Zero;
try
{
var xrc = DGImage.ImageNativeXfer.Get(ref dataPtr);
if (xrc == ReturnCode.XferDone)
{
State = 7;
TWImageInfo imgInfo;
TWExtImageInfo extInfo = null;
if (SupportedCaps.Contains(CapabilityId.ICapExtImageInfo))
{
if (DGImage.ExtImageInfo.Get(out extInfo) != ReturnCode.Success)
{
extInfo = null;
}
}
if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
if (dataPtr != IntPtr.Zero)
{
lockedPtr = Platform.MemoryManager.Lock(dataPtr);
}
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs
{
NativeData = lockedPtr,
ImageInfo = imgInfo,
ExImageInfo = extInfo
});
if (extInfo != null) { extInfo.Dispose(); }
}
else
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
}
}
catch (Exception ex)
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { Exception = ex });
}
finally
{
State = 6;
// data here is allocated by source so needs to use shared mem calls
if (lockedPtr != IntPtr.Zero)
{
Platform.MemoryManager.Unlock(lockedPtr);
lockedPtr = IntPtr.Zero;
}
if (dataPtr != IntPtr.Zero)
{
Platform.MemoryManager.Free(dataPtr);
dataPtr = IntPtr.Zero;
}
}
}
private void DoImageFileXfer()
{
string filePath = null;
TWSetupFileXfer setupInfo;
if (DGControl.SetupFileXfer.Get(out setupInfo) == ReturnCode.Success)
{
filePath = setupInfo.FileName;
}
var xrc = DGImage.ImageFileXfer.Get();
if (xrc == ReturnCode.XferDone)
{
TWImageInfo imgInfo;
TWExtImageInfo extInfo = null;
if (SupportedCaps.Contains(CapabilityId.ICapExtImageInfo))
{
if (DGImage.ExtImageInfo.Get(out extInfo) != ReturnCode.Success)
{
extInfo = null;
}
}
if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs
{
FileDataPath = filePath,
ImageInfo = imgInfo,
ExImageInfo = extInfo
});
if (extInfo != null) { extInfo.Dispose(); }
}
else
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
}
}
private void DoImageMemoryXfer()
{
TWSetupMemXfer memInfo;
if (DGControl.SetupMemXfer.Get(out memInfo) == ReturnCode.Success)
{
TWImageMemXfer xferInfo = new TWImageMemXfer();
try
{
// how to tell if going to xfer in strip vs tile?
// if tile don't allocate memory in app?
xferInfo.Memory = new TWMemory
{
Flags = MemoryFlags.AppOwns | MemoryFlags.Pointer,
Length = memInfo.Preferred,
TheMem = Platform.MemoryManager.Allocate(memInfo.Preferred)
};
// do the unthinkable and keep all xferred batches in memory,
// possibly defeating the purpose of mem xfer
// unless compression is used.
// todo: use array instead of memory stream?
using (MemoryStream xferredData = new MemoryStream())
{
var xrc = ReturnCode.Success;
do
{
xrc = DGImage.ImageMemFileXfer.Get(xferInfo);
if (xrc == ReturnCode.Success ||
xrc == ReturnCode.XferDone)
{
State = 7;
// optimize and allocate buffer only once instead of inside the loop?
byte[] buffer = new byte[(int)xferInfo.BytesWritten];
IntPtr lockPtr = IntPtr.Zero;
try
{
lockPtr = Platform.MemoryManager.Lock(xferInfo.Memory.TheMem);
Marshal.Copy(lockPtr, buffer, 0, buffer.Length);
xferredData.Write(buffer, 0, buffer.Length);
}
finally
{
if (lockPtr != IntPtr.Zero)
{
Platform.MemoryManager.Unlock(lockPtr);
}
}
}
} while (xrc == ReturnCode.Success);
if (xrc == ReturnCode.XferDone)
{
TWImageInfo imgInfo;
TWExtImageInfo extInfo = null;
if (SupportedCaps.Contains(CapabilityId.ICapExtImageInfo))
{
if (DGImage.ExtImageInfo.Get(out extInfo) != ReturnCode.Success)
{
extInfo = null;
}
}
if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs
{
MemData = xferredData.ToArray(),
ImageInfo = imgInfo,
ExImageInfo = extInfo
});
if (extInfo != null) { extInfo.Dispose(); }
}
else
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
}
}
}
catch (Exception ex)
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { Exception = ex });
}
finally
{
State = 6;
if (xferInfo.Memory.TheMem != IntPtr.Zero)
{
Platform.MemoryManager.Free(xferInfo.Memory.TheMem);
}
}
}
}
private void DoImageMemoryFileXfer()
{
// since it's memory-file xfer need info from both (maybe)
TWSetupMemXfer memInfo;
TWSetupFileXfer fileInfo;
if (DGControl.SetupMemXfer.Get(out memInfo) == ReturnCode.Success &&
DGControl.SetupFileXfer.Get(out fileInfo) == ReturnCode.Success)
{
TWImageMemXfer xferInfo = new TWImageMemXfer();
var tempFile = Path.GetTempFileName();
string finalFile = null;
try
{
// no strip or tile here, just chunks
xferInfo.Memory = new TWMemory
{
Flags = MemoryFlags.AppOwns | MemoryFlags.Pointer,
Length = memInfo.Preferred,
TheMem = Platform.MemoryManager.Allocate(memInfo.Preferred)
};
var xrc = ReturnCode.Success;
using (var outStream = File.OpenWrite(tempFile))
{
do
{
xrc = DGImage.ImageMemFileXfer.Get(xferInfo);
if (xrc == ReturnCode.Success ||
xrc == ReturnCode.XferDone)
{
State = 7;
byte[] buffer = new byte[(int)xferInfo.BytesWritten];
IntPtr lockPtr = IntPtr.Zero;
try
{
lockPtr = Platform.MemoryManager.Lock(xferInfo.Memory.TheMem);
Marshal.Copy(lockPtr, buffer, 0, buffer.Length);
}
finally
{
if (lockPtr != IntPtr.Zero)
{
Platform.MemoryManager.Unlock(lockPtr);
}
}
outStream.Write(buffer, 0, buffer.Length);
}
} while (xrc == ReturnCode.Success);
}
if (xrc == ReturnCode.XferDone)
{
switch (fileInfo.Format)
{
case FileFormat.Bmp:
finalFile = Path.ChangeExtension(tempFile, ".bmp");
break;
case FileFormat.Dejavu:
finalFile = Path.ChangeExtension(tempFile, ".dejavu");
break;
case FileFormat.Exif:
finalFile = Path.ChangeExtension(tempFile, ".exit");
break;
case FileFormat.Fpx:
finalFile = Path.ChangeExtension(tempFile, ".fpx");
break;
case FileFormat.Jfif:
finalFile = Path.ChangeExtension(tempFile, ".jpg");
break;
case FileFormat.Jp2:
finalFile = Path.ChangeExtension(tempFile, ".jp2");
break;
case FileFormat.Jpx:
finalFile = Path.ChangeExtension(tempFile, ".jpx");
break;
case FileFormat.Pdf:
case FileFormat.PdfA:
case FileFormat.PdfA2:
finalFile = Path.ChangeExtension(tempFile, ".pdf");
break;
case FileFormat.Pict:
finalFile = Path.ChangeExtension(tempFile, ".pict");
break;
case FileFormat.Png:
finalFile = Path.ChangeExtension(tempFile, ".png");
break;
case FileFormat.Spiff:
finalFile = Path.ChangeExtension(tempFile, ".spiff");
break;
case FileFormat.Tiff:
case FileFormat.TiffMulti:
finalFile = Path.ChangeExtension(tempFile, ".tif");
break;
case FileFormat.Xbm:
finalFile = Path.ChangeExtension(tempFile, ".xbm");
break;
default:
finalFile = Path.ChangeExtension(tempFile, ".unknown");
break;
}
File.Move(tempFile, finalFile);
}
else
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
}
}
catch (Exception ex)
{
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { Exception = ex });
}
finally
{
State = 6;
if (xferInfo.Memory.TheMem != IntPtr.Zero)
{
Platform.MemoryManager.Free(xferInfo.Memory.TheMem);
}
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
}
if (File.Exists(finalFile))
{
TWImageInfo imgInfo;
TWExtImageInfo extInfo = null;
if (SupportedCaps.Contains(CapabilityId.ICapExtImageInfo))
{
if (DGImage.ExtImageInfo.Get(out extInfo) != ReturnCode.Success)
{
extInfo = null;
}
}
if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs
{
FileDataPath = finalFile,
ImageInfo = imgInfo,
ExImageInfo = extInfo
});
if (extInfo != null) { extInfo.Dispose(); }
}
}
}
#endregion
#endregion #endregion
} }
} }

View File

@ -15,7 +15,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static TWStatus GetManagerStatus(this TwainSession session) public static TWStatus GetManagerStatus(this ITwainOperation session)
{ {
TWStatus stat; TWStatus stat;
session.DGControl.Status.GetManager(out stat); session.DGControl.Status.GetManager(out stat);
@ -26,7 +26,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static TWStatus GetSourceStatus(this TwainSession session) public static TWStatus GetSourceStatus(this ITwainOperation session)
{ {
TWStatus stat; TWStatus stat;
session.DGControl.Status.GetSource(out stat); session.DGControl.Status.GetSource(out stat);
@ -39,7 +39,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<TWIdentity> GetSources(this TwainSession session) public static IList<TWIdentity> GetSources(this ITwainOperation session)
{ {
List<TWIdentity> list = new List<TWIdentity>(); List<TWIdentity> list = new List<TWIdentity>();
@ -67,7 +67,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="capId">The cap id.</param> /// <param name="capId">The cap id.</param>
/// <returns></returns> /// <returns></returns>
public static object GetCurrentCap(this TwainSession session, CapabilityId capId) public static object GetCurrentCap(this ITwainOperation session, CapabilityId capId)
{ {
using (TWCapability cap = new TWCapability(capId)) using (TWCapability cap = new TWCapability(capId))
{ {
@ -147,7 +147,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="capabilityId">The capability unique identifier.</param> /// <param name="capabilityId">The capability unique identifier.</param>
/// <returns></returns> /// <returns></returns>
public static IList<object> GetCapabilityValues(this TwainSession session, CapabilityId capabilityId) public static IList<object> GetCapabilityValues(this ITwainOperation session, CapabilityId capabilityId)
{ {
var list = new List<object>(); var list = new List<object>();
using (TWCapability cap = new TWCapability(capabilityId)) using (TWCapability cap = new TWCapability(capabilityId))
@ -167,7 +167,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
internal static IList<CapabilityId> GetCapabilities(this TwainSession session) internal static IList<CapabilityId> GetCapabilities(this ITwainOperation session)
{ {
return session.GetCapabilityValues(CapabilityId.CapSupportedCaps).CastToEnum<CapabilityId>(false); return session.GetCapabilityValues(CapabilityId.CapSupportedCaps).CastToEnum<CapabilityId>(false);
} }
@ -180,7 +180,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<XferMech> CapGetImageXferMech(this TwainSession session) public static IList<XferMech> CapGetImageXferMech(this ITwainOperation session)
{ {
return session.GetCapabilityValues(CapabilityId.ICapXferMech).CastToEnum<XferMech>(true); return session.GetCapabilityValues(CapabilityId.ICapXferMech).CastToEnum<XferMech>(true);
} }
@ -195,7 +195,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<CompressionType> CapGetCompression(this TwainSession session) public static IList<CompressionType> CapGetCompression(this ITwainOperation session)
{ {
return session.GetCapabilityValues(CapabilityId.ICapCompression).CastToEnum<CompressionType>(true); return session.GetCapabilityValues(CapabilityId.ICapCompression).CastToEnum<CompressionType>(true);
} }
@ -206,7 +206,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="compression">The compression.</param> /// <param name="compression">The compression.</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetImageCompression(this TwainSession session, CompressionType compression) public static ReturnCode CapSetImageCompression(this ITwainOperation session, CompressionType compression)
{ {
using (TWCapability compressCap = new TWCapability(CapabilityId.ICapCompression, new TWOneValue { Item = (uint)compression, ItemType = ItemType.UInt16 })) using (TWCapability compressCap = new TWCapability(CapabilityId.ICapCompression, new TWOneValue { Item = (uint)compression, ItemType = ItemType.UInt16 }))
{ {
@ -224,7 +224,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<FileFormat> CapGetImageFileFormat(this TwainSession session) public static IList<FileFormat> CapGetImageFileFormat(this ITwainOperation session)
{ {
return session.GetCapabilityValues(CapabilityId.ICapImageFileFormat).CastToEnum<FileFormat>(true); return session.GetCapabilityValues(CapabilityId.ICapImageFileFormat).CastToEnum<FileFormat>(true);
} }
@ -235,7 +235,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="format">The format.</param> /// <param name="format">The format.</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetImageFormat(this TwainSession session, FileFormat format) public static ReturnCode CapSetImageFormat(this ITwainOperation session, FileFormat format)
{ {
using (TWCapability formatCap = new TWCapability(CapabilityId.ICapImageFileFormat, new TWOneValue { Item = (uint)format, ItemType = ItemType.UInt16 })) using (TWCapability formatCap = new TWCapability(CapabilityId.ICapImageFileFormat, new TWOneValue { Item = (uint)format, ItemType = ItemType.UInt16 }))
{ {
@ -253,7 +253,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<PixelType> CapGetPixelTypes(this TwainSession session) public static IList<PixelType> CapGetPixelTypes(this ITwainOperation session)
{ {
return session.GetCapabilityValues(CapabilityId.ICapPixelType).CastToEnum<PixelType>(true); return session.GetCapabilityValues(CapabilityId.ICapPixelType).CastToEnum<PixelType>(true);
} }
@ -264,7 +264,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetPixelType(this TwainSession session, PixelType type) public static ReturnCode CapSetPixelType(this ITwainOperation session, PixelType type)
{ {
var one = new TWOneValue(); var one = new TWOneValue();
one.Item = (uint)type; one.Item = (uint)type;
@ -285,7 +285,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<XferMech> CapGetImageXferMechs(this TwainSession session) public static IList<XferMech> CapGetImageXferMechs(this ITwainOperation session)
{ {
return session.GetCapabilityValues(CapabilityId.ICapXferMech).CastToEnum<XferMech>(true); return session.GetCapabilityValues(CapabilityId.ICapXferMech).CastToEnum<XferMech>(true);
} }
@ -296,7 +296,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<XferMech> CapGetAudioXferMechs(this TwainSession session) public static IList<XferMech> CapGetAudioXferMechs(this ITwainOperation session)
{ {
return session.GetCapabilityValues(CapabilityId.ACapXferMech).CastToEnum<XferMech>(true); return session.GetCapabilityValues(CapabilityId.ACapXferMech).CastToEnum<XferMech>(true);
} }
@ -307,7 +307,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetImageXferMech(this TwainSession session, XferMech type) public static ReturnCode CapSetImageXferMech(this ITwainOperation session, XferMech type)
{ {
var one = new TWOneValue(); var one = new TWOneValue();
one.Item = (uint)type; one.Item = (uint)type;
@ -324,7 +324,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetAudioXferMech(this TwainSession session, XferMech type) public static ReturnCode CapSetAudioXferMech(this ITwainOperation session, XferMech type)
{ {
var one = new TWOneValue(); var one = new TWOneValue();
one.Item = (uint)type; one.Item = (uint)type;
@ -345,7 +345,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<TWFix32> CapGetDPIs(this TwainSession session) public static IList<TWFix32> CapGetDPIs(this ITwainOperation session)
{ {
var list = session.GetCapabilityValues(CapabilityId.ICapXResolution); var list = session.GetCapabilityValues(CapabilityId.ICapXResolution);
return list.Select(o => o.ConvertToFix32()).ToList(); return list.Select(o => o.ConvertToFix32()).ToList();
@ -357,7 +357,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="dpi">The DPI.</param> /// <param name="dpi">The DPI.</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetDPI(this TwainSession session, TWFix32 dpi) public static ReturnCode CapSetDPI(this ITwainOperation session, TWFix32 dpi)
{ {
return CapSetDPI(session, dpi, dpi); return CapSetDPI(session, dpi, dpi);
} }
@ -369,7 +369,7 @@ namespace NTwain
/// <param name="xDPI">The x DPI.</param> /// <param name="xDPI">The x DPI.</param>
/// <param name="yDPI">The y DPI.</param> /// <param name="yDPI">The y DPI.</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetDPI(this TwainSession session, TWFix32 xDPI, TWFix32 yDPI) public static ReturnCode CapSetDPI(this ITwainOperation session, TWFix32 xDPI, TWFix32 yDPI)
{ {
TWOneValue one = new TWOneValue(); TWOneValue one = new TWOneValue();
one.Item = (uint)xDPI;// ((uint)dpi) << 16; one.Item = (uint)xDPI;// ((uint)dpi) << 16;
@ -400,7 +400,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <returns></returns> /// <returns></returns>
public static IList<SupportedSize> CapGetSupportedSizes(this TwainSession session) public static IList<SupportedSize> CapGetSupportedSizes(this ITwainOperation session)
{ {
return session.GetCapabilityValues(CapabilityId.ICapSupportedSizes).CastToEnum<SupportedSize>(true); return session.GetCapabilityValues(CapabilityId.ICapSupportedSizes).CastToEnum<SupportedSize>(true);
} }
@ -411,7 +411,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="size">The size.</param> /// <param name="size">The size.</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetSupportedSize(this TwainSession session, SupportedSize size) public static ReturnCode CapSetSupportedSize(this ITwainOperation session, SupportedSize size)
{ {
var one = new TWOneValue(); var one = new TWOneValue();
one.Item = (uint)size; one.Item = (uint)size;
@ -474,7 +474,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="useIt">if set to <c>true</c> [use it].</param> /// <param name="useIt">if set to <c>true</c> [use it].</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetAutoRotate(this TwainSession session, bool useIt) public static ReturnCode CapSetAutoRotate(this ITwainSession session, bool useIt)
{ {
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
if (session.SupportedCaps.Contains(CapabilityId.ICapAutomaticRotate)) if (session.SupportedCaps.Contains(CapabilityId.ICapAutomaticRotate))
@ -512,7 +512,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="useIt">if set to <c>true</c> [use it].</param> /// <param name="useIt">if set to <c>true</c> [use it].</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetBorderDetection(this TwainSession session, bool useIt) public static ReturnCode CapSetBorderDetection(this ITwainSession session, bool useIt)
{ {
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
if (session.SupportedCaps.Contains(CapabilityId.ICapAutomaticBorderDetection)) if (session.SupportedCaps.Contains(CapabilityId.ICapAutomaticBorderDetection))
@ -560,7 +560,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="useIt">if set to <c>true</c> [use it].</param> /// <param name="useIt">if set to <c>true</c> [use it].</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetDuplex(this TwainSession session, bool useIt) public static ReturnCode CapSetDuplex(this ITwainSession session, bool useIt)
{ {
if (session.SourceId.ProtocolMajor >= 2) if (session.SourceId.ProtocolMajor >= 2)
{ {
@ -594,7 +594,7 @@ namespace NTwain
/// <param name="session">The session.</param> /// <param name="session">The session.</param>
/// <param name="useIt">if set to <c>true</c> [use it].</param> /// <param name="useIt">if set to <c>true</c> [use it].</param>
/// <returns></returns> /// <returns></returns>
public static ReturnCode CapSetFeeder(this TwainSession session, bool useIt) public static ReturnCode CapSetFeeder(this ITwainSession session, bool useIt)
{ {
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
if (session.SupportedCaps.Contains(CapabilityId.CapFeederEnabled)) if (session.SupportedCaps.Contains(CapabilityId.CapFeederEnabled))

View File

@ -12,7 +12,7 @@ namespace NTwain.Tests
[ExpectedException(typeof(TwainStateException), "State check failed to throw.")] [ExpectedException(typeof(TwainStateException), "State check failed to throw.")]
public void VerifyState_Throws_When_State_Is_Enforced() public void VerifyState_Throws_When_State_Is_Enforced()
{ {
ITwainStateInternal session = new TwainSession(TWIdentity.Create(DataGroups.Image, new Version(1, 0), "test", "test", "test", "test")); ITwainSessionInternal session = new TwainSession(TWIdentity.Create(DataGroups.Image, new Version(1, 0), "test", "test", "test", "test"));
session.EnforceState = true; session.EnforceState = true;
session.ChangeState(4, false); session.ChangeState(4, false);
@ -22,7 +22,7 @@ namespace NTwain.Tests
[TestMethod] [TestMethod]
public void VerifyState_No_Throws_When_State_Is_Not_Enforced() public void VerifyState_No_Throws_When_State_Is_Not_Enforced()
{ {
ITwainStateInternal session = new TwainSession(TWIdentity.Create(DataGroups.Image, new Version(1, 0), "test", "test", "test", "test")); ITwainSessionInternal session = new TwainSession(TWIdentity.Create(DataGroups.Image, new Version(1, 0), "test", "test", "test", "test"));
session.EnforceState = false; session.EnforceState = false;
session.ChangeState(4, false); session.ChangeState(4, false);