mirror of
https://github.com/soukoku/ntwain.git
synced 2026-02-25 13:04:07 +08:00
Experiment with ownership idea for transferred event so caller won't need to dispose it.
This commit is contained in:
@@ -141,6 +141,5 @@ internal class Program
|
||||
{
|
||||
Console.WriteLine($"BUMMER! No twain data #{++xferCount} on thread {Environment.CurrentManagedThreadId}.");
|
||||
}
|
||||
e.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ public partial class MainForm : Form
|
||||
var path = info.FileName.ToString();
|
||||
LogIt($"Received {e.ImageInfo.PixelType} {info.Format} in {e.ImageInfo.Compression} compressed file {path}");
|
||||
}
|
||||
e.Dispose();
|
||||
LogIt("");
|
||||
}
|
||||
|
||||
|
||||
@@ -131,20 +131,22 @@ public partial class Form1 : Form
|
||||
if (_useThreadForImag)
|
||||
{
|
||||
// bad thread example but whatev. should use a dedicated thread of some sort for real
|
||||
var data = e.TakeDataOwnership();
|
||||
Task.Run(() =>
|
||||
{
|
||||
HandleTransferredData(e);
|
||||
HandleTransferredData(data);
|
||||
data?.Dispose();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleTransferredData(e);
|
||||
HandleTransferredData(e.Data);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleTransferredData(TransferredEventArgs e)
|
||||
private void HandleTransferredData(BufferedData? data)
|
||||
{
|
||||
if (e.Data != null)
|
||||
if (data != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -153,7 +155,7 @@ public partial class Form1 : Form
|
||||
|
||||
if (_useSystemDrawing)
|
||||
{
|
||||
using (var img = Image.FromStream(e.Data.AsStream()))
|
||||
using (var img = Image.FromStream(data.AsStream()))
|
||||
{
|
||||
if (img.PixelFormat == System.Drawing.Imaging.PixelFormat.Format1bppIndexed ||
|
||||
img.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
|
||||
@@ -174,7 +176,7 @@ public partial class Form1 : Form
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var img = new ImageMagick.MagickImage(e.Data.AsSpan()))
|
||||
using (var img = new ImageMagick.MagickImage(data.AsSpan()))
|
||||
{
|
||||
var format = ImageMagick.MagickFormat.Png;
|
||||
if (img.ColorType == ImageMagick.ColorType.Palette)
|
||||
@@ -198,7 +200,7 @@ public partial class Form1 : Form
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
e.Dispose();
|
||||
data.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,10 +110,6 @@ public sealed partial class MainWindow : Window
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
e.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void Session_SourceDisabled(TwainAppSession sender, TWIdentityWrapper e)
|
||||
|
||||
@@ -34,11 +34,14 @@ public class TransferredEventArgs : EventArgs, IDisposable
|
||||
/// </summary>
|
||||
public bool IsImage { get; }
|
||||
|
||||
private readonly BufferedData? _data;
|
||||
private BufferedData? _data;
|
||||
private bool _dataOwnershipTransferred;
|
||||
|
||||
/// <summary>
|
||||
/// The complete file data if memory was involved in the transfer.
|
||||
/// IMPORTANT: Content of this array will not be valid once
|
||||
/// this event arg has been disposed.
|
||||
/// Gets the transferred data.
|
||||
/// IMPORTANT: This data is only valid during the event handler execution.
|
||||
/// If you need to keep the data after the event handler returns, call <see cref="TakeDataOwnership"/> first.
|
||||
/// Otherwise, the data will be automatically disposed when the event completes.
|
||||
/// </summary>
|
||||
public BufferedData? Data => _data;
|
||||
|
||||
@@ -73,8 +76,51 @@ public class TransferredEventArgs : EventArgs, IDisposable
|
||||
return _twain.WrapInSTS(DGImage.ExtImageInfo.Get(_twain.AppIdentity, _twain.CurrentSource, ref container));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfers ownership of the in-memory data to the caller, preventing automatic disposal.
|
||||
/// Use this when you need to process the data asynchronously or keep it beyond the event handler scope.
|
||||
/// After calling this, you MUST manually dispose the returned BufferedData when finished.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The buffered data with transferred ownership, or null if no data exists or ownership was already transferred.
|
||||
/// </returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// private async void OnTransferred(TwainAppSession sender, TransferredEventArgs e)
|
||||
/// {
|
||||
/// var data = e.TakeDataOwnership(); // Take ownership
|
||||
/// if (data != null)
|
||||
/// {
|
||||
/// try
|
||||
/// {
|
||||
/// await ProcessDataAsync(data); // Can use beyond event handler
|
||||
/// }
|
||||
/// finally
|
||||
/// {
|
||||
/// data.Dispose(); // Must dispose when done
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public BufferedData? TakeDataOwnership()
|
||||
{
|
||||
if (_dataOwnershipTransferred || _data == null)
|
||||
return null;
|
||||
|
||||
_dataOwnershipTransferred = true;
|
||||
var data = _data;
|
||||
_data = null;
|
||||
return data;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_data?.Dispose();
|
||||
// Only dispose if ownership wasn't transferred
|
||||
if (!_dataOwnershipTransferred && _data != null)
|
||||
{
|
||||
_data.Dispose();
|
||||
_data = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,10 +224,7 @@ partial class TransferLoopThread
|
||||
var args = new TransferredEventArgs(info, data);
|
||||
_twain.RaiseTransferred(args);
|
||||
}
|
||||
catch
|
||||
{
|
||||
data.Dispose();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,10 +311,7 @@ partial class TransferLoopThread
|
||||
var args = new TransferredEventArgs(_twain, info, null, data);
|
||||
_twain.RaiseTransferred(args);
|
||||
}
|
||||
catch
|
||||
{
|
||||
data.Dispose();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ partial class TwainAppSession
|
||||
internal void RaiseTransferred(TransferredEventArgs args)
|
||||
{
|
||||
// no wait here, app can handle at its leisure
|
||||
RaiseEvent(Transferred, args);
|
||||
RaiseEvent(Transferred, args, static e => e.Dispose());
|
||||
}
|
||||
|
||||
|
||||
@@ -139,17 +139,24 @@ partial class TwainAppSession
|
||||
/// <typeparam name="TEventArgs">The type of event arguments.</typeparam>
|
||||
/// <param name="eventHandler">The event handler to invoke.</param>
|
||||
/// <param name="eventArgs">The event arguments.</param>
|
||||
protected void RaiseEvent<TEventArgs>(EventHandler<TwainAppSession, TEventArgs>? eventHandler, TEventArgs eventArgs)
|
||||
/// <param name="completeCallback"></param>
|
||||
protected void RaiseEvent<TEventArgs>(EventHandler<TwainAppSession, TEventArgs>? eventHandler, TEventArgs eventArgs,
|
||||
Action<TEventArgs>? completeCallback = null)
|
||||
{
|
||||
if (eventHandler == null) return;
|
||||
|
||||
if (AppThreadContext != null)
|
||||
{
|
||||
AppThreadContext.Post(_ => eventHandler(this, eventArgs), null);
|
||||
AppThreadContext.Post(_ =>
|
||||
{
|
||||
eventHandler(this, eventArgs);
|
||||
completeCallback?.Invoke(eventArgs);
|
||||
}, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventHandler(this, eventArgs);
|
||||
completeCallback?.Invoke(eventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user