Timing hack for file transfer.

This commit is contained in:
Eugene Wang 2025-02-19 06:47:37 -05:00
parent 69d90aa945
commit 6b35b1735d
6 changed files with 510 additions and 448 deletions

View File

@ -36,7 +36,9 @@ namespace WinConsole32
Console.WriteLine($"Default data source = {defaultSrc}"); Console.WriteLine($"Default data source = {defaultSrc}");
Console.WriteLine(); Console.WriteLine();
twain.ShowUserSelect(); sts = twain.ShowUserSelect();
if (sts.IsSuccess)
{
Console.WriteLine($"Selected data source = {twain.DefaultSource}"); Console.WriteLine($"Selected data source = {twain.DefaultSource}");
Console.WriteLine(); Console.WriteLine();
@ -58,6 +60,7 @@ namespace WinConsole32
Console.ReadLine(); Console.ReadLine();
twain.TryStepdown(STATE.S1); twain.TryStepdown(STATE.S1);
} }
}
else else
{ {
Console.WriteLine("Failed to attach: " + sts); Console.WriteLine("Failed to attach: " + sts);
@ -115,7 +118,7 @@ namespace WinConsole32
TW_SETUPFILEXFER setup = new() TW_SETUPFILEXFER setup = new()
{ {
FileName = targetName, FileName = Path.Combine("Images", targetName),
Format = format, Format = format,
}; };
e.SetupFileTransfer(ref setup); e.SetupFileTransfer(ref setup);
@ -171,9 +174,11 @@ namespace WinConsole32
{ {
watch.Stop(); watch.Stop();
var elapsed = watch.Elapsed; var elapsed = watch.Elapsed;
Console.WriteLine($"Session source disabled, took {elapsed}."); Console.WriteLine($"Session source disabled, took {elapsed}, will retest in 3 sec...");
//TestThisSource(twain, e); Thread.Sleep(3000);
if (twain.State > STATE.S3)
TestThisSource(twain, e);
} }
private static void TestThisSource(TwainAppSession twain, TW_IDENTITY_LEGACY source) private static void TestThisSource(TwainAppSession twain, TW_IDENTITY_LEGACY source)

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<!--change these in each release--> <!--change these in each release-->
<VersionPrefix>4.0.0.0</VersionPrefix> <VersionPrefix>4.0.0.0</VersionPrefix>
<VersionSuffix>alpha.7</VersionSuffix> <VersionSuffix>alpha.8</VersionSuffix>
<!--keep it the same until major # changes--> <!--keep it the same until major # changes-->
<AssemblyVersion>4.0.0.0</AssemblyVersion> <AssemblyVersion>4.0.0.0</AssemblyVersion>

View File

@ -9,8 +9,7 @@ using System.Windows.Forms;
namespace NTwain namespace NTwain
{ {
/// <summary> /// <summary>
/// For use under Windows to host a message pump in non-winform/wpf apps. /// For use under Windows to host a message pump.
/// This is highly experimental.
/// </summary> /// </summary>
class MessagePumpThread class MessagePumpThread
{ {

View File

@ -98,6 +98,13 @@ namespace NTwain
switch (msg) switch (msg)
{ {
case MSG.XFERREADY: case MSG.XFERREADY:
if (_transferInCallbackThread)
{
EnterTransferRoutine();
}
else
{
// use bg thread to process transfer.
// some sources spam this even during transfer so we gate it // some sources spam this even during transfer so we gate it
if (!_inTransfer) if (!_inTransfer)
{ {
@ -105,6 +112,7 @@ namespace NTwain
_xferReady.Set(); _xferReady.Set();
//_bgPendingMsgs.Add(msg); //_bgPendingMsgs.Add(msg);
} }
}
break; break;
case MSG.CLOSEDSOK: case MSG.CLOSEDSOK:
case MSG.CLOSEDSREQ: case MSG.CLOSEDSREQ:

View File

@ -2,9 +2,11 @@
using NTwain.Native; using NTwain.Native;
using NTwain.Triplets; using NTwain.Triplets;
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
namespace NTwain namespace NTwain
{ {
@ -161,7 +163,7 @@ namespace NTwain
break; break;
} }
} }
HandleXferCode(ref sts, ref pending); HandleXferCode(ref sts, ref pending, isEnd: false);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -176,7 +178,7 @@ namespace NTwain
} while (sts.RC == TWRC.SUCCESS && pending.Count != 0); } while (sts.RC == TWRC.SUCCESS && pending.Count != 0);
} }
HandleXferCode(ref sts, ref pending); HandleXferCode(ref sts, ref pending, isEnd: true);
if (State >= STATE.S5) if (State >= STATE.S5)
{ {
@ -185,13 +187,17 @@ namespace NTwain
_inTransfer = false; _inTransfer = false;
} }
private void HandleXferCode(ref STS sts, ref TW_PENDINGXFERS pending) private void HandleXferCode(ref STS sts, ref TW_PENDINGXFERS pending, bool isEnd)
{ {
switch (sts.RC) switch (sts.RC)
{ {
case TWRC.SUCCESS: case TWRC.SUCCESS:
case TWRC.XFERDONE: case TWRC.XFERDONE:
// ok to keep going // ok to keep going
if (isEnd)
{
//DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending);
}
break; break;
case TWRC.CANCEL: case TWRC.CANCEL:
// might eventually have option to cancel this or all like transfer ready // might eventually have option to cancel this or all like transfer ready
@ -210,6 +216,18 @@ namespace NTwain
// TODO: raise error event // TODO: raise error event
switch (sts.STATUS.ConditionCode) switch (sts.STATUS.ConditionCode)
{ {
case TWCC.SEQERROR:
if (isEnd)
{
// special break down to state 5
pending = TW_PENDINGXFERS.DONTCARE();
sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending));
State = STATE.S6;
pending = TW_PENDINGXFERS.DONTCARE();
sts = WrapInSTS(DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending));
State = STATE.S5;
}
break;
case TWCC.DAMAGEDCORNER: case TWCC.DAMAGEDCORNER:
case TWCC.DOCTOODARK: case TWCC.DOCTOODARK:
case TWCC.DOCTOOLIGHT: case TWCC.DOCTOOLIGHT:
@ -245,6 +263,7 @@ namespace NTwain
// and just start it // and just start it
var sts = WrapInSTS(DGAudio.AudioFileXfer.Get(ref _appIdentity, ref _currentDS)); var sts = WrapInSTS(DGAudio.AudioFileXfer.Get(ref _appIdentity, ref _currentDS));
if (sts.RC == TWRC.XFERDONE) if (sts.RC == TWRC.XFERDONE)
{ {
State = STATE.S7; State = STATE.S7;
@ -475,7 +494,11 @@ namespace NTwain
// get what will be transferred // get what will be transferred
DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup); DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup);
// and just start it // and just start it
int tries = 0;
RETRY:
var sts = WrapInSTS(DGImage.ImageFileXfer.Get(ref _appIdentity, ref _currentDS)); var sts = WrapInSTS(DGImage.ImageFileXfer.Get(ref _appIdentity, ref _currentDS));
if (sts.RC == TWRC.XFERDONE) if (sts.RC == TWRC.XFERDONE)
{ {
State = STATE.S7; State = STATE.S7;
@ -494,6 +517,23 @@ namespace NTwain
State = pending.Count == 0 ? STATE.S5 : STATE.S6; State = pending.Count == 0 ? STATE.S5 : STATE.S6;
} }
} }
else
{
// sometimes it errors only due to timing so wait a bit and try again
if (sts.RC == TWRC.FAILURE && (sts.ConditionCode == TWCC.None || sts.ConditionCode == TWCC.SEQERROR))
{
if (tries++ < 3)
{
Debug.WriteLine($"Using fileXfer timing workaround try {tries}.");
Thread.Sleep(500);
goto RETRY;
}
}
else
{
Debugger.Break();
}
}
return sts; return sts;
} }

View File

@ -50,6 +50,7 @@ namespace NTwain
bool _inTransfer; bool _inTransfer;
readonly AutoResetEvent _xferReady = new(false); readonly AutoResetEvent _xferReady = new(false);
private bool disposedValue; private bool disposedValue;
bool _transferInCallbackThread = true;
void StartTransferThread() void StartTransferThread()
{ {
@ -114,7 +115,7 @@ namespace NTwain
#if WINDOWS || NETFRAMEWORK #if WINDOWS || NETFRAMEWORK
/// <summary> /// <summary>
/// Loads and opens the TWAIN data source manager in a self-hosted message queue thread. /// Loads and opens the TWAIN data source manager in a self-hosted message queue thread.
/// Highly experimental and only use if necessary. Must close with <see cref="CloseDSMAsync"/> /// Must close with <see cref="CloseDSMAsync"/>
/// if used. /// if used.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
@ -122,6 +123,7 @@ namespace NTwain
{ {
if (_selfPump == null) if (_selfPump == null)
{ {
_transferInCallbackThread = true;
var pump = new MessagePumpThread(); var pump = new MessagePumpThread();
var sts = await pump.AttachAsync(this); var sts = await pump.AttachAsync(this);
if (sts.IsSuccess) if (sts.IsSuccess)
@ -162,6 +164,7 @@ namespace NTwain
var rc = DGControl.Parent.OpenDSM(ref _appIdentity, hwnd); var rc = DGControl.Parent.OpenDSM(ref _appIdentity, hwnd);
if (rc == TWRC.SUCCESS) if (rc == TWRC.SUCCESS)
{ {
_transferInCallbackThread = true;
_hwnd = hwnd; _hwnd = hwnd;
_pumpThreadMarshaller = uiThreadMarshaller; _pumpThreadMarshaller = uiThreadMarshaller;
State = STATE.S3; State = STATE.S3;
@ -296,7 +299,14 @@ namespace NTwain
{ {
// todo: finish // todo: finish
case STATE.S7: case STATE.S7:
var pending = TW_PENDINGXFERS.DONTCARE();
DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending);
_state = STATE.S6;
break;
case STATE.S6: case STATE.S6:
pending = TW_PENDINGXFERS.DONTCARE();
DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending);
_state = STATE.S5;
break; break;
case STATE.S5: case STATE.S5:
DisableSource(); DisableSource();