mirror of
https://github.com/soukoku/ntwain.git
synced 2025-09-19 18:27:56 +08:00
Start experimenting with configuration builder-type initialization.
This commit is contained in:
76
src/NTwain/Data/TwainState.cs
Normal file
76
src/NTwain/Data/TwainState.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NTwain.Data
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The logical state of a TWAIN session.
|
||||||
|
/// </summary>
|
||||||
|
public enum TwainState
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Just a default value.
|
||||||
|
/// </summary>
|
||||||
|
Invalid = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// The starting state, nothing loaded.
|
||||||
|
/// </summary>
|
||||||
|
S1 = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// The DSM library has been loaded.
|
||||||
|
/// </summary>
|
||||||
|
S2 = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// The DSM has been opened.
|
||||||
|
/// </summary>
|
||||||
|
S3 = 3,
|
||||||
|
/// <summary>
|
||||||
|
/// A data source has been opened, ready for configuration.
|
||||||
|
/// </summary>
|
||||||
|
S4 = 4,
|
||||||
|
/// <summary>
|
||||||
|
/// A data source has been enabled, GUI up or waiting to transfer first image.
|
||||||
|
/// </summary>
|
||||||
|
S5 = 5,
|
||||||
|
/// <summary>
|
||||||
|
/// Data is ready for transfer from the source.
|
||||||
|
/// </summary>
|
||||||
|
S6 = 6,
|
||||||
|
/// <summary>
|
||||||
|
/// Data is being transferred.
|
||||||
|
/// </summary>
|
||||||
|
S7 = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The starting state, nothing loaded.
|
||||||
|
/// </summary>
|
||||||
|
DsmUnloaded = S1,
|
||||||
|
/// <summary>
|
||||||
|
/// The DSM library has been loaded.
|
||||||
|
/// </summary>
|
||||||
|
DsmLoaded = S2,
|
||||||
|
/// <summary>
|
||||||
|
/// The DSM has been opened.
|
||||||
|
/// </summary>
|
||||||
|
DsmOpened = S3,
|
||||||
|
/// <summary>
|
||||||
|
/// A data source has been opened, ready for configuration.
|
||||||
|
/// </summary>
|
||||||
|
SourceOpened = S4,
|
||||||
|
/// <summary>
|
||||||
|
/// A data source has been enabled, GUI up or waiting to transfer first image.
|
||||||
|
/// </summary>
|
||||||
|
SourceEnabled = S5,
|
||||||
|
/// <summary>
|
||||||
|
/// Data is ready for transfer from the source.
|
||||||
|
/// </summary>
|
||||||
|
TransferReady = S6,
|
||||||
|
/// <summary>
|
||||||
|
/// Data is being transferred.
|
||||||
|
/// </summary>
|
||||||
|
Transferring = S7
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
src/NTwain/Internals/IMemoryManager.cs
Normal file
39
src/NTwain/Internals/IMemoryManager.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NTwain.Internals
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface that provides the correct methods for managing memory on data exchanged with TWAIN sources.
|
||||||
|
/// </summary>
|
||||||
|
interface IMemoryManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Function to allocate memory. Calls to this must be coupled with <see cref="Free"/> later.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">The size in bytes.</param>
|
||||||
|
/// <returns>Handle to the allocated memory.</returns>
|
||||||
|
IntPtr Allocate(uint size);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Function to free memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle from <see cref="Allocate"/>.</param>
|
||||||
|
void Free(IntPtr handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Function to lock some memory. Calls to this must be coupled with <see cref="Unlock"/> later.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle to allocated memory.</param>
|
||||||
|
/// <returns>Handle to the lock.</returns>
|
||||||
|
IntPtr Lock(IntPtr handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Function to unlock a previously locked memory region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The same handle passed <see cref="Lock"/>.</param>
|
||||||
|
void Unlock(IntPtr handle);
|
||||||
|
}
|
||||||
|
}
|
37
src/NTwain/Internals/LinuxMemoryManager.cs
Normal file
37
src/NTwain/Internals/LinuxMemoryManager.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NTwain.Internals
|
||||||
|
{
|
||||||
|
// probably wrong
|
||||||
|
|
||||||
|
class LinuxMemoryManager : IMemoryManager
|
||||||
|
{
|
||||||
|
#region IMemoryManager Members
|
||||||
|
|
||||||
|
public IntPtr Allocate(uint size)
|
||||||
|
{
|
||||||
|
return Marshal.AllocHGlobal((int)size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free(IntPtr handle)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr Lock(IntPtr handle)
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unlock(IntPtr handle)
|
||||||
|
{
|
||||||
|
// no op
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
61
src/NTwain/Internals/WinMemoryManager.cs
Normal file
61
src/NTwain/Internals/WinMemoryManager.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
|
namespace NTwain.Internals
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods for managing memory on data exchanged with twain sources using old win32 methods.
|
||||||
|
/// </summary>
|
||||||
|
class WinMemoryManager : IMemoryManager
|
||||||
|
{
|
||||||
|
public IntPtr Allocate(uint size)
|
||||||
|
{
|
||||||
|
IntPtr retVal = UnsafeNativeMethods.WinGlobalAlloc(0x0040, new UIntPtr(size));
|
||||||
|
|
||||||
|
if (retVal == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new Win32Exception();
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free(IntPtr handle)
|
||||||
|
{
|
||||||
|
UnsafeNativeMethods.WinGlobalFree(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr Lock(IntPtr handle)
|
||||||
|
{
|
||||||
|
return UnsafeNativeMethods.WinGlobalLock(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unlock(IntPtr handle)
|
||||||
|
{
|
||||||
|
UnsafeNativeMethods.WinGlobalUnlock(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[SuppressUnmanagedCodeSecurity]
|
||||||
|
static class UnsafeNativeMethods
|
||||||
|
{
|
||||||
|
#region mem stuff for twain 1.x
|
||||||
|
|
||||||
|
[DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalAlloc")]
|
||||||
|
internal static extern IntPtr WinGlobalAlloc(uint uFlags, UIntPtr dwBytes);
|
||||||
|
|
||||||
|
[DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalFree")]
|
||||||
|
internal static extern IntPtr WinGlobalFree(IntPtr hMem);
|
||||||
|
|
||||||
|
[DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalLock")]
|
||||||
|
internal static extern IntPtr WinGlobalLock(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport("kernel32", SetLastError = true, EntryPoint = "GlobalUnlock")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool WinGlobalUnlock(IntPtr handle);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
src/NTwain/TwainConfig.cs
Normal file
113
src/NTwain/TwainConfig.cs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
using NTwain.Data;
|
||||||
|
using NTwain.Internals;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NTwain
|
||||||
|
{
|
||||||
|
public class TwainConfig
|
||||||
|
{
|
||||||
|
internal TwainConfig() { }
|
||||||
|
|
||||||
|
public bool PreferLegacyDsm { get; internal set; }
|
||||||
|
|
||||||
|
public string AppName { get; internal set; }
|
||||||
|
|
||||||
|
internal DataGroups DataGroup { get; set; }
|
||||||
|
internal IMemoryManager MemoryManager { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TwainConfigurationBuilder
|
||||||
|
{
|
||||||
|
private bool _legacy;
|
||||||
|
private string _appName;
|
||||||
|
private string _companyName;
|
||||||
|
private DataGroups _dg = DataGroups.Image;
|
||||||
|
private bool _64bit;
|
||||||
|
private PlatformID _platform;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default ctor.
|
||||||
|
/// </summary>
|
||||||
|
public TwainConfigurationBuilder()
|
||||||
|
{
|
||||||
|
_64bit = IntPtr.Size == 8;
|
||||||
|
_platform = Environment.OSVersion.Platform;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies which DSM to use.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="legacyDsm"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public TwainConfigurationBuilder UseDsm(bool legacyDsm = false)
|
||||||
|
{
|
||||||
|
if (legacyDsm)
|
||||||
|
{
|
||||||
|
if (_64bit) throw new InvalidOperationException("Cannot use legacy DSM under 64bit.");
|
||||||
|
}
|
||||||
|
_legacy = legacyDsm;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies what kind of data the app can to handle from TWAIN devices.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image"></param>
|
||||||
|
/// <param name="audio"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public TwainConfigurationBuilder HandlesDataType(bool image = true, bool audio = false)
|
||||||
|
{
|
||||||
|
DataGroups dg = DataGroups.None;
|
||||||
|
if (image) dg |= DataGroups.Image;
|
||||||
|
if (audio) dg |= DataGroups.Audio;
|
||||||
|
|
||||||
|
if (dg == DataGroups.None) throw new InvalidOperationException("No data type specified.");
|
||||||
|
_dg = dg;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the app info that will interface with TWAIN.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="appName"></param>
|
||||||
|
/// <param name="companyName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public TwainConfigurationBuilder DefineApp(string appName, string companyName = null)
|
||||||
|
{
|
||||||
|
_appName = appName;
|
||||||
|
_companyName = companyName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the app info that will interface with TWAIN.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="appAssembly">Assembly containing the app info.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public TwainConfigurationBuilder DefineApp(Assembly appAssembly)
|
||||||
|
{
|
||||||
|
var info = FileVersionInfo.GetVersionInfo(appAssembly.Location);
|
||||||
|
return DefineApp(info.ProductName, info.CompanyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the final configuration object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public TwainConfig Build()
|
||||||
|
{
|
||||||
|
return new TwainConfig
|
||||||
|
{
|
||||||
|
PreferLegacyDsm = _legacy,
|
||||||
|
AppName = _appName,
|
||||||
|
DataGroup = _dg
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
src/NTwain/TwainSession.cs
Normal file
93
src/NTwain/TwainSession.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using NTwain.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NTwain
|
||||||
|
{
|
||||||
|
public class TwainSession : INotifyPropertyChanged, IDisposable
|
||||||
|
{
|
||||||
|
private TwainConfig _config;
|
||||||
|
public TwainSession(TwainConfig config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
var rc = Open();
|
||||||
|
if (rc != ReturnCode.Success)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TwainState _state;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the logical state of the session.
|
||||||
|
/// </summary>
|
||||||
|
public TwainState State
|
||||||
|
{
|
||||||
|
get { return _state; }
|
||||||
|
internal set
|
||||||
|
{
|
||||||
|
_state = value;
|
||||||
|
RaisePropertyChanged(nameof(State));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
void RaisePropertyChanged(string property)
|
||||||
|
{
|
||||||
|
var handle = PropertyChanged;
|
||||||
|
handle?.Invoke(this, new PropertyChangedEventArgs(property));
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnCode Open()
|
||||||
|
{
|
||||||
|
if (State < TwainState.DsmOpened)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnCode StepDown(TwainState targetState)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDisposable Support
|
||||||
|
private bool disposedValue = false; // To detect redundant calls
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposedValue)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
StepDown(TwainState.DsmLoaded);
|
||||||
|
// TODO: dispose managed state (managed objects).
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
|
||||||
|
// TODO: set large fields to null.
|
||||||
|
|
||||||
|
disposedValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
|
||||||
|
// ~TwainSession() {
|
||||||
|
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||||
|
// Dispose(false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// This code added to correctly implement the disposable pattern.
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
// TODO: uncomment the following line if the finalizer is overridden above.
|
||||||
|
// GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user