diff --git a/NTwain.sln b/NTwain.sln
index f111ee3..ee6934e 100644
--- a/NTwain.sln
+++ b/NTwain.sln
@@ -17,6 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Others", "Others", "{4CE0B9
ProjectSection(SolutionItems) = preProject
LICENSE.txt = LICENSE.txt
README.markdown = README.markdown
+ Spec\twain2.3.h = Spec\twain2.3.h
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tester.Console", "Tests\Tester.Console\Tester.Console.csproj", "{12D761EF-68DF-41CE-92EF-0C7AE81857A3}"
diff --git a/NTwain/Data/Types.cs b/NTwain/Data/Types.cs
index b45743c..1217236 100644
--- a/NTwain/Data/Types.cs
+++ b/NTwain/Data/Types.cs
@@ -8,10 +8,9 @@ using NTwain.Values;
// to aid in mapping against the twain.h file using copy-paste.
// Consumers will not see those names.
-#if WIN32
// use HandleRef instead?
-using TW_HANDLE = System.IntPtr; // HANDLE
+using TW_HANDLE = System.IntPtr; // HANDLE, todo: should really be uintptr?
using TW_MEMREF = System.IntPtr; // LPVOID
// iffy
using TW_UINTPTR = System.UIntPtr; // UINT_PTR
@@ -26,12 +25,6 @@ using TW_UINT32 = System.UInt32; // unsigned long
using TW_BOOL = System.UInt16; // unsigned short
-#elif GNUC
-
-#elif APPLE
-
-#endif
-
// This mono doc is awesome. An interop must-read
@@ -101,6 +94,7 @@ namespace NTwain.Data
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String255)]
string _name;
+
TW_UINT32 _reserved;
}
@@ -152,6 +146,7 @@ namespace NTwain.Data
TWCiePoint _blackPoint;
TWCiePoint _whitePaper;
TWCiePoint _blackInk;
+
// TODO: may be totally wrong
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
TWFix32[] _samples;
@@ -169,8 +164,10 @@ namespace NTwain.Data
partial class TWDeviceEvent
{
TW_UINT32 _event;
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String255)]
string _deviceName;
+
TW_UINT32 _batteryMinutes;
TW_INT16 _batteryPercentage;
TW_INT32 _powerSupply;
@@ -214,9 +211,7 @@ namespace NTwain.Data
TW_UINT16 _infoID;
TW_UINT16 _itemType;
TW_UINT16 _numItems;
-
TW_UINT16 _returnCode;
-
TW_UINTPTR _item;
}
@@ -224,6 +219,7 @@ namespace NTwain.Data
partial class TWExtImageInfo
{
TW_UINT32 _numInfos;
+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 200)]
TWInfo[] _info;
}
@@ -232,54 +228,29 @@ namespace NTwain.Data
BestFitMapping(false, ThrowOnUnmappableChar = true)]
partial class TWFileSystem
{
- //[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String255)]
string _inputName;
-
- //[FieldOffset(TwainConst.String255)]
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String255)]
string _outputName;
- //[FieldOffset(512)]
TW_MEMREF _context;
-
- //[FieldOffset(520)]
- //short _recursive;
- //[FieldOffset(520)]
TW_BOOL _subdirectories;
-
- //[FieldOffset(524)]
TW_INT32 _fileType;
- //[FieldOffset(524)]
- //TW_UINT32 _fileSystemType;
-
- //[FieldOffset(528)]
TW_UINT32 _size;
- //[FieldOffset(532)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String32)]
string _createTimeDate;
- //[FieldOffset(566)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String32)]
string _modifiedTimeDate;
- //[FieldOffset(600)]
TW_UINT32 _freeSpace;
-
- //[FieldOffset(604)]
TW_INT32 _newImageSize;
-
- //[FieldOffset(608)]
TW_UINT32 _numberOfFiles;
-
- //[FieldOffset(612)]
TW_UINT32 _numberOfSnippets;
-
- //[FieldOffset(616)]
TW_UINT32 _deviceGroupMask;
- //[FieldOffset(620)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 508)]
TW_INT8[] _reserved;
}
@@ -300,6 +271,7 @@ namespace NTwain.Data
TW_UINT16 _minorNum;
TW_UINT16 _language;
TW_UINT16 _country;
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String32)]
string _info;
}
@@ -313,10 +285,13 @@ namespace NTwain.Data
TW_UINT16 _protocolMajor;
TW_UINT16 _protocolMinor;
TW_UINT32 _supportedGroups;
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String32)]
string _manufacturer;
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String32)]
string _productFamily;
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String32)]
string _productName;
}
@@ -329,8 +304,10 @@ namespace NTwain.Data
TW_INT32 _imageWidth;
TW_INT32 _imageLength;
TW_INT16 _samplesPerPixel;
+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
TW_INT16[] _bitsPerSample;
+
TW_INT16 _bitsPerPixel;
TW_BOOL _planar;
TW_INT16 _pixelType;
@@ -349,7 +326,7 @@ namespace NTwain.Data
[StructLayout(LayoutKind.Sequential, Pack = 2)]
partial struct TWMemory
{
- // not a class due to embedded
+ // not a class due to being embedded next
TW_UINT32 _flags;
TW_UINT32 _length;
@@ -405,6 +382,7 @@ namespace NTwain.Data
{
TW_UINT16 _numColors;
TW_UINT16 _paletteType;
+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
TWElement8[] _colors;
}
@@ -420,18 +398,11 @@ namespace NTwain.Data
TW_UINT32 _dataBytesXfered;
}
- //[StructLayout(LayoutKind.Explicit, Pack = 2)]
[StructLayout(LayoutKind.Sequential, Pack = 2)]
partial class TWPendingXfers
{
- //[FieldOffset(0)]
- //TW_INT16 _count;
TW_UINT16 _count;
-
- //[FieldOffset(2)]
TW_UINT32 _eOJ;
- //[FieldOffset(2)]
- //TW_UINT32 _reserved;
}
@@ -459,6 +430,7 @@ namespace NTwain.Data
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = TwainConst.String255)]
string _fileName;
+
TW_UINT16 _format;
TW_INT16 _vRefNum = -1;
}
@@ -474,13 +446,8 @@ namespace NTwain.Data
[StructLayout(LayoutKind.Sequential, Pack = 2)]
partial class TWStatus
{
- //[FieldOffset(0)]
TW_UINT16 _conditionCode;
- //[FieldOffset(2)]
TW_UINT16 _data;
- //[FieldOffset(2)]
- //TW_UINT16 _reserved;
-
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
@@ -491,9 +458,7 @@ namespace NTwain.Data
// definition remember to change it here
TW_UINT16 _conditionCode;
TW_UINT16 _data;
-
TW_UINT32 _size;
-
TW_HANDLE _uTF8string;
}
@@ -503,7 +468,6 @@ namespace NTwain.Data
TW_BOOL _showUI;
TW_BOOL _modalUI;
TW_HANDLE _hParent;
- //HandleRef _hParent;
}
delegate ReturnCode CallbackDelegate(TWIdentity origin, TWIdentity destination,
@@ -525,10 +489,10 @@ namespace NTwain.Data
[MarshalAs(UnmanagedType.FunctionPtr)]
MemUnlockDelegate _dSM_MemUnlock;
- public delegate IntPtr MemAllocateDelegate(uint size);
- public delegate void MemFreeDelegate(IntPtr handle);
- public delegate IntPtr MemLockDelegate(IntPtr handle);
- public delegate void MemUnlockDelegate(IntPtr handle);
+ public delegate TW_HANDLE MemAllocateDelegate(TW_UINT32 size);
+ public delegate void MemFreeDelegate(TW_HANDLE handle);
+ public delegate TW_MEMREF MemLockDelegate(TW_HANDLE handle);
+ public delegate void MemUnlockDelegate(TW_HANDLE handle);
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
diff --git a/NTwain/Data/TypesExtended.cs b/NTwain/Data/TypesExtended.cs
index 39096ec..8e49909 100644
--- a/NTwain/Data/TypesExtended.cs
+++ b/NTwain/Data/TypesExtended.cs
@@ -890,12 +890,18 @@ namespace NTwain.Data
///
public void Dispose()
{
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ void Dispose(bool disposing)
+ {
+ if (disposing) { }
if (_hContainer != IntPtr.Zero)
{
MemoryManager.Instance.Free(_hContainer);
_hContainer = IntPtr.Zero;
}
- GC.SuppressFinalize(this);
}
///
@@ -903,11 +909,7 @@ namespace NTwain.Data
///
~TWCapability()
{
- if (_hContainer != IntPtr.Zero)
- {
- MemoryManager.Instance.Free(_hContainer);
- _hContainer = IntPtr.Zero;
- }
+ Dispose(false);
}
#endregion
}
@@ -1296,15 +1298,15 @@ namespace NTwain.Data
///
/// Tag identifying an information.
///
- public ushort InfoID { get { return _infoID; } set { _infoID = value; } }
+ public ushort InfoID { get { return _infoID; } }
///
/// Item data type.
///
- public ItemType ItemType { get { return (ItemType)_itemType; } set { _itemType = (ushort)value; } }
+ public ItemType ItemType { get { return (ItemType)_itemType; } }
///
/// Number of items.
///
- public ushort NumItems { get { return _numItems; } set { _numItems = value; } }
+ public ushort NumItems { get { return _numItems; } }
///
/// This is the return code of availability of data for extended image attribute requested.
@@ -1312,18 +1314,18 @@ namespace NTwain.Data
///
/// The return code.
///
- public ReturnCode ReturnCode { get { return (ReturnCode)_returnCode; } set { _returnCode = (ushort)value; } }
+ public ReturnCode ReturnCode { get { return (ReturnCode)_returnCode; } }
///
/// Contains either data or a handle to data. The field
/// contains data if the total amount of data is less than or equal to four bytes. The
- /// field contains a handle of the total amount of data is more than four bytes.
+ /// field contains a handle if the total amount of data is more than four bytes.
/// The amount of data is determined by multiplying NumItems times
/// the byte size of the data type specified by ItemType.
/// If the Item field contains a handle to data, then the Application is
/// responsible for freeing that memory.
///
- public UIntPtr Item { get { return _item; } set { _item = value; } }
+ public UIntPtr Item { get { return _item; } }
}
///
@@ -1334,7 +1336,7 @@ namespace NTwain.Data
/// using the above operation triplet. The data source then examines each Info, and fills the rest of
/// data with information allocating memory when necessary.
///
- public partial class TWExtImageInfo
+ public sealed partial class TWExtImageInfo : IDisposable
{
///
/// Number of information that application is requesting. This is filled by the
@@ -1342,11 +1344,47 @@ namespace NTwain.Data
/// image information. The application should allocate memory and fill in the
/// attribute tag for image information.
///
- public uint NumInfos { get { return _numInfos; } set { _numInfos = value; } }
+ public uint NumInfos { get { return _numInfos; } }
///
/// Array of information.
///
- public TWInfo[] Info { get { return _info; } set { _info = value; } }
+ public TWInfo[] Info { get { return _info; } }
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (disposing) { }
+ // this is iffy & may have to flatten info array as individual fields in this class to work
+ if (_info != null)
+ {
+ foreach (var i in _info)
+ {
+ if (i.Item != UIntPtr.Zero)
+ {
+ var sz = i.NumItems * CapReadOut.GetItemTypeSize(i.ItemType);
+ if (sz > UIntPtr.Size || i.ItemType == ItemType.Handle)
+ {
+ // uintptr to intptr could be bad
+ var ptr = new IntPtr(BitConverter.ToInt64(BitConverter.GetBytes(i.Item.ToUInt64()), 0));
+ MemoryManager.Instance.Free(ptr);
+ }
+ }
+ }
+ }
+ }
+
+ ~TWExtImageInfo()
+ {
+ Dispose(false);
+ }
+ #endregion
}
///
@@ -1374,7 +1412,7 @@ namespace NTwain.Data
/// sub-directories in the directory being copied.
///
public bool Recursive { get { return _subdirectories == TwainConst.True; } set { _subdirectories = value ? TwainConst.True : TwainConst.False; } }
-
+
///
/// Gets the type of the file.
///
@@ -1382,7 +1420,7 @@ namespace NTwain.Data
/// The type of the file.
///
public FileType FileType { get { return (FileType)_fileType; } set { _fileType = (int)value; } }
-
+
///
/// If , total size of media in bytes.
/// If , size of image in bytes.
@@ -2155,7 +2193,7 @@ namespace NTwain.Data
/// Translates the contents of Status into a localized UTF8string, with the total number of bytes
/// in the string.
///
- public partial class TWStatusUtf8
+ public sealed partial class TWStatusUtf8 : IDisposable
{
///
/// data received from a previous call.
@@ -2163,24 +2201,69 @@ namespace NTwain.Data
public TWStatus Status
{
get { return new TWStatus { ConditionCode = (ConditionCode)_conditionCode, Data = _data }; }
- set
- {
- _conditionCode = (ushort)value.ConditionCode;
- _data = value.Data;
- }
}
///
/// Total number of bytes in the UTF8string, plus the terminating NULL byte.
/// This is not the same as the total number of characters in the string.
///
- public uint Size { get { return _size; } set { _size = value; } }
+ public int Size { get { return (int)_size; } }
+
///
/// TW_HANDLE to a UTF-8 encoded localized string (based on
/// TwIdentity.Language or CapLanguage). The Source allocates
/// it, the Application frees it.
///
- IntPtr UTF8string { get { return _uTF8string; } set { _uTF8string = value; } }
+ IntPtr UTF8StringPtr { get { return _uTF8string; } }
+
+ ///
+ /// Gets the actual string from the pointer.
+ ///
+ ///
+ public string GetActualString()
+ {
+ if (_uTF8string != IntPtr.Zero)
+ {
+ var sb = new StringBuilder(Size - 1);
+ byte bt;
+ while (sb.Length < _size &&
+ (bt = Marshal.ReadByte(_uTF8string, sb.Length)) != 0)
+ {
+ sb.Append((char)bt);
+ }
+ return sb.ToString();
+ }
+ return null;
+ }
+
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+
+ }
+ if (_uTF8string != IntPtr.Zero)
+ {
+ MemoryManager.Instance.Free(_uTF8string);
+ _uTF8string = IntPtr.Zero;
+ }
+ }
+
+ ~TWStatusUtf8()
+ {
+ Dispose(false);
+ }
+
+ #endregion
}