mirror of
https://github.com/soukoku/ntwain.git
synced 2026-02-25 13:04:07 +08:00
Expose wndproc hook method and test reset TW_PENDINGXFERS before use.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -12,94 +12,102 @@ using MSG = NTwain.Data.MSG;
|
|||||||
namespace NTwain
|
namespace NTwain
|
||||||
{
|
{
|
||||||
|
|
||||||
// contains parts for winform/wpf message loop integration
|
// contains parts for winform/wpf message loop integration
|
||||||
|
|
||||||
partial class TwainAppSession : IMessageFilter
|
partial class TwainAppSession : IMessageFilter
|
||||||
{
|
{
|
||||||
HwndSource? _wpfhook;
|
HwndSource? _wpfhook;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers this session for use in a Winform UI thread.
|
/// Registers this session for use in a Winform UI thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void AddWinformFilter()
|
public void AddWinformFilter()
|
||||||
{
|
|
||||||
Application.AddMessageFilter(this);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Unregisters this session if previously registered with <see cref="AddWinformFilter"/>.
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveWinformFilter()
|
|
||||||
{
|
|
||||||
Application.RemoveMessageFilter(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Registers this session for use in a WPF UI thread.
|
|
||||||
/// This requires the hwnd used in <see cref="OpenDSM"/>
|
|
||||||
/// be a valid WPF window handle.
|
|
||||||
/// </summary>
|
|
||||||
public void AddWpfHook()
|
|
||||||
{
|
|
||||||
if (_wpfhook == null)
|
|
||||||
{
|
|
||||||
_wpfhook = HwndSource.FromHwnd(_hwnd);
|
|
||||||
_wpfhook.AddHook(WpfHook);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Unregisters this session if previously registered with <see cref="AddWpfHook"/>.
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveWpfHook()
|
|
||||||
{
|
|
||||||
if (_wpfhook != null)
|
|
||||||
{
|
|
||||||
_wpfhook.RemoveHook(WpfHook);
|
|
||||||
_wpfhook = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IMessageFilter.PreFilterMessage(ref Message m)
|
|
||||||
{
|
|
||||||
return WndProc(m.HWnd, m.Msg, m.WParam, m.LParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
IntPtr WpfHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
|
||||||
{
|
|
||||||
handled = WndProc(hwnd, msg, wParam, lParam);
|
|
||||||
return IntPtr.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam)
|
|
||||||
{
|
|
||||||
// this handles the message from a typical WndProc message loop and checks if it's for the TWAIN source.
|
|
||||||
bool handled = false;
|
|
||||||
if (_state >= STATE.S5)
|
|
||||||
{
|
|
||||||
WIN_MESSAGE winMsg = new()
|
|
||||||
{
|
{
|
||||||
hwnd = hWnd,
|
Application.AddMessageFilter(this);
|
||||||
message = (uint)msg,
|
}
|
||||||
wParam = wParam,
|
/// <summary>
|
||||||
lParam = lParam
|
/// Unregisters this session if previously registered with <see cref="AddWinformFilter"/>.
|
||||||
};
|
/// </summary>
|
||||||
// no need to do another lock call when using marshal alloc
|
public void RemoveWinformFilter()
|
||||||
if (_procEvent.pEvent == IntPtr.Zero)
|
{
|
||||||
_procEvent.pEvent = Marshal.AllocHGlobal(Marshal.SizeOf(winMsg));
|
Application.RemoveMessageFilter(this);
|
||||||
Marshal.StructureToPtr(winMsg, _procEvent.pEvent, true);
|
}
|
||||||
|
|
||||||
if (!_closeDsRequested)
|
/// <summary>
|
||||||
{
|
/// Registers this session for use in a WPF UI thread.
|
||||||
var rc = DGControl.Event.ProcessEvent(ref _appIdentity, ref _currentDS, ref _procEvent);
|
/// This requires the hwnd used in <see cref="OpenDSM"/>
|
||||||
handled = rc == TWRC.DSEVENT;
|
/// be a valid WPF window handle.
|
||||||
if (_procEvent.TWMessage != 0 && (handled || rc == TWRC.NOTDSEVENT))
|
/// </summary>
|
||||||
{
|
public void AddWpfHook()
|
||||||
//Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] CheckIfTwainMessage at state {State} with MSG={_procEvent.TWMessage}.");
|
{
|
||||||
HandleSourceMsg((MSG)_procEvent.TWMessage);
|
if (_wpfhook == null)
|
||||||
}
|
{
|
||||||
|
_wpfhook = HwndSource.FromHwnd(_hwnd);
|
||||||
|
_wpfhook.AddHook(WpfHook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Unregisters this session if previously registered with <see cref="AddWpfHook"/>.
|
||||||
|
/// </summary>
|
||||||
|
public void RemoveWpfHook()
|
||||||
|
{
|
||||||
|
if (_wpfhook != null)
|
||||||
|
{
|
||||||
|
_wpfhook.RemoveHook(WpfHook);
|
||||||
|
_wpfhook = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IMessageFilter.PreFilterMessage(ref Message m)
|
||||||
|
{
|
||||||
|
return WndProc(m.HWnd, m.Msg, m.WParam, m.LParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntPtr WpfHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||||
|
{
|
||||||
|
handled = WndProc(hwnd, msg, wParam, lParam);
|
||||||
|
return IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method to check window message and handle it if it's for the TWAIN source.'
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWnd"></param>
|
||||||
|
/// <param name="msg"></param>
|
||||||
|
/// <param name="wParam"></param>
|
||||||
|
/// <param name="lParam"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
// this handles the message from a typical WndProc message loop and checks if it's for the TWAIN source.
|
||||||
|
bool handled = false;
|
||||||
|
if (_state >= STATE.S5)
|
||||||
|
{
|
||||||
|
WIN_MESSAGE winMsg = new()
|
||||||
|
{
|
||||||
|
hwnd = hWnd,
|
||||||
|
message = (uint)msg,
|
||||||
|
wParam = wParam,
|
||||||
|
lParam = lParam
|
||||||
|
};
|
||||||
|
// no need to do another lock call when using marshal alloc
|
||||||
|
if (_procEvent.pEvent == IntPtr.Zero)
|
||||||
|
_procEvent.pEvent = Marshal.AllocHGlobal(Marshal.SizeOf(winMsg));
|
||||||
|
Marshal.StructureToPtr(winMsg, _procEvent.pEvent, true);
|
||||||
|
|
||||||
|
if (!_closeDsRequested)
|
||||||
|
{
|
||||||
|
var rc = DGControl.Event.ProcessEvent(ref _appIdentity, ref _currentDS, ref _procEvent);
|
||||||
|
handled = rc == TWRC.DSEVENT;
|
||||||
|
if (_procEvent.TWMessage != 0 && (handled || rc == TWRC.NOTDSEVENT))
|
||||||
|
{
|
||||||
|
//Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] CheckIfTwainMessage at state {State} with MSG={_procEvent.TWMessage}.");
|
||||||
|
HandleSourceMsg((MSG)_procEvent.TWMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -8,521 +8,534 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace NTwain
|
namespace NTwain
|
||||||
{
|
{
|
||||||
// this file contains various xfer methods
|
// this file contains various xfer methods
|
||||||
|
|
||||||
partial class TwainAppSession
|
partial class TwainAppSession
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Can only be called in state 7, so it's hidden here and
|
|
||||||
/// only exposed in data transferred event.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="container"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal STS GetExtendedImageInfo(ref TW_EXTIMAGEINFO container)
|
|
||||||
{
|
{
|
||||||
return WrapInSTS(DGImage.ExtImageInfo.Get(ref _appIdentity, ref _currentDS, ref container));
|
/// <summary>
|
||||||
}
|
/// Can only be called in state 7, so it's hidden here and
|
||||||
|
/// only exposed in data transferred event.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="container"></param>
|
||||||
/// Start the transfer loop.
|
/// <returns></returns>
|
||||||
/// This should be called after receiving
|
internal STS GetExtendedImageInfo(ref TW_EXTIMAGEINFO container)
|
||||||
/// <see cref="MSG.XFERREADY"/> in the background thread.
|
|
||||||
/// </summary>
|
|
||||||
void EnterTransferRoutine()
|
|
||||||
{
|
|
||||||
// TODO: currently implemented routine doesn't quite work for audio as described in spec
|
|
||||||
|
|
||||||
|
|
||||||
// default options if source doesn't support changing them or whatever
|
|
||||||
bool xferImage = true;
|
|
||||||
bool xferAudio = false;
|
|
||||||
if (DGControl.XferGroup.Get(ref _appIdentity, ref _currentDS, out DG xferType) == TWRC.SUCCESS)
|
|
||||||
{
|
|
||||||
xferAudio = (xferType & DG.AUDIO) == DG.AUDIO;
|
|
||||||
var dsName = _currentDS.ProductName.ToString();
|
|
||||||
// check for Plustek OpticSlim 2680H, this scanner returns wrong xferGroup after first scanning
|
|
||||||
if (dsName.IndexOf("Plustek", StringComparison.OrdinalIgnoreCase) > -1 &&
|
|
||||||
dsName.IndexOf("OpticSlim", StringComparison.OrdinalIgnoreCase) > -1 &&
|
|
||||||
dsName.IndexOf("2680H", StringComparison.OrdinalIgnoreCase) > -1)
|
|
||||||
{
|
{
|
||||||
xferImage = true;
|
return WrapInSTS(DGImage.ExtImageInfo.Get(ref _appIdentity, ref _currentDS, ref container));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start the transfer loop.
|
||||||
|
/// This should be called after receiving
|
||||||
|
/// <see cref="MSG.XFERREADY"/> in the background thread.
|
||||||
|
/// </summary>
|
||||||
|
void EnterTransferRoutine()
|
||||||
{
|
{
|
||||||
// some DS end up getting none but we will assume it's image
|
// TODO: currently implemented routine doesn't quite work for audio as described in spec
|
||||||
xferImage = xferType == 0 || (xferType & DG.IMAGE) == DG.IMAGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var imgXferMech = TWSX.NATIVE;
|
|
||||||
var audXferMech = TWSX.NATIVE;
|
|
||||||
if (xferImage) imgXferMech = Caps.ICAP_XFERMECH.GetCurrent().FirstOrDefault();
|
|
||||||
else if (xferAudio) audXferMech = Caps.ACAP_XFERMECH.GetCurrent().FirstOrDefault();
|
|
||||||
|
|
||||||
TW_PENDINGXFERS pending = default;
|
// default options if source doesn't support changing them or whatever
|
||||||
var sts = WrapInSTS(DGControl.PendingXfers.Get(ref _appIdentity, ref _currentDS, ref pending));
|
bool xferImage = true;
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
bool xferAudio = false;
|
||||||
{
|
if (DGControl.XferGroup.Get(ref _appIdentity, ref _currentDS, out DG xferType) == TWRC.SUCCESS)
|
||||||
do
|
{
|
||||||
{
|
xferAudio = (xferType & DG.AUDIO) == DG.AUDIO;
|
||||||
var readyArgs = new TransferReadyEventArgs(pending.Count, (TWEJ)pending.EOJ);
|
var dsName = _currentDS.ProductName.ToString();
|
||||||
try
|
// check for Plustek OpticSlim 2680H, this scanner returns wrong xferGroup after first scanning
|
||||||
{
|
if (dsName.IndexOf("Plustek", StringComparison.OrdinalIgnoreCase) > -1 &&
|
||||||
TransferReady?.Invoke(this, readyArgs);
|
dsName.IndexOf("OpticSlim", StringComparison.OrdinalIgnoreCase) > -1 &&
|
||||||
}
|
dsName.IndexOf("2680H", StringComparison.OrdinalIgnoreCase) > -1)
|
||||||
catch { } // don't let consumer kill the loop if they have exception
|
{
|
||||||
|
xferImage = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// some DS end up getting none but we will assume it's image
|
||||||
|
xferImage = xferType == 0 || (xferType & DG.IMAGE) == DG.IMAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (readyArgs.Cancel == CancelType.EndNow || _closeDsRequested)
|
var imgXferMech = TWSX.NATIVE;
|
||||||
{
|
var audXferMech = TWSX.NATIVE;
|
||||||
// TODO: need to call EndXfer first?
|
if (xferImage) imgXferMech = Caps.ICAP_XFERMECH.GetCurrent().FirstOrDefault();
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending));
|
else if (xferAudio) audXferMech = Caps.ACAP_XFERMECH.GetCurrent().FirstOrDefault();
|
||||||
if (sts.RC == TWRC.SUCCESS && xferImage) State = STATE.S5;
|
|
||||||
}
|
TW_PENDINGXFERS pending = new TW_PENDINGXFERS();
|
||||||
else if (readyArgs.Cancel == CancelType.SkipCurrent)
|
var sts = WrapInSTS(DGControl.PendingXfers.Get(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
{
|
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
{
|
{
|
||||||
if (xferImage)
|
do
|
||||||
{
|
|
||||||
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
|
||||||
}
|
|
||||||
else if (xferAudio)
|
|
||||||
{
|
|
||||||
State = STATE.S6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (readyArgs.Cancel == CancelType.Graceful)
|
|
||||||
{
|
|
||||||
// ignore rc in this and continue transfer as normal
|
|
||||||
DGControl.PendingXfers.StopFeeder(ref _appIdentity, ref _currentDS, ref pending);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (readyArgs.Cancel != CancelType.SkipCurrent)
|
|
||||||
{
|
|
||||||
// transfer normally and only if someone's listening
|
|
||||||
// to DataTransferred event
|
|
||||||
if (xferImage)
|
|
||||||
{
|
{
|
||||||
switch (imgXferMech)
|
var readyArgs = new TransferReadyEventArgs(pending.Count, (TWEJ)pending.EOJ);
|
||||||
{
|
try
|
||||||
case TWSX.NATIVE:
|
{
|
||||||
sts = TransferNativeImage(ref pending);
|
TransferReady?.Invoke(this, readyArgs);
|
||||||
break;
|
}
|
||||||
case TWSX.FILE:
|
catch { } // don't let consumer kill the loop if they have exception
|
||||||
sts = TransferFileImage(ref pending);
|
|
||||||
break;
|
if (readyArgs.Cancel == CancelType.EndNow || _closeDsRequested)
|
||||||
case TWSX.MEMORY:
|
{
|
||||||
sts = TransferMemoryImage(ref pending);
|
// TODO: need to call EndXfer first?
|
||||||
break;
|
pending = new TW_PENDINGXFERS();
|
||||||
case TWSX.MEMFILE:
|
sts = WrapInSTS(DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
sts = TransferMemoryFileImage(ref pending);
|
if (sts.RC == TWRC.SUCCESS && xferImage) State = STATE.S5;
|
||||||
break;
|
}
|
||||||
}
|
else if (readyArgs.Cancel == CancelType.SkipCurrent)
|
||||||
}
|
{
|
||||||
else if (xferAudio)
|
pending = new TW_PENDINGXFERS();
|
||||||
{
|
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
switch (audXferMech)
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
{
|
{
|
||||||
case TWSX.NATIVE:
|
if (xferImage)
|
||||||
sts = TransferNativeAudio(ref pending);
|
{
|
||||||
break;
|
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
||||||
case TWSX.FILE:
|
}
|
||||||
sts = TransferFileAudio(ref pending);
|
else if (xferAudio)
|
||||||
break;
|
{
|
||||||
}
|
State = STATE.S6;
|
||||||
}
|
}
|
||||||
HandleXferCode(ref sts, ref pending);
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (readyArgs.Cancel == CancelType.Graceful)
|
||||||
|
{
|
||||||
|
// ignore rc in this and continue transfer as normal
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
DGControl.PendingXfers.StopFeeder(ref _appIdentity, ref _currentDS, ref pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (readyArgs.Cancel != CancelType.SkipCurrent)
|
||||||
|
{
|
||||||
|
// transfer normally and only if someone's listening
|
||||||
|
// to DataTransferred event
|
||||||
|
if (xferImage)
|
||||||
|
{
|
||||||
|
switch (imgXferMech)
|
||||||
|
{
|
||||||
|
case TWSX.NATIVE:
|
||||||
|
sts = TransferNativeImage(ref pending);
|
||||||
|
break;
|
||||||
|
case TWSX.FILE:
|
||||||
|
sts = TransferFileImage(ref pending);
|
||||||
|
break;
|
||||||
|
case TWSX.MEMORY:
|
||||||
|
sts = TransferMemoryImage(ref pending);
|
||||||
|
break;
|
||||||
|
case TWSX.MEMFILE:
|
||||||
|
sts = TransferMemoryFileImage(ref pending);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (xferAudio)
|
||||||
|
{
|
||||||
|
switch (audXferMech)
|
||||||
|
{
|
||||||
|
case TWSX.NATIVE:
|
||||||
|
sts = TransferNativeAudio(ref pending);
|
||||||
|
break;
|
||||||
|
case TWSX.FILE:
|
||||||
|
sts = TransferFileAudio(ref pending);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HandleXferCode(ref sts, ref pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TransferError?.Invoke(this, new TransferErrorEventArgs(ex));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (sts.RC == TWRC.SUCCESS && pending.Count != 0);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
|
HandleXferCode(ref sts, ref pending);
|
||||||
|
|
||||||
|
if (State >= STATE.S5)
|
||||||
{
|
{
|
||||||
try
|
DisableSource();
|
||||||
{
|
|
||||||
TransferError?.Invoke(this, new TransferErrorEventArgs(ex));
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
}
|
||||||
}
|
_inTransfer = false;
|
||||||
} while (sts.RC == TWRC.SUCCESS && pending.Count != 0);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
HandleXferCode(ref sts, ref pending);
|
private void HandleXferCode(ref STS sts, ref TW_PENDINGXFERS pending)
|
||||||
|
{
|
||||||
|
switch (sts.RC)
|
||||||
|
{
|
||||||
|
case TWRC.SUCCESS:
|
||||||
|
case TWRC.XFERDONE:
|
||||||
|
// ok to keep going
|
||||||
|
break;
|
||||||
|
case TWRC.CANCEL:
|
||||||
|
// might eventually have option to cancel this or all like transfer ready
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TransferCanceled?.Invoke(this, new TransferCanceledEventArgs());
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
sts = WrapInSTS(DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
if (sts.RC == TWRC.SUCCESS) State = STATE.S5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TODO: raise error event
|
||||||
|
switch (sts.STATUS.ConditionCode)
|
||||||
|
{
|
||||||
|
case TWCC.DAMAGEDCORNER:
|
||||||
|
case TWCC.DOCTOODARK:
|
||||||
|
case TWCC.DOCTOOLIGHT:
|
||||||
|
case TWCC.FOCUSERROR:
|
||||||
|
case TWCC.NOMEDIA:
|
||||||
|
case TWCC.PAPERDOUBLEFEED:
|
||||||
|
case TWCC.PAPERJAM:
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
break;
|
||||||
|
case TWCC.OPERATIONERROR:
|
||||||
|
var indicators = Caps.CAP_INDICATORS.GetCurrent().FirstOrDefault();
|
||||||
|
if (_userInterface.ShowUI == 0 && indicators == TW_BOOL.False)
|
||||||
|
{
|
||||||
|
// todo: alert user and drop to S4
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
sts = WrapInSTS(DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (State >= STATE.S5)
|
private STS TransferFileAudio(ref TW_PENDINGXFERS pending)
|
||||||
{
|
{
|
||||||
DisableSource();
|
// assuming user already configured the transfer in transferready event,
|
||||||
}
|
// get what will be transferred
|
||||||
_inTransfer = false;
|
var rc = DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup);
|
||||||
}
|
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
||||||
|
|
||||||
private void HandleXferCode(ref STS sts, ref TW_PENDINGXFERS pending)
|
// and just start it
|
||||||
{
|
var sts = WrapInSTS(DGAudio.AudioFileXfer.Get(ref _appIdentity, ref _currentDS));
|
||||||
switch (sts.RC)
|
if (sts.RC == TWRC.XFERDONE)
|
||||||
{
|
{
|
||||||
case TWRC.SUCCESS:
|
State = STATE.S7;
|
||||||
case TWRC.XFERDONE:
|
try
|
||||||
// ok to keep going
|
{
|
||||||
break;
|
DGAudio.AudioInfo.Get(ref _appIdentity, ref _currentDS, out TW_AUDIOINFO info);
|
||||||
case TWRC.CANCEL:
|
var args = new TransferredEventArgs(info, fileSetup);
|
||||||
// might eventually have option to cancel this or all like transfer ready
|
Transferred?.Invoke(this, args);
|
||||||
try
|
}
|
||||||
{
|
catch { }
|
||||||
TransferCanceled?.Invoke(this, new TransferCanceledEventArgs());
|
|
||||||
}
|
pending = new TW_PENDINGXFERS();
|
||||||
catch { }
|
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending));
|
|
||||||
if (sts.RC == TWRC.SUCCESS) State = STATE.S5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// TODO: raise error event
|
|
||||||
switch (sts.STATUS.ConditionCode)
|
|
||||||
{
|
|
||||||
case TWCC.DAMAGEDCORNER:
|
|
||||||
case TWCC.DOCTOODARK:
|
|
||||||
case TWCC.DOCTOOLIGHT:
|
|
||||||
case TWCC.FOCUSERROR:
|
|
||||||
case TWCC.NOMEDIA:
|
|
||||||
case TWCC.PAPERDOUBLEFEED:
|
|
||||||
case TWCC.PAPERJAM:
|
|
||||||
pending = default;
|
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
|
||||||
break;
|
|
||||||
case TWCC.OPERATIONERROR:
|
|
||||||
var indicators = Caps.CAP_INDICATORS.GetCurrent().FirstOrDefault();
|
|
||||||
if (_userInterface.ShowUI == 0 && indicators == TW_BOOL.False)
|
|
||||||
{
|
|
||||||
// todo: alert user and drop to S4
|
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending));
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
}
|
{
|
||||||
break;
|
State = STATE.S6;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
}
|
return sts;
|
||||||
}
|
|
||||||
|
|
||||||
private STS TransferFileAudio(ref TW_PENDINGXFERS pending)
|
|
||||||
{
|
|
||||||
// assuming user already configured the transfer in transferready event,
|
|
||||||
// get what will be transferred
|
|
||||||
var rc = DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup);
|
|
||||||
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
|
||||||
|
|
||||||
// and just start it
|
|
||||||
var sts = WrapInSTS(DGAudio.AudioFileXfer.Get(ref _appIdentity, ref _currentDS));
|
|
||||||
if (sts.RC == TWRC.XFERDONE)
|
|
||||||
{
|
|
||||||
State = STATE.S7;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DGAudio.AudioInfo.Get(ref _appIdentity, ref _currentDS, out TW_AUDIOINFO info);
|
|
||||||
var args = new TransferredEventArgs(info, fileSetup);
|
|
||||||
Transferred?.Invoke(this, args);
|
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
;
|
private STS TransferNativeAudio(ref TW_PENDINGXFERS pending)
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
|
||||||
{
|
{
|
||||||
State = STATE.S6;
|
IntPtr dataPtr = IntPtr.Zero;
|
||||||
}
|
IntPtr lockedPtr = IntPtr.Zero;
|
||||||
}
|
|
||||||
return sts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private STS TransferNativeAudio(ref TW_PENDINGXFERS pending)
|
|
||||||
{
|
|
||||||
IntPtr dataPtr = IntPtr.Zero;
|
|
||||||
IntPtr lockedPtr = IntPtr.Zero;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var sts = WrapInSTS(DGAudio.AudioNativeXfer.Get(ref _appIdentity, ref _currentDS, out dataPtr));
|
|
||||||
if (sts.RC == TWRC.XFERDONE)
|
|
||||||
{
|
|
||||||
State = STATE.S7;
|
|
||||||
lockedPtr = Lock(dataPtr);
|
|
||||||
BufferedData? data = default;
|
|
||||||
|
|
||||||
// TODO: don't know how to read wav/aiff from pointer yet
|
|
||||||
|
|
||||||
if (data != null)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DGAudio.AudioInfo.Get(ref _appIdentity, ref _currentDS, out TW_AUDIOINFO info);
|
var sts = WrapInSTS(DGAudio.AudioNativeXfer.Get(ref _appIdentity, ref _currentDS, out dataPtr));
|
||||||
var args = new TransferredEventArgs(info, data);
|
if (sts.RC == TWRC.XFERDONE)
|
||||||
Transferred?.Invoke(this, args);
|
{
|
||||||
}
|
State = STATE.S7;
|
||||||
catch
|
lockedPtr = Lock(dataPtr);
|
||||||
{
|
BufferedData? data = default;
|
||||||
data.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
// TODO: don't know how to read wav/aiff from pointer yet
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
|
||||||
{
|
|
||||||
State = STATE.S6;
|
|
||||||
}
|
|
||||||
return sts;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (lockedPtr != IntPtr.Zero) Unlock(dataPtr);
|
|
||||||
if (dataPtr != IntPtr.Zero) Free(dataPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private STS TransferMemoryImage(ref TW_PENDINGXFERS pending)
|
if (data != null)
|
||||||
{
|
{
|
||||||
var rc = DGControl.SetupMemXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPMEMXFER memSetup);
|
try
|
||||||
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
{
|
||||||
rc = DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info);
|
DGAudio.AudioInfo.Get(ref _appIdentity, ref _currentDS, out TW_AUDIOINFO info);
|
||||||
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
var args = new TransferredEventArgs(info, data);
|
||||||
rc = DGImage.ImageLayout.Get(ref _appIdentity, ref _currentDS, out TW_IMAGELAYOUT layout);
|
Transferred?.Invoke(this, args);
|
||||||
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
data.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint buffSize = memSetup.DetermineBufferSize();
|
pending = new TW_PENDINGXFERS();
|
||||||
var memPtr = Alloc(buffSize);
|
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
TW_IMAGEMEMXFER memXfer = TW_IMAGEMEMXFER.DONTCARE();
|
{
|
||||||
TW_IMAGEMEMXFER_MACOSX memXferOSX = TW_IMAGEMEMXFER_MACOSX.DONTCARE();
|
State = STATE.S6;
|
||||||
memXfer.Memory = new TW_MEMORY
|
}
|
||||||
{
|
return sts;
|
||||||
Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER),
|
|
||||||
Length = buffSize,
|
|
||||||
TheMem = memPtr
|
|
||||||
};
|
|
||||||
memXferOSX.Memory = memXfer.Memory;
|
|
||||||
|
|
||||||
byte[] dotnetBuff = BufferedData.MemPool.Rent((int)buffSize);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
rc = TWPlatform.IsMacOSX ?
|
|
||||||
DGImage.ImageMemXfer.Get(ref _appIdentity, ref _currentDS, ref memXferOSX) :
|
|
||||||
DGImage.ImageMemXfer.Get(ref _appIdentity, ref _currentDS, ref memXfer);
|
|
||||||
|
|
||||||
if (rc == TWRC.SUCCESS || rc == TWRC.XFERDONE)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var written = TWPlatform.IsMacOSX ?
|
|
||||||
memXferOSX.BytesWritten : memXfer.BytesWritten;
|
|
||||||
|
|
||||||
IntPtr lockedPtr = Lock(memPtr);
|
|
||||||
|
|
||||||
// assemble!
|
|
||||||
|
|
||||||
//Marshal.Copy(lockedPtr, dotnetBuff, 0, (int)written);
|
|
||||||
//outStream.Write(dotnetBuff, 0, (int)written);
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Unlock(memPtr);
|
if (lockedPtr != IntPtr.Zero) Unlock(dataPtr);
|
||||||
|
if (dataPtr != IntPtr.Zero) Free(dataPtr);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} while (rc == TWRC.SUCCESS);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (memPtr != IntPtr.Zero) Free(memPtr);
|
|
||||||
BufferedData.MemPool.Return(dotnetBuff);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (rc == TWRC.XFERDONE)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out info);
|
|
||||||
//var args = new DataTransferredEventArgs(info, null, outStream.ToArray());
|
|
||||||
//DataTransferred?.Invoke(this, args);
|
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
|
|
||||||
var sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
private STS TransferMemoryImage(ref TW_PENDINGXFERS pending)
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
|
||||||
{
|
{
|
||||||
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
var rc = DGControl.SetupMemXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPMEMXFER memSetup);
|
||||||
}
|
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
||||||
return sts;
|
rc = DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info);
|
||||||
}
|
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
||||||
return WrapInSTS(rc);
|
rc = DGImage.ImageLayout.Get(ref _appIdentity, ref _currentDS, out TW_IMAGELAYOUT layout);
|
||||||
}
|
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
||||||
|
|
||||||
private STS TransferMemoryFileImage(ref TW_PENDINGXFERS pending)
|
uint buffSize = memSetup.DetermineBufferSize();
|
||||||
{
|
var memPtr = Alloc(buffSize);
|
||||||
var rc = DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup);
|
|
||||||
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
|
||||||
rc = DGControl.SetupMemXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPMEMXFER memSetup);
|
|
||||||
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
|
||||||
|
|
||||||
uint buffSize = memSetup.DetermineBufferSize();
|
TW_IMAGEMEMXFER memXfer = TW_IMAGEMEMXFER.DONTCARE();
|
||||||
var memPtr = Alloc(buffSize);
|
TW_IMAGEMEMXFER_MACOSX memXferOSX = TW_IMAGEMEMXFER_MACOSX.DONTCARE();
|
||||||
|
memXfer.Memory = new TW_MEMORY
|
||||||
|
{
|
||||||
|
Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER),
|
||||||
|
Length = buffSize,
|
||||||
|
TheMem = memPtr
|
||||||
|
};
|
||||||
|
memXferOSX.Memory = memXfer.Memory;
|
||||||
|
|
||||||
TW_IMAGEMEMXFER memXfer = TW_IMAGEMEMXFER.DONTCARE();
|
byte[] dotnetBuff = BufferedData.MemPool.Rent((int)buffSize);
|
||||||
TW_IMAGEMEMXFER_MACOSX memXferOSX = TW_IMAGEMEMXFER_MACOSX.DONTCARE();
|
|
||||||
memXfer.Memory = new TW_MEMORY
|
|
||||||
{
|
|
||||||
Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER),
|
|
||||||
Length = buffSize,
|
|
||||||
TheMem = memPtr
|
|
||||||
};
|
|
||||||
memXferOSX.Memory = memXfer.Memory;
|
|
||||||
|
|
||||||
// TODO: how to get actual file size before hand? Is it imagelayout?
|
|
||||||
// otherwise will just write to stream with lots of copies
|
|
||||||
byte[] dotnetBuff = BufferedData.MemPool.Rent((int)buffSize);
|
|
||||||
using var outStream = new MemoryStream();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
rc = TWPlatform.IsMacOSX ?
|
|
||||||
DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXferOSX) :
|
|
||||||
DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXfer);
|
|
||||||
|
|
||||||
if (rc == TWRC.SUCCESS || rc == TWRC.XFERDONE)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var written = TWPlatform.IsMacOSX ?
|
do
|
||||||
memXferOSX.BytesWritten : memXfer.BytesWritten;
|
{
|
||||||
|
rc = TWPlatform.IsMacOSX ?
|
||||||
|
DGImage.ImageMemXfer.Get(ref _appIdentity, ref _currentDS, ref memXferOSX) :
|
||||||
|
DGImage.ImageMemXfer.Get(ref _appIdentity, ref _currentDS, ref memXfer);
|
||||||
|
|
||||||
IntPtr lockedPtr = Lock(memPtr);
|
if (rc == TWRC.SUCCESS || rc == TWRC.XFERDONE)
|
||||||
Marshal.Copy(lockedPtr, dotnetBuff, 0, (int)written);
|
{
|
||||||
outStream.Write(dotnetBuff, 0, (int)written);
|
try
|
||||||
|
{
|
||||||
|
var written = TWPlatform.IsMacOSX ?
|
||||||
|
memXferOSX.BytesWritten : memXfer.BytesWritten;
|
||||||
|
|
||||||
|
IntPtr lockedPtr = Lock(memPtr);
|
||||||
|
|
||||||
|
// assemble!
|
||||||
|
|
||||||
|
//Marshal.Copy(lockedPtr, dotnetBuff, 0, (int)written);
|
||||||
|
//outStream.Write(dotnetBuff, 0, (int)written);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Unlock(memPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (rc == TWRC.SUCCESS);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Unlock(memPtr);
|
if (memPtr != IntPtr.Zero) Free(memPtr);
|
||||||
|
BufferedData.MemPool.Return(dotnetBuff);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} while (rc == TWRC.SUCCESS);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (memPtr != IntPtr.Zero) Free(memPtr);
|
|
||||||
BufferedData.MemPool.Return(dotnetBuff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == TWRC.XFERDONE)
|
|
||||||
{
|
if (rc == TWRC.XFERDONE)
|
||||||
try
|
{
|
||||||
{
|
try
|
||||||
DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info);
|
{
|
||||||
// ToArray bypasses the XferMemPool but I guess this will have to do for now
|
DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out info);
|
||||||
var args = new TransferredEventArgs(this, info, fileSetup, new BufferedData(outStream.ToArray(), (int)outStream.Length, false));
|
//var args = new DataTransferredEventArgs(info, null, outStream.ToArray());
|
||||||
Transferred?.Invoke(this, args);
|
//DataTransferred?.Invoke(this, args);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
var sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
|
{
|
||||||
|
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
||||||
|
}
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
return WrapInSTS(rc);
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
|
|
||||||
var sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
private STS TransferMemoryFileImage(ref TW_PENDINGXFERS pending)
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
|
||||||
{
|
{
|
||||||
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
var rc = DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup);
|
||||||
}
|
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
||||||
return sts;
|
rc = DGControl.SetupMemXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPMEMXFER memSetup);
|
||||||
}
|
if (rc != TWRC.SUCCESS) return WrapInSTS(rc);
|
||||||
return WrapInSTS(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private STS TransferFileImage(ref TW_PENDINGXFERS pending)
|
uint buffSize = memSetup.DetermineBufferSize();
|
||||||
{
|
var memPtr = Alloc(buffSize);
|
||||||
// assuming user already configured the transfer in transferready event,
|
|
||||||
// get what will be transferred
|
|
||||||
DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup);
|
|
||||||
// and just start it
|
|
||||||
var sts = WrapInSTS(DGImage.ImageFileXfer.Get(ref _appIdentity, ref _currentDS));
|
|
||||||
if (sts.RC == TWRC.XFERDONE)
|
|
||||||
{
|
|
||||||
State = STATE.S7;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info);
|
|
||||||
var args = new TransferredEventArgs(this, info, fileSetup, default);
|
|
||||||
Transferred?.Invoke(this, args);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
TW_IMAGEMEMXFER memXfer = TW_IMAGEMEMXFER.DONTCARE();
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
TW_IMAGEMEMXFER_MACOSX memXferOSX = TW_IMAGEMEMXFER_MACOSX.DONTCARE();
|
||||||
{
|
memXfer.Memory = new TW_MEMORY
|
||||||
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
{
|
||||||
}
|
Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER),
|
||||||
}
|
Length = buffSize,
|
||||||
return sts;
|
TheMem = memPtr
|
||||||
}
|
};
|
||||||
|
memXferOSX.Memory = memXfer.Memory;
|
||||||
|
|
||||||
private STS TransferNativeImage(ref TW_PENDINGXFERS pending)
|
// TODO: how to get actual file size before hand? Is it imagelayout?
|
||||||
{
|
// otherwise will just write to stream with lots of copies
|
||||||
IntPtr dataPtr = IntPtr.Zero;
|
byte[] dotnetBuff = BufferedData.MemPool.Rent((int)buffSize);
|
||||||
IntPtr lockedPtr = IntPtr.Zero;
|
using var outStream = new MemoryStream();
|
||||||
try
|
|
||||||
{
|
|
||||||
DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info);
|
|
||||||
var sts = WrapInSTS(DGImage.ImageNativeXfer.Get(ref _appIdentity, ref _currentDS, out dataPtr));
|
|
||||||
if (sts.RC == TWRC.XFERDONE)
|
|
||||||
{
|
|
||||||
State = STATE.S7;
|
|
||||||
lockedPtr = Lock(dataPtr);
|
|
||||||
BufferedData? data = default;
|
|
||||||
|
|
||||||
if (ImageTools.IsDib(lockedPtr))
|
|
||||||
{
|
|
||||||
data = ImageTools.GetBitmapData(lockedPtr);
|
|
||||||
}
|
|
||||||
else if (ImageTools.IsTiff(lockedPtr))
|
|
||||||
{
|
|
||||||
data = ImageTools.GetTiffData(lockedPtr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// PicHandle?
|
|
||||||
// don't support more formats :(
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data != null)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// some sources do not support getting image info in state 7 so
|
do
|
||||||
// it's up there in the beginning now.
|
{
|
||||||
var args = new TransferredEventArgs(this, info, null, data);
|
rc = TWPlatform.IsMacOSX ?
|
||||||
Transferred?.Invoke(this, args);
|
DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXferOSX) :
|
||||||
|
DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXfer);
|
||||||
|
|
||||||
|
if (rc == TWRC.SUCCESS || rc == TWRC.XFERDONE)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var written = TWPlatform.IsMacOSX ?
|
||||||
|
memXferOSX.BytesWritten : memXfer.BytesWritten;
|
||||||
|
|
||||||
|
IntPtr lockedPtr = Lock(memPtr);
|
||||||
|
Marshal.Copy(lockedPtr, dotnetBuff, 0, (int)written);
|
||||||
|
outStream.Write(dotnetBuff, 0, (int)written);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Unlock(memPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (rc == TWRC.SUCCESS);
|
||||||
}
|
}
|
||||||
catch
|
finally
|
||||||
{
|
{
|
||||||
data.Dispose();
|
if (memPtr != IntPtr.Zero) Free(memPtr);
|
||||||
|
BufferedData.MemPool.Return(dotnetBuff);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if (rc == TWRC.XFERDONE)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info);
|
||||||
|
// ToArray bypasses the XferMemPool but I guess this will have to do for now
|
||||||
|
var args = new TransferredEventArgs(this, info, fileSetup, new BufferedData(outStream.ToArray(), (int)outStream.Length, false));
|
||||||
|
Transferred?.Invoke(this, args);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
pending = new TW_PENDINGXFERS();
|
||||||
if (sts.RC == TWRC.SUCCESS)
|
var sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
{
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
{
|
||||||
}
|
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
||||||
|
}
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
return WrapInSTS(rc);
|
||||||
}
|
}
|
||||||
return sts;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (lockedPtr != IntPtr.Zero) Unlock(dataPtr);
|
|
||||||
if (dataPtr != IntPtr.Zero) Free(dataPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
private STS TransferFileImage(ref TW_PENDINGXFERS pending)
|
||||||
|
{
|
||||||
|
// assuming user already configured the transfer in transferready event,
|
||||||
|
// get what will be transferred
|
||||||
|
DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup);
|
||||||
|
// and just start it
|
||||||
|
var sts = WrapInSTS(DGImage.ImageFileXfer.Get(ref _appIdentity, ref _currentDS));
|
||||||
|
if (sts.RC == TWRC.XFERDONE)
|
||||||
|
{
|
||||||
|
State = STATE.S7;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info);
|
||||||
|
var args = new TransferredEventArgs(this, info, fileSetup, default);
|
||||||
|
Transferred?.Invoke(this, args);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
|
{
|
||||||
|
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private STS TransferNativeImage(ref TW_PENDINGXFERS pending)
|
||||||
|
{
|
||||||
|
IntPtr dataPtr = IntPtr.Zero;
|
||||||
|
IntPtr lockedPtr = IntPtr.Zero;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info);
|
||||||
|
var sts = WrapInSTS(DGImage.ImageNativeXfer.Get(ref _appIdentity, ref _currentDS, out dataPtr));
|
||||||
|
if (sts.RC == TWRC.XFERDONE)
|
||||||
|
{
|
||||||
|
State = STATE.S7;
|
||||||
|
lockedPtr = Lock(dataPtr);
|
||||||
|
BufferedData? data = default;
|
||||||
|
|
||||||
|
if (ImageTools.IsDib(lockedPtr))
|
||||||
|
{
|
||||||
|
data = ImageTools.GetBitmapData(lockedPtr);
|
||||||
|
}
|
||||||
|
else if (ImageTools.IsTiff(lockedPtr))
|
||||||
|
{
|
||||||
|
data = ImageTools.GetTiffData(lockedPtr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// PicHandle?
|
||||||
|
// don't support more formats :(
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// some sources do not support getting image info in state 7 so
|
||||||
|
// it's up there in the beginning now.
|
||||||
|
var args = new TransferredEventArgs(this, info, null, data);
|
||||||
|
Transferred?.Invoke(this, args);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
data.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pending = new TW_PENDINGXFERS();
|
||||||
|
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
|
||||||
|
if (sts.RC == TWRC.SUCCESS)
|
||||||
|
{
|
||||||
|
State = pending.Count == 0 ? STATE.S5 : STATE.S6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (lockedPtr != IntPtr.Zero) Unlock(dataPtr);
|
||||||
|
if (dataPtr != IntPtr.Zero) Free(dataPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user