Skip to content

Commit

Permalink
Sdk: Keep SANE initialized for multiple operations
Browse files Browse the repository at this point in the history
  • Loading branch information
cyanfish committed Mar 1, 2024
1 parent c8eab25 commit 4ba463d
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 5 deletions.
4 changes: 4 additions & 0 deletions NAPS2.Lib/Scan/ScanPerformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ private ScanOptions BuildOptions(ScanProfile scanProfile, ScanParams scanParams,
IncludeWiaDevices = false
// TODO: Consider adding a user option for TwainOptions.ShowProgress instead of our progress window
},
SaneOptions =
{
KeepInitialized = false
},
KeyValueOptions = scanProfile.KeyValueOptions != null
? new KeyValueScanOptions(scanProfile.KeyValueOptions)
: new KeyValueScanOptions(),
Expand Down
17 changes: 14 additions & 3 deletions NAPS2.Sdk/Scan/Internal/Sane/Native/SaneClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace NAPS2.Scan.Internal.Sane.Native;
internal class SaneClient : SaneNativeObject
{
private static readonly object SaneLock = new();
private static bool _isInitialized;

private readonly bool _keepInitialized;

private static SaneNativeLibrary GetNativeLibrary(ISaneInstallation saneInstallation)
{
Expand All @@ -15,10 +18,17 @@ private static SaneNativeLibrary GetNativeLibrary(ISaneInstallation saneInstalla
}
}

public SaneClient(ISaneInstallation saneInstallation) : base(GetNativeLibrary(saneInstallation), IntPtr.Zero)
public SaneClient(ISaneInstallation saneInstallation, bool keepInitialized)
: base(GetNativeLibrary(saneInstallation), IntPtr.Zero)
{
_keepInitialized = keepInitialized;

Monitor.Enter(SaneLock);
Native.sane_init(out _, IntPtr.Zero);
if (!_isInitialized)
{
Native.sane_init(out _, IntPtr.Zero);
_isInitialized = true;
}
}

public IEnumerable<SaneDeviceInfo> GetDevices()
Expand Down Expand Up @@ -56,9 +66,10 @@ public SaneDevice OpenDevice(string deviceName)

protected override void Dispose(bool disposing)
{
if (disposing)
if (disposing && !_keepInitialized)
{
Native.sane_exit();
_isInitialized = false;
}
Monitor.Exit(SaneLock);
}
Expand Down
4 changes: 2 additions & 2 deletions NAPS2.Sdk/Scan/Internal/Sane/SaneScanDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void MaybeCallback(SaneDeviceInfo device)
{
// TODO: This is crashing after a delay for no apparent reason.
// That's okay because we're in a worker process, but ideally we could fix it in SANE.
using var client = new SaneClient(Installation);
using var client = new SaneClient(Installation, options.SaneOptions.KeepInitialized);
// TODO: We can use device.type and .vendor to help pick an icon etc.
// https://sane-project.gitlab.io/standard/api.html#device-descriptor-type
if (Installation.CanStreamDevices)
Expand Down Expand Up @@ -133,7 +133,7 @@ public Task Scan(ScanOptions options, CancellationToken cancelToken, IScanEvents
try
{
Installation.Initialize();
using var client = new SaneClient(Installation);
using var client = new SaneClient(Installation, options.SaneOptions.KeepInitialized);
if (cancelToken.IsCancellationRequested) return;
_scanningContext.Logger.LogDebug("Opening SANE Device \"{ID}\"", options.Device!.ID);
using var device = client.OpenDevice(options.Device.ID);
Expand Down
6 changes: 6 additions & 0 deletions NAPS2.Sdk/Scan/SaneOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ public class SaneOptions
/// Limit the devices queried by GetDevices/GetDeviceList to the given SANE backend.
/// </summary>
public string? Backend { get; set; }

/// <summary>
/// Whether to keep SANE initialized in memory after the operation is complete. This improves stability when
/// doing multiple operations in a single process. Defaults to true.
/// </summary>
public bool KeepInitialized { get; set; } = true;
}

0 comments on commit 4ba463d

Please sign in to comment.