mirror of
https://github.com/soukoku/ntwain.git
synced 2025-04-05 20:59:23 +08:00
Ported old native image xfer with shared buffer test.
This commit is contained in:
parent
242e3eba15
commit
20df6fc74c
22
samples/WinForm32/ControlExtensions.cs
Normal file
22
samples/WinForm32/ControlExtensions.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WinFormSample
|
||||
{
|
||||
static class ControlExtensions
|
||||
{
|
||||
public static void SetDoubleBuffered(this Control control, bool value)
|
||||
{
|
||||
if (SystemInformation.TerminalServerSession) return;
|
||||
|
||||
var dbprop = control.GetType().GetProperty("DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
dbprop!.SetValue(control, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -25,18 +25,33 @@ namespace WinFormSample
|
||||
twain.StateChanged += Twain_StateChanged;
|
||||
twain.DefaultSourceChanged += Twain_DefaultSourceChanged;
|
||||
twain.CurrentSourceChanged += Twain_CurrentSourceChanged;
|
||||
twain.TransferReady += Twain_TransferReady;
|
||||
twain.DataTransferred += Twain_DataTransferred;
|
||||
twain.TransferError += Twain_TransferError;
|
||||
twain.DeviceEvent += Twain_DeviceEvent;
|
||||
|
||||
SetDoubleBuffered(capListView);
|
||||
capListView.SetDoubleBuffered(true);
|
||||
|
||||
this.Disposed += Form1_Disposed;
|
||||
}
|
||||
|
||||
static void SetDoubleBuffered(Control control)
|
||||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
if (SystemInformation.TerminalServerSession) return;
|
||||
base.OnHandleCreated(e);
|
||||
|
||||
var dbprop = control.GetType().GetProperty(nameof(DoubleBuffered), BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
dbprop!.SetValue(control, true);
|
||||
|
||||
var hwnd = this.Handle;
|
||||
var rc = twain.OpenDSM(hwnd);
|
||||
twain.AddWinformFilter();
|
||||
Debug.WriteLine($"OpenDSM={rc}");
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
var finalState = twain.TryStepdown(STATE.S2);
|
||||
Debug.WriteLine($"Stepdown result state={finalState}");
|
||||
twain.RemoveWinformFilter();
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void Form1_Disposed(object? sender, EventArgs e)
|
||||
@ -44,7 +59,38 @@ namespace WinFormSample
|
||||
twain.Dispose();
|
||||
}
|
||||
|
||||
private void Twain_CurrentSourceChanged(TwainAppSession arg1, TW_IDENTITY_LEGACY ds)
|
||||
|
||||
private void Twain_DeviceEvent(TwainAppSession sender, TW_DEVICEEVENT e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void Twain_TransferError(TwainAppSession sender, TransferErrorEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void Twain_DataTransferred(TwainAppSession sender, DataTransferredEventArgs e)
|
||||
{
|
||||
Debug.WriteLine($"Image transferred with info {e.ImageInfo}");
|
||||
}
|
||||
|
||||
private void Twain_TransferReady(TwainAppSession sender, TransferReadyEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void Twain_DefaultSourceChanged(TwainAppSession sender, TW_IDENTITY_LEGACY ds)
|
||||
{
|
||||
lblDefault.Text = ds.ProductName;
|
||||
}
|
||||
|
||||
private void Twain_StateChanged(TwainAppSession sender, STATE state)
|
||||
{
|
||||
Invoke(()=> lblState.Text = state.ToString());
|
||||
}
|
||||
|
||||
private void Twain_CurrentSourceChanged(TwainAppSession sender, TW_IDENTITY_LEGACY ds)
|
||||
{
|
||||
lblCurrent.Text = ds.ProductName;
|
||||
if (twain.State == STATE.S4)
|
||||
@ -170,35 +216,6 @@ namespace WinFormSample
|
||||
return "";
|
||||
}
|
||||
|
||||
private void Twain_DefaultSourceChanged(TwainAppSession arg1, TW_IDENTITY_LEGACY ds)
|
||||
{
|
||||
lblDefault.Text = ds.ProductName;
|
||||
}
|
||||
|
||||
private void Twain_StateChanged(TwainAppSession session, STATE state)
|
||||
{
|
||||
lblState.Text = state.ToString();
|
||||
}
|
||||
|
||||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
base.OnHandleCreated(e);
|
||||
|
||||
|
||||
var hwnd = this.Handle;
|
||||
var rc = twain.OpenDSM(hwnd);
|
||||
twain.AddWinformFilter();
|
||||
Debug.WriteLine($"OpenDSM={rc}");
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
var finalState = twain.TryStepdown(STATE.S2);
|
||||
Debug.WriteLine($"Stepdown result state={finalState}");
|
||||
twain.RemoveWinformFilter();
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void btnSelect_Click(object sender, EventArgs e)
|
||||
{
|
||||
twain.ShowUserSelect();
|
||||
|
@ -2193,7 +2193,7 @@ namespace NTwain.Data
|
||||
/// Describes the “real” image data, that is, the complete image being transferred between the Source and application.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
public struct TW_IMAGEINFO
|
||||
public partial struct TW_IMAGEINFO
|
||||
{
|
||||
public TW_FIX32 XResolution;
|
||||
public TW_FIX32 YResolution;
|
||||
@ -2209,9 +2209,9 @@ namespace NTwain.Data
|
||||
public short BitsPerSample_6;
|
||||
public short BitsPerSample_7;
|
||||
public short BitsPerPixel;
|
||||
public ushort Planar;
|
||||
public short PixelType;
|
||||
public ushort Compression;
|
||||
public TW_BOOL Planar;
|
||||
public TWPT PixelType;
|
||||
public TWCP Compression;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
public struct TW_IMAGEINFO_LINUX64
|
||||
@ -2230,9 +2230,9 @@ namespace NTwain.Data
|
||||
public short BitsPerSample_6;
|
||||
public short BitsPerSample_7;
|
||||
public short BitsPerPixel;
|
||||
public ushort Planar;
|
||||
public short PixelType;
|
||||
public ushort Compression;
|
||||
public TW_BOOL Planar;
|
||||
public TWPT PixelType;
|
||||
public TWCP Compression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -754,6 +754,14 @@ namespace NTwain.Data
|
||||
}
|
||||
}
|
||||
|
||||
partial struct TW_IMAGEINFO
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ImageWidth}x{ImageLength} {PixelType} {Compression} {BitsPerPixel}bpp";
|
||||
}
|
||||
}
|
||||
|
||||
//partial struct TW_DEVICEEVENT
|
||||
//{
|
||||
// public TWDE Event { get { return (TWDE)_event; } }
|
||||
|
@ -1,46 +1,54 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using NTwain.Data;
|
||||
using System;
|
||||
|
||||
namespace NTwain
|
||||
{
|
||||
public class DataTransferredEventArgs : EventArgs, IDisposable
|
||||
public class DataTransferredEventArgs : EventArgs
|
||||
{
|
||||
readonly TwainAppSession _twain;
|
||||
readonly bool _isImage;
|
||||
|
||||
/// <summary>
|
||||
/// Ctor for pooled data and the pool to clean it up.
|
||||
/// Ctor for array data;
|
||||
/// </summary>
|
||||
/// <param name="pool"></param>
|
||||
/// <param name="twain"></param>
|
||||
/// <param name="data"></param>
|
||||
internal DataTransferredEventArgs(ArrayPool<byte>? pool, byte[]? data)
|
||||
internal DataTransferredEventArgs(TwainAppSession twain, byte[] data, bool isImage)
|
||||
{
|
||||
_pool = pool;
|
||||
this._twain = twain;
|
||||
Data = data;
|
||||
this._isImage = isImage;
|
||||
}
|
||||
|
||||
|
||||
bool _disposed;
|
||||
private readonly ArrayPool<byte>? _pool;
|
||||
|
||||
/// <summary>
|
||||
/// The complete file data if the transfer was done
|
||||
/// through memory. IMPORTANT: The data held
|
||||
/// in this array will no longer be valid once
|
||||
/// this event arg has been disposed.
|
||||
/// the event handler ends.
|
||||
/// </summary>
|
||||
public byte[]? Data { get; private set; }
|
||||
public byte[]? Data { get; }
|
||||
|
||||
|
||||
TW_IMAGEINFO? _imgInfo;
|
||||
|
||||
public void Dispose()
|
||||
/// <summary>
|
||||
/// Gets the final image information if applicable.
|
||||
/// </summary>
|
||||
public TW_IMAGEINFO? ImageInfo
|
||||
{
|
||||
if (!_disposed)
|
||||
get
|
||||
{
|
||||
if (_pool != null && Data != null)
|
||||
if (_isImage && _imgInfo == null)
|
||||
{
|
||||
_pool.Return(Data);
|
||||
Data = null;
|
||||
if (_twain.GetImageInfo(out TW_IMAGEINFO info).RC == TWRC.SUCCESS)
|
||||
{
|
||||
_imgInfo = info;
|
||||
}
|
||||
}
|
||||
_disposed = true;
|
||||
return _imgInfo;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
140
src/NTwain/Native/ImageTools.cs
Normal file
140
src/NTwain/Native/ImageTools.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NTwain.Native
|
||||
{
|
||||
static class ImageTools
|
||||
{
|
||||
// this is modified from twain cs sample
|
||||
// http://sourceforge.net/projects/twainforcsharp/?source=typ_redirect
|
||||
|
||||
public static bool IsDib(IntPtr data)
|
||||
{
|
||||
// a quick check not guaranteed correct,
|
||||
// compare first 2 bytes to size of struct (which is also the first field)
|
||||
var test = Marshal.ReadInt16(data);
|
||||
// should be 40
|
||||
return test == BITMAPINFOHEADER.GetByteSize();
|
||||
}
|
||||
public static bool IsTiff(IntPtr data)
|
||||
{
|
||||
var test = Marshal.ReadInt16(data);
|
||||
// should be II
|
||||
return test == 0x4949;
|
||||
}
|
||||
|
||||
|
||||
public static byte[]? GetBitmapData(System.Buffers.ArrayPool<byte> xferMemPool, IntPtr data)
|
||||
{
|
||||
var infoHeader = (BITMAPINFOHEADER)Marshal.PtrToStructure(data, typeof(BITMAPINFOHEADER));
|
||||
if (infoHeader.Validate())
|
||||
{
|
||||
var fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
||||
|
||||
|
||||
var fileHeader = new BITMAPFILEHEADER
|
||||
{
|
||||
bfType = 0x4D42, // "BM"
|
||||
bfOffBits = (uint)fileHeaderSize +
|
||||
infoHeader.biSize +
|
||||
(infoHeader.biClrUsed * 4)
|
||||
};
|
||||
fileHeader.bfSize = fileHeader.bfOffBits + infoHeader.biSizeImage;
|
||||
|
||||
var dataCopy = xferMemPool.Rent((int)fileHeader.bfSize);// new byte[fileHeader.bfSize];
|
||||
|
||||
// TODO: reduce extra alloc
|
||||
// write file header
|
||||
IntPtr tempPtr = Marshal.AllocHGlobal(fileHeaderSize);
|
||||
Marshal.StructureToPtr(fileHeader, tempPtr, true);
|
||||
Marshal.Copy(tempPtr, dataCopy, 0, fileHeaderSize);
|
||||
Marshal.FreeHGlobal(tempPtr);
|
||||
// write image
|
||||
Marshal.Copy(data, dataCopy, fileHeaderSize, (int)fileHeader.bfSize - fileHeaderSize);
|
||||
|
||||
return dataCopy;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[]? GetTiffData(System.Buffers.ArrayPool<byte> xferMemPool, IntPtr data)
|
||||
{
|
||||
// Find the size of the image so we can turn it into a memory stream...
|
||||
var headerSize = Marshal.SizeOf(typeof(TIFFHEADER));
|
||||
var tagSize = Marshal.SizeOf(typeof(TIFFTAG));
|
||||
var tiffSize = 0;
|
||||
var tagPtr = data.ToInt64() + headerSize;
|
||||
for (int i = 0; i < 999; i++)
|
||||
{
|
||||
tagPtr += (tagSize * i);
|
||||
var tag = (TIFFTAG)Marshal.PtrToStructure((IntPtr)tagPtr, typeof(TIFFTAG));
|
||||
|
||||
switch (tag.u16Tag)
|
||||
{
|
||||
case 273: // StripOffsets...
|
||||
case 279: // StripByteCounts...
|
||||
tiffSize += (int)tag.u32Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tiffSize > 0)
|
||||
{
|
||||
var dataCopy = xferMemPool.Rent(tiffSize);// new byte[tiffSize];
|
||||
// is this optimal?
|
||||
Marshal.Copy(data, dataCopy, 0, tiffSize);
|
||||
return dataCopy;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//internal static Bitmap ReadBitmapImage(IntPtr data)
|
||||
//{
|
||||
// Bitmap finalImg = null;
|
||||
// Bitmap tempImg = null;
|
||||
// try
|
||||
// {
|
||||
// var header = (BITMAPINFOHEADER)Marshal.PtrToStructure(data, typeof(BITMAPINFOHEADER));
|
||||
|
||||
// if (header.Validate())
|
||||
// {
|
||||
// PixelFormat format = header.GetDrawingPixelFormat();
|
||||
// tempImg = new Bitmap(header.biWidth, Math.Abs(header.biHeight), header.GetStride(), format, header.GetScan0(data));
|
||||
// ColorPalette pal = header.GetDrawingPalette(data);
|
||||
// if (pal != null)
|
||||
// {
|
||||
// tempImg.Palette = pal;
|
||||
// }
|
||||
// float xdpi = header.GetXDpi();
|
||||
// float ydpi = header.GetYDpi();
|
||||
// if (xdpi != 0 && ydpi == 0)
|
||||
// {
|
||||
// ydpi = xdpi;
|
||||
// }
|
||||
// else if (ydpi != 0 && xdpi == 0)
|
||||
// {
|
||||
// xdpi = ydpi;
|
||||
// }
|
||||
// if (xdpi != 0)
|
||||
// {
|
||||
// tempImg.SetResolution(xdpi, ydpi);
|
||||
// }
|
||||
// if (header.IsBottomUpImage)
|
||||
// {
|
||||
// tempImg.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
||||
// }
|
||||
// finalImg = tempImg;
|
||||
// tempImg = null;
|
||||
// }
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// if (tempImg != null)
|
||||
// {
|
||||
// tempImg.Dispose();
|
||||
// }
|
||||
// }
|
||||
// return finalImg;
|
||||
//}
|
||||
}
|
||||
}
|
@ -128,37 +128,37 @@ namespace NTwain
|
||||
/// Fires when <see cref="State"/> changes.
|
||||
/// This is not guaranteed to be raised on the UI thread.
|
||||
/// </summary>
|
||||
public event Action<TwainAppSession, STATE>? StateChanged;
|
||||
public event TwainEventDelegate<STATE>? StateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Fires when <see cref="DefaultSource"/> changes.
|
||||
/// </summary>
|
||||
public event Action<TwainAppSession, TW_IDENTITY_LEGACY>? DefaultSourceChanged;
|
||||
public event TwainEventDelegate<TW_IDENTITY_LEGACY>? DefaultSourceChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Fires when <see cref="CurrentSource"/> changes.
|
||||
/// </summary>
|
||||
public event Action<TwainAppSession, TW_IDENTITY_LEGACY>? CurrentSourceChanged;
|
||||
public event TwainEventDelegate<TW_IDENTITY_LEGACY>? CurrentSourceChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Fires when the source has some device event happening.
|
||||
/// </summary>
|
||||
public event Action<TwainAppSession, TW_DEVICEEVENT>? DeviceEvent;
|
||||
public event TwainEventDelegate<TW_DEVICEEVENT>? DeviceEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Fires when there's an error during transfer.
|
||||
/// </summary>
|
||||
public event EventHandler<TransferErrorEventArgs>? TransferError;
|
||||
public event TwainEventDelegate<TransferErrorEventArgs>? TransferError;
|
||||
|
||||
/// <summary>
|
||||
/// Fires when there's an upcoming transfer. App can inspect the image info
|
||||
/// and cancel if needed.
|
||||
/// </summary>
|
||||
public event EventHandler<TransferReadyEventArgs>? TransferReady;
|
||||
public event TwainEventDelegate<TransferReadyEventArgs>? TransferReady;
|
||||
|
||||
/// <summary>
|
||||
/// Fires when transferred data is available for app to use.
|
||||
/// </summary>
|
||||
public event EventHandler<DataTransferredEventArgs>? DataTransferred;
|
||||
public event TwainEventDelegate<DataTransferredEventArgs>? DataTransferred;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using NTwain.Data;
|
||||
using NTwain.Native;
|
||||
using NTwain.Triplets;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
@ -18,7 +19,7 @@ namespace NTwain
|
||||
// so the array max is made with 32 MB. Typical usage should be a lot less.
|
||||
static readonly ArrayPool<byte> XferMemPool = ArrayPool<byte>.Create(32 * 1024 * 1024, 8);
|
||||
|
||||
public STS GetImageInfo(out TW_IMAGEINFO info)
|
||||
internal STS GetImageInfo(out TW_IMAGEINFO info)
|
||||
{
|
||||
return WrapInSTS(DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out info));
|
||||
}
|
||||
@ -81,27 +82,30 @@ namespace NTwain
|
||||
}
|
||||
if (readyArgs.Cancel == CancelType.Graceful)
|
||||
{
|
||||
sts = WrapInSTS(DGControl.PendingXfers.StopFeeder(ref _appIdentity, ref _currentDS, ref pending));
|
||||
// ignore rc in this
|
||||
DGControl.PendingXfers.StopFeeder(ref _appIdentity, ref _currentDS, ref pending);
|
||||
}
|
||||
|
||||
if (readyArgs.Cancel != CancelType.SkipCurrent)
|
||||
if (readyArgs.Cancel != CancelType.SkipCurrent &&
|
||||
DataTransferred != null)
|
||||
{
|
||||
// transfer normally
|
||||
// transfer normally and only if someone's listening
|
||||
// to DataTransferred event
|
||||
if (xferImage)
|
||||
{
|
||||
switch (imgXferMech)
|
||||
{
|
||||
case TWSX.NATIVE:
|
||||
TransferNativeImage();
|
||||
sts = TransferNativeImage();
|
||||
break;
|
||||
case TWSX.FILE:
|
||||
TransferFileImage();
|
||||
sts = TransferFileImage();
|
||||
break;
|
||||
case TWSX.MEMORY:
|
||||
TransferMemoryImage();
|
||||
sts = TransferMemoryImage();
|
||||
break;
|
||||
case TWSX.MEMFILE:
|
||||
TransferMemoryFileImage();
|
||||
sts = TransferMemoryFileImage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -110,10 +114,10 @@ namespace NTwain
|
||||
switch (audXferMech)
|
||||
{
|
||||
case TWSX.NATIVE:
|
||||
TransferNativeAudio();
|
||||
sts = TransferNativeAudio();
|
||||
break;
|
||||
case TWSX.FILE:
|
||||
TransferFileAudio();
|
||||
sts = TransferFileAudio();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -138,40 +142,109 @@ namespace NTwain
|
||||
{
|
||||
HandleNonSuccessXferCode(sts);
|
||||
}
|
||||
_uiThreadMarshaller.BeginInvoke(() =>
|
||||
|
||||
//if (State > STATE.S5)
|
||||
//{
|
||||
//if (_closeDsRequested)
|
||||
//{
|
||||
_uiThreadMarshaller.BeginInvoke(() =>
|
||||
{
|
||||
DisableSource();
|
||||
});
|
||||
//}
|
||||
}
|
||||
|
||||
private STS TransferFileAudio()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
private STS TransferNativeAudio()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
private STS TransferMemoryFileImage()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
private STS TransferMemoryImage()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
private STS TransferFileImage()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
private STS TransferNativeImage()
|
||||
{
|
||||
IntPtr dataPtr = IntPtr.Zero;
|
||||
IntPtr lockedPtr = IntPtr.Zero;
|
||||
STS sts = default;
|
||||
try
|
||||
{
|
||||
DisableSource();
|
||||
});
|
||||
}
|
||||
sts = WrapInSTS(DGImage.ImageNativeXfer.Get(ref _appIdentity, ref _currentDS, out dataPtr));
|
||||
if (sts.RC == TWRC.XFERDONE)
|
||||
{
|
||||
State = STATE.S7;
|
||||
|
||||
private void TransferFileAudio()
|
||||
{
|
||||
lockedPtr = Lock(dataPtr);
|
||||
|
||||
}
|
||||
byte[]? data = null;
|
||||
|
||||
private void TransferNativeAudio()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void TransferMemoryFileImage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void TransferMemoryImage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void TransferFileImage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void TransferNativeImage()
|
||||
{
|
||||
if (ImageTools.IsDib(lockedPtr))
|
||||
{
|
||||
data = ImageTools.GetBitmapData(XferMemPool, lockedPtr);
|
||||
}
|
||||
else if (ImageTools.IsTiff(lockedPtr))
|
||||
{
|
||||
data = ImageTools.GetTiffData(XferMemPool, lockedPtr);
|
||||
}
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var args = new DataTransferredEventArgs(this, data, true);
|
||||
DataTransferred?.Invoke(this, args);
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
XferMemPool.Return(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleNonSuccessXferCode(sts);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
TransferError?.Invoke(this, new TransferErrorEventArgs(ex));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
finally
|
||||
{
|
||||
State = STATE.S6;
|
||||
if (lockedPtr != IntPtr.Zero)
|
||||
{
|
||||
Unlock(dataPtr);
|
||||
}
|
||||
if (dataPtr != IntPtr.Zero)
|
||||
{
|
||||
Free(dataPtr);
|
||||
}
|
||||
}
|
||||
return sts;
|
||||
}
|
||||
|
||||
private void HandleNonSuccessXferCode(STS sts)
|
||||
|
11
src/NTwain/TwainEventDelegate.cs
Normal file
11
src/NTwain/TwainEventDelegate.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace NTwain
|
||||
{
|
||||
/// <summary>
|
||||
/// General event delegate use by <see cref="TwainAppSession"/>.
|
||||
/// Better than basic object sender and requires EventArgs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventArgs"></typeparam>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate void TwainEventDelegate<TEventArgs>(TwainAppSession sender, TEventArgs e);
|
||||
}
|
Loading…
Reference in New Issue
Block a user