mirror of
https://github.com/cyanfish/naps2.git
synced 2024-09-11 15:26:55 +03:00
Sdk: Win32 worker polish
This commit is contained in:
parent
657a05c2d2
commit
65aec41038
@ -38,7 +38,7 @@ public class DesktopController
|
||||
private bool _initialized;
|
||||
private bool _suspended;
|
||||
|
||||
public DesktopController(ScanningContext scanningContext, UiImageList imageList,
|
||||
internal DesktopController(ScanningContext scanningContext, UiImageList imageList,
|
||||
RecoveryStorageManager recoveryStorageManager, ThumbnailController thumbnailController,
|
||||
OperationProgress operationProgress, Naps2Config config, IOperationFactory operationFactory,
|
||||
StillImage stillImage,
|
||||
|
@ -17,7 +17,7 @@ public class AboutForm : EtoDialogBase
|
||||
private readonly UpdateChecker _updateChecker;
|
||||
private readonly CheckBox _enableDebugLogging = C.CheckBox(UiStrings.EnableDebugLogging);
|
||||
|
||||
public AboutForm(Naps2Config config, UpdateChecker updateChecker, IWorkerFactory workerFactory)
|
||||
public AboutForm(Naps2Config config, UpdateChecker updateChecker)
|
||||
: base(config)
|
||||
{
|
||||
_donateButton = EtoPlatform.Current.AccessibleImageButton(
|
||||
|
36
NAPS2.Sdk.Samples/TwainSample.cs
Normal file
36
NAPS2.Sdk.Samples/TwainSample.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using NAPS2.Images.Gdi;
|
||||
using NAPS2.Scan;
|
||||
|
||||
namespace NAPS2.Sdk.Samples;
|
||||
|
||||
public class TwainSample
|
||||
{
|
||||
public static async Task Run()
|
||||
{
|
||||
// Scanning with TWAIN on Windows must happen from a 32-bit process. You can do this by building your exe as
|
||||
// 32-bit, but the better solution is to install the NAPS2.Sdk.Worker.Win32 Nuget package, which includes a
|
||||
// pre-compiled 32-bit NAPS2.Worker.exe. Then you only need to call ScanningContext.SetUpWin32Worker and you
|
||||
// should be able to scan with TWAIN.
|
||||
//
|
||||
// If you want to use a worker process but don't want to use a pre-compiled exe (or want to set up your own
|
||||
// logging etc), you can also build your own worker exe with the same name (and call WorkerServer.Run in its
|
||||
// Main method).
|
||||
|
||||
using var scanningContext = new ScanningContext(new GdiImageContext());
|
||||
|
||||
// Set up the worker; this includes starting a worker process in the background so it will be ready to respond
|
||||
// when we need it
|
||||
scanningContext.SetUpWin32Worker();
|
||||
|
||||
var controller = new ScanController(scanningContext);
|
||||
|
||||
// As we're not using the default (WIA) driver, we need to specify it when listing devices or scanning
|
||||
ScanDevice device = (await controller.GetDeviceList(Driver.Twain)).First();
|
||||
var options = new ScanOptions { Device = device, Driver = Driver.Twain };
|
||||
|
||||
await foreach (var image in controller.Scan(options))
|
||||
{
|
||||
Console.WriteLine("Scanned a page!");
|
||||
}
|
||||
}
|
||||
}
|
@ -25,4 +25,8 @@
|
||||
<ProjectReference Include="..\NAPS2.Sdk\NAPS2.Sdk.csproj" />
|
||||
<PackageReference Include="LargeAddressAware" Version="1.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="*.targets" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net6</TargetFrameworks>
|
||||
<RootNamespace>NAPS2.Sdk.Worker.Win32</RootNamespace>
|
||||
<RootNamespace>NAPS2.Sdk.Worker</RootNamespace>
|
||||
<AssemblyName>NAPS2.Sdk.Worker.Win32</AssemblyName>
|
||||
|
||||
<Title>NAPS2.Sdk.Worker.Win32</Title>
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="*.*" />
|
||||
<Content Include="NAPS2.Sdk.Worker.targets" PackagePath="build/NAPS2.Sdk.Worker.targets" />
|
||||
<Content Include="NAPS2.Sdk.Worker.Win32.targets" PackagePath="build/NAPS2.Sdk.Worker.Win32.targets" />
|
||||
<None Include="bin\Release\net6\win-x86\publish\NAPS2.Worker.exe">
|
||||
<Link>lib/NAPS2.Worker.exe</Link>
|
||||
<Pack>true</Pack>
|
||||
|
@ -5,7 +5,7 @@ namespace NAPS2.Remoting.Worker;
|
||||
/// <summary>
|
||||
/// A factory interface to spawn NAPS2.Worker.exe instances as needed.
|
||||
/// </summary>
|
||||
public interface IWorkerFactory : IDisposable
|
||||
internal interface IWorkerFactory : IDisposable
|
||||
{
|
||||
void Init(ScanningContext scanningContext, WorkerFactoryInitOptions? options = null);
|
||||
WorkerContext Create(ScanningContext scanningContext, WorkerType workerType);
|
||||
|
@ -7,7 +7,7 @@ namespace NAPS2.Remoting.Worker;
|
||||
/// <summary>
|
||||
/// A class storing the objects the client needs to use a NAPS2.Worker.exe instance.
|
||||
/// </summary>
|
||||
public class WorkerContext : IDisposable
|
||||
internal class WorkerContext : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeout after attempting to normally stop a worker before it is killed.
|
||||
|
@ -9,12 +9,10 @@ namespace NAPS2.Remoting.Worker;
|
||||
/// <summary>
|
||||
/// A class to manage the lifecycle of worker processes and hook up the named pipe channels.
|
||||
/// </summary>
|
||||
public class WorkerFactory : IWorkerFactory
|
||||
internal class WorkerFactory : IWorkerFactory
|
||||
{
|
||||
public const string PIPE_NAME_FORMAT = "NAPS2.Worker.{0}";
|
||||
|
||||
private readonly string _nativeWorkerExePath;
|
||||
private readonly string? _winX86WorkerExePath;
|
||||
private const int TAKE_WORKER_TIMEOUT = 10_000;
|
||||
private readonly Dictionary<string, string> _environmentVariables;
|
||||
|
||||
private Dictionary<WorkerType, BlockingCollection<WorkerContext>>? _workerQueues;
|
||||
@ -53,24 +51,27 @@ public class WorkerFactory : IWorkerFactory
|
||||
public WorkerFactory(string nativeWorkerExePath, string? winX86WorkerExePath = null,
|
||||
Dictionary<string, string>? environmentVariables = null)
|
||||
{
|
||||
_nativeWorkerExePath = nativeWorkerExePath;
|
||||
_winX86WorkerExePath = winX86WorkerExePath;
|
||||
NativeWorkerExePath = nativeWorkerExePath;
|
||||
WinX86WorkerExePath = winX86WorkerExePath;
|
||||
_environmentVariables = environmentVariables ?? new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public string NativeWorkerExePath { get; }
|
||||
public string? WinX86WorkerExePath { get; }
|
||||
|
||||
private Process StartWorkerProcess(WorkerType workerType)
|
||||
{
|
||||
var parentId = Process.GetCurrentProcess().Id;
|
||||
ProcessStartInfo startInfo;
|
||||
if (workerType == WorkerType.WinX86)
|
||||
{
|
||||
if (!PlatformCompat.System.SupportsWinX86Worker || _winX86WorkerExePath == null)
|
||||
if (!PlatformCompat.System.SupportsWinX86Worker || WinX86WorkerExePath == null)
|
||||
{
|
||||
throw new InvalidOperationException("Unexpected worker configuration");
|
||||
}
|
||||
startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = _winX86WorkerExePath,
|
||||
FileName = WinX86WorkerExePath,
|
||||
Arguments = $"{parentId}",
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
@ -81,7 +82,7 @@ public class WorkerFactory : IWorkerFactory
|
||||
{
|
||||
startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = _nativeWorkerExePath,
|
||||
FileName = NativeWorkerExePath,
|
||||
Arguments = $"worker {parentId}",
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
@ -150,18 +151,22 @@ public class WorkerFactory : IWorkerFactory
|
||||
private WorkerContext NextWorker(ScanningContext scanningContext, WorkerType workerType)
|
||||
{
|
||||
StartWorkerService(scanningContext, workerType);
|
||||
return _workerQueues![workerType]!.Take();
|
||||
if (!_workerQueues![workerType]!.TryTake(out var worker, TAKE_WORKER_TIMEOUT))
|
||||
{
|
||||
throw new InvalidOperationException("Could not start a worker process; see logs for details");
|
||||
}
|
||||
return worker;
|
||||
}
|
||||
|
||||
public void Init(ScanningContext scanningContext, WorkerFactoryInitOptions? options)
|
||||
public void Init(ScanningContext scanningContext, WorkerFactoryInitOptions? options = null)
|
||||
{
|
||||
if (!File.Exists(_nativeWorkerExePath))
|
||||
if (!File.Exists(NativeWorkerExePath))
|
||||
{
|
||||
scanningContext.Logger.LogDebug($"Native worker exe does not exist: {_nativeWorkerExePath}");
|
||||
scanningContext.Logger.LogDebug($"Native worker exe does not exist: {NativeWorkerExePath}");
|
||||
}
|
||||
if (_winX86WorkerExePath != null && !File.Exists(_winX86WorkerExePath))
|
||||
if (WinX86WorkerExePath != null && !File.Exists(WinX86WorkerExePath))
|
||||
{
|
||||
scanningContext.Logger.LogDebug($"WinX86 worker exe does not exist: {_winX86WorkerExePath}");
|
||||
scanningContext.Logger.LogDebug($"WinX86 worker exe does not exist: {WinX86WorkerExePath}");
|
||||
}
|
||||
|
||||
options ??= new WorkerFactoryInitOptions();
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace NAPS2.Remoting.Worker;
|
||||
|
||||
public class WorkerFactoryInitOptions
|
||||
internal class WorkerFactoryInitOptions
|
||||
{
|
||||
public bool StartSpareWorkers { get; set; } = true;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
namespace NAPS2.Remoting.Worker;
|
||||
|
||||
public enum WorkerType
|
||||
internal enum WorkerType
|
||||
{
|
||||
Native,
|
||||
WinX86
|
||||
|
@ -45,7 +45,7 @@ public class ScanningContext : IDisposable
|
||||
/// Gets or sets the context's WorkerFactory. This is required for some operations that need to happen in a worker
|
||||
/// process (e.g. to scan with 32-bit TWAIN from a 64-bit process).
|
||||
/// </summary>
|
||||
public IWorkerFactory? WorkerFactory { get; set; }
|
||||
internal IWorkerFactory? WorkerFactory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the context's OcrEngine. This is used to perform the OCR (optical character recognition) operation
|
||||
|
18
NAPS2.Sdk/Scan/ScanningContextExtensions.cs
Normal file
18
NAPS2.Sdk/Scan/ScanningContextExtensions.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using NAPS2.Remoting.Worker;
|
||||
|
||||
namespace NAPS2.Scan;
|
||||
|
||||
public static class ScanningContextExtensions
|
||||
{
|
||||
public static void SetUpWin32Worker(this ScanningContext scanningContext)
|
||||
{
|
||||
var workerFactory = WorkerFactory.CreateDefault();
|
||||
if (!File.Exists(workerFactory.WinX86WorkerExePath))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Could not find NAPS2.Worker.exe; have you installed the NAPS2.Sdk.Worker.Win32 Nuget package?");
|
||||
}
|
||||
workerFactory.Init(scanningContext);
|
||||
scanningContext.WorkerFactory = workerFactory;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user