Experiment with only transferring data in background thread to work with bad sources.

This commit is contained in:
Eugene Wang 2023-04-09 23:30:06 -04:00
parent 902cf844df
commit 4b337f036e
5 changed files with 53 additions and 53 deletions

View File

@ -86,8 +86,6 @@ namespace NTwain
return (ushort)TWRC.SUCCESS;
}
bool _closeDsRequested;
bool _inTransfer;
private void HandleSourceMsg(MSG msg, [CallerMemberName] string? caller = null)
{
@ -95,7 +93,7 @@ namespace NTwain
// the reason we post these to the background is
// if they're coming from UI message loop then
// this needs to return asap (?)
// this needs to return asap
switch (msg)
{
@ -104,18 +102,33 @@ namespace NTwain
if (!_inTransfer)
{
_inTransfer = true;
_bgPendingMsgs.Add(msg);
_xferReady.Set();
//_bgPendingMsgs.Add(msg);
}
break;
case MSG.DEVICEEVENT:
case MSG.CLOSEDSOK:
_bgPendingMsgs.Add(msg);
break;
case MSG.CLOSEDSREQ:
_closeDsRequested = true;
if (!_inTransfer)
{
_bgPendingMsgs.Add(msg);
// this should be done on ui thread (or same one that enabled the ds)
_uiThreadMarshaller.BeginInvoke(() =>
{
DisableSource();
});
}
break;
case MSG.DEVICEEVENT:
if (DeviceEvent != null && DGControl.DeviceEvent.Get(ref _appIdentity, ref _currentDS, out TW_DEVICEEVENT de) == TWRC.SUCCESS)
{
_uiThreadMarshaller.BeginInvoke(() =>
{
try
{
DeviceEvent.Invoke(this, de);
}
catch { }
});
}
break;
}

View File

@ -137,6 +137,7 @@ namespace NTwain
/// <returns></returns>
public STS DisableSource()
{
_closeDsRequested = true;
var rc = DGControl.UserInterface.DisableDS(ref _appIdentity, ref _currentDS, ref _userInterface);
if (rc == TWRC.SUCCESS)
{

View File

@ -87,12 +87,15 @@ namespace NTwain
_procEvent.pEvent = Marshal.AllocHGlobal(Marshal.SizeOf(winMsg));
Marshal.StructureToPtr(winMsg, _procEvent.pEvent, true);
var rc = DGControl.Event.ProcessEvent(ref _appIdentity, ref _currentDS, ref _procEvent);
handled = rc == TWRC.DSEVENT;
if (_procEvent.TWMessage != 0 && (handled || rc == TWRC.NOTDSEVENT))
if (!_closeDsRequested)
{
//Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] CheckIfTwainMessage at state {State} with MSG={_procEvent.TWMessage}.");
HandleSourceMsg((MSG)_procEvent.TWMessage);
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;

View File

@ -171,14 +171,14 @@ namespace NTwain
}
HandleXferCode(sts);
_inTransfer = false;
if (State >= STATE.S5)
{
_uiThreadMarshaller.BeginInvoke(() =>
_uiThreadMarshaller.Invoke(() =>
{
DisableSource();
});
}
_inTransfer = false;
}
private void HandleXferCode(STS sts)

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Xml;
namespace NTwain
{
@ -93,7 +94,7 @@ namespace NTwain
_osxCallbackDelegate = OSXCallbackHandler;
_uiThreadMarshaller = uiThreadMarshaller;
StartBackgroundThread();
StartTransferThread();
}
internal IntPtr _hwnd;
@ -102,13 +103,16 @@ namespace NTwain
TW_EVENT _procEvent; // kept here so the alloc/free only happens once
#endif
// test threads a bit
readonly BlockingCollection<MSG> _bgPendingMsgs = new();
//readonly BlockingCollection<MSG> _bgPendingMsgs = new();
private readonly IThreadMarshaller _uiThreadMarshaller;
bool _closeDsRequested;
bool _inTransfer;
readonly AutoResetEvent _xferReady = new(false);
private bool disposedValue;
void StartBackgroundThread()
void StartTransferThread()
{
Thread t = new(BackgroundThreadLoop)
Thread t = new(TransferLoopLoop)
{
IsBackground = true
};
@ -118,44 +122,21 @@ namespace NTwain
t.Start();
}
private void BackgroundThreadLoop(object? obj)
private void TransferLoopLoop(object? obj)
{
foreach (var msg in _bgPendingMsgs.GetConsumingEnumerable())
while (!disposedValue)
{
switch (msg)
try
{
case MSG.CLOSEDSOK:
case MSG.CLOSEDSREQ:
// this should be done on ui thread (or same one that enabled the ds)
_uiThreadMarshaller.BeginInvoke(() =>
{
DisableSource();
});
break;
case MSG.DEVICEEVENT:
if (DeviceEvent != null && DGControl.DeviceEvent.Get(ref _appIdentity, ref _currentDS, out TW_DEVICEEVENT de) == TWRC.SUCCESS)
{
_uiThreadMarshaller.BeginInvoke(() =>
{
try
{
DeviceEvent.Invoke(this, de);
}
catch { }
});
}
break;
case MSG.XFERREADY:
//_uiThreadMarshaller.Invoke(() =>
//{
State = STATE.S6;
//});
EnterTransferRoutine();
break;
_xferReady.WaitOne();
}
catch (ObjectDisposedException) { break; }
try
{
EnterTransferRoutine();
}
catch { }
}
Debug.WriteLine("Ending BackgroundThreadLoop...");
}
protected virtual void Dispose(bool disposing)
@ -165,7 +146,9 @@ namespace NTwain
if (disposing)
{
// this will end the bg thread
_bgPendingMsgs.CompleteAdding();
_xferReady.Dispose();
//_bgPendingMsgs.CompleteAdding();
}
#if WINDOWS || NETFRAMEWORK
if (_procEvent.pEvent != IntPtr.Zero) Marshal.FreeHGlobal(_procEvent.pEvent);