mirror of
https://github.com/soukoku/ntwain.git
synced 2025-09-19 18:27:56 +08:00
Added value writer with type detection.
This commit is contained in:
@@ -34,7 +34,7 @@ namespace NTwain
|
|||||||
public TW_CAPABILITY Generate<T>(CapabilityId cap, ItemType type, T value)
|
public TW_CAPABILITY Generate<T>(CapabilityId cap, ItemType type, T value)
|
||||||
{
|
{
|
||||||
// size of data + uint16 item type
|
// size of data + uint16 item type
|
||||||
var valueSz = type.GetSize();
|
var valueSz = type.GetByteSize();
|
||||||
if (valueSz < 4) valueSz = 4; // onevalue container value minimum is 32bit
|
if (valueSz < 4) valueSz = 4; // onevalue container value minimum is 32bit
|
||||||
var memSz = valueSz + 2; // + item type field
|
var memSz = valueSz + 2; // + item type field
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
// TODO: type size may be different on mac
|
// TODO: type size may be different on mac
|
||||||
baseAddr.WriteValue(ref offset, ItemType.UInt16, value);
|
baseAddr.WriteValue(ref offset, type, ItemType.UInt16);
|
||||||
// ONEVALUE is special in value can be uint32 or string
|
// ONEVALUE is special in value can be uint32 or string
|
||||||
// if less than uint32 put it in lower word
|
// if less than uint32 put it in lower word
|
||||||
// (string value seems undocumented but internet says put it as-is and not a pointer)
|
// (string value seems undocumented but internet says put it as-is and not a pointer)
|
||||||
@@ -61,7 +61,7 @@ namespace NTwain
|
|||||||
Marshal.WriteInt16(baseAddr, offset, 0);
|
Marshal.WriteInt16(baseAddr, offset, 0);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
}
|
}
|
||||||
baseAddr.WriteValue(ref offset, type, value);
|
baseAddr.WriteValue(ref offset, value, type);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -90,7 +90,7 @@ namespace NTwain
|
|||||||
};
|
};
|
||||||
if (twCap.hContainer != IntPtr.Zero)
|
if (twCap.hContainer != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
var listSz = value.Type.GetSize() * value.ItemList.Length;
|
var listSz = value.Type.GetByteSize() * value.ItemList.Length;
|
||||||
TW_ARRAY container = new TW_ARRAY
|
TW_ARRAY container = new TW_ARRAY
|
||||||
{
|
{
|
||||||
ItemType = (ushort)value.Type,
|
ItemType = (ushort)value.Type,
|
||||||
@@ -105,7 +105,7 @@ namespace NTwain
|
|||||||
int offset = 0;
|
int offset = 0;
|
||||||
foreach (var it in value.ItemList)
|
foreach (var it in value.ItemList)
|
||||||
{
|
{
|
||||||
baseAddr.WriteValue(ref offset, value.Type, it);
|
baseAddr.WriteValue(ref offset, it, value.Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -149,7 +149,7 @@ namespace NTwain
|
|||||||
};
|
};
|
||||||
if (twCap.hContainer != IntPtr.Zero)
|
if (twCap.hContainer != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
var listSz = value.Type.GetSize() * value.ItemList.Length;
|
var listSz = value.Type.GetByteSize() * value.ItemList.Length;
|
||||||
TW_ENUMERATION container = new TW_ENUMERATION
|
TW_ENUMERATION container = new TW_ENUMERATION
|
||||||
{
|
{
|
||||||
ItemType = (ushort)value.Type,
|
ItemType = (ushort)value.Type,
|
||||||
@@ -166,7 +166,7 @@ namespace NTwain
|
|||||||
int offset = 0;
|
int offset = 0;
|
||||||
foreach (var it in value.ItemList)
|
foreach (var it in value.ItemList)
|
||||||
{
|
{
|
||||||
baseAddr.WriteValue(ref offset, value.Type, it);
|
baseAddr.WriteValue(ref offset, it, value.Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using NTwain.Resources;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -13,7 +14,7 @@ namespace NTwain.Data
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static class TypeExtensions
|
static class TypeExtensions
|
||||||
{
|
{
|
||||||
static readonly Dictionary<ItemType, int> _sizes = new Dictionary<ItemType, int>
|
static readonly Dictionary<ItemType, int> _twainBytes = new Dictionary<ItemType, int>
|
||||||
{
|
{
|
||||||
{ ItemType.Int8, 1 },
|
{ ItemType.Int8, 1 },
|
||||||
{ ItemType.UInt8, 1 },
|
{ ItemType.UInt8, 1 },
|
||||||
@@ -28,44 +29,108 @@ namespace NTwain.Data
|
|||||||
{ ItemType.String255, TwainConst.String255 },
|
{ ItemType.String255, TwainConst.String255 },
|
||||||
{ ItemType.String32, TwainConst.String32 },
|
{ ItemType.String32, TwainConst.String32 },
|
||||||
{ ItemType.String64, TwainConst.String64 },
|
{ ItemType.String64, TwainConst.String64 },
|
||||||
// TODO: find out if it should be fixed 4 bytes or intptr size
|
|
||||||
{ ItemType.Handle, IntPtr.Size },
|
{ ItemType.Handle, IntPtr.Size },
|
||||||
};
|
};
|
||||||
|
static readonly Dictionary<Type, ItemType> _netToTwainTypes = new Dictionary<Type, ItemType>
|
||||||
public static int GetSize(this ItemType type)
|
|
||||||
{
|
{
|
||||||
if(_sizes.TryGetValue(type, out int size)) return size;
|
{ typeof(sbyte), ItemType.Int8 },
|
||||||
|
{ typeof(byte), ItemType.UInt8 },
|
||||||
|
{ typeof(short), ItemType.Int16 },
|
||||||
|
{ typeof(ushort), ItemType.UInt16 },
|
||||||
|
{ typeof(int), ItemType.Int32 },
|
||||||
|
{ typeof(uint), ItemType.UInt32 },
|
||||||
|
{ typeof(TW_FIX32), ItemType.Fix32 },
|
||||||
|
{ typeof(TW_FRAME), ItemType.Frame },
|
||||||
|
{ typeof(IntPtr), ItemType.Handle },
|
||||||
|
{ typeof(UIntPtr), ItemType.Handle },
|
||||||
|
};
|
||||||
|
|
||||||
throw new NotSupportedException($"Unsupported item type {type}.");
|
|
||||||
|
internal static int GetByteSize(this ItemType type)
|
||||||
|
{
|
||||||
|
if (_twainBytes.TryGetValue(type, out int size)) return size;
|
||||||
|
|
||||||
|
throw new NotSupportedException(string.Format(MsgText.TypeNotSupported, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region writes
|
#region writes
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes a TWAIN value.
|
/// Writes a TWAIN value with type detection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="baseAddr">The base addr.</param>
|
/// <param name="baseAddr">The base addr.</param>
|
||||||
/// <param name="offset">The offset.</param>
|
/// <param name="offset">The offset.</param>
|
||||||
/// <param name="type">The TWAIN type.</param>
|
|
||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
|
public static void WriteValue(this IntPtr baseAddr, ref int offset, object value)
|
||||||
public static void WriteValue(this IntPtr baseAddr, ref int offset, ItemType type, object value)
|
{
|
||||||
|
var rawType = value.GetType();
|
||||||
|
if (rawType.IsEnum)
|
||||||
|
{
|
||||||
|
// convert enum to numerical value
|
||||||
|
rawType = Enum.GetUnderlyingType(rawType);
|
||||||
|
value = Convert.ChangeType(value, rawType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (_netToTwainTypes.ContainsKey(rawType))
|
||||||
|
{
|
||||||
|
WriteValue(baseAddr, ref offset, value, _netToTwainTypes[rawType]);
|
||||||
|
}
|
||||||
|
else if (rawType == typeof(string))
|
||||||
|
{
|
||||||
|
var strVal = value.ToString();
|
||||||
|
if (strVal.Length <= 32)
|
||||||
|
{
|
||||||
|
WriteValue(baseAddr, ref offset, strVal, ItemType.String32);
|
||||||
|
}
|
||||||
|
else if (strVal.Length <= 64)
|
||||||
|
{
|
||||||
|
WriteValue(baseAddr, ref offset, strVal, ItemType.String64);
|
||||||
|
}
|
||||||
|
else if (strVal.Length <= 128)
|
||||||
|
{
|
||||||
|
WriteValue(baseAddr, ref offset, strVal, ItemType.String128);
|
||||||
|
}
|
||||||
|
else if (strVal.Length <= 255)
|
||||||
|
{
|
||||||
|
WriteValue(baseAddr, ref offset, strVal, ItemType.String255);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(string.Format(MsgText.MaxStringLengthExceeded, 255));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(string.Format(MsgText.TypeNotSupported, rawType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a TWAIN value as specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseAddr">The base addr.</param>
|
||||||
|
/// <param name="offset">The offset.</param>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <param name="type">The TWAIN type.</param>
|
||||||
|
public static void WriteValue(this IntPtr baseAddr, ref int offset, object value, ItemType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ItemType.Int8:
|
case ItemType.Int8:
|
||||||
case ItemType.UInt8:
|
case ItemType.UInt8:
|
||||||
Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value, CultureInfo.InvariantCulture));// (byte)value);
|
Marshal.WriteByte(baseAddr, offset, Convert.ToByte(value, CultureInfo.InvariantCulture));
|
||||||
break;
|
break;
|
||||||
case ItemType.Bool:
|
case ItemType.Bool:
|
||||||
case ItemType.Int16:
|
case ItemType.Int16:
|
||||||
case ItemType.UInt16:
|
case ItemType.UInt16:
|
||||||
Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value, CultureInfo.InvariantCulture));//(short)value);
|
Marshal.WriteInt16(baseAddr, offset, Convert.ToInt16(value, CultureInfo.InvariantCulture));
|
||||||
break;
|
break;
|
||||||
case ItemType.UInt32:
|
case ItemType.UInt32:
|
||||||
case ItemType.Int32:
|
case ItemType.Int32:
|
||||||
Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value, CultureInfo.InvariantCulture));//(int)value);
|
Marshal.WriteInt32(baseAddr, offset, Convert.ToInt32(value, CultureInfo.InvariantCulture));
|
||||||
break;
|
break;
|
||||||
case ItemType.Fix32:
|
case ItemType.Fix32:
|
||||||
TW_FIX32 f32 = (TW_FIX32)value;
|
TW_FIX32 f32 = (TW_FIX32)value;
|
||||||
@@ -81,6 +146,9 @@ namespace NTwain.Data
|
|||||||
//case ItemType.String1024:
|
//case ItemType.String1024:
|
||||||
// WriteString(baseAddr, offset, value as string, 1024);
|
// WriteString(baseAddr, offset, value as string, 1024);
|
||||||
// break;
|
// break;
|
||||||
|
case ItemType.Handle:
|
||||||
|
Marshal.WriteIntPtr(baseAddr, offset, (IntPtr)value);
|
||||||
|
break;
|
||||||
case ItemType.String128:
|
case ItemType.String128:
|
||||||
WriteString(baseAddr, offset, (string)value, 128);
|
WriteString(baseAddr, offset, (string)value, 128);
|
||||||
break;
|
break;
|
||||||
@@ -93,25 +161,33 @@ namespace NTwain.Data
|
|||||||
case ItemType.String64:
|
case ItemType.String64:
|
||||||
WriteString(baseAddr, offset, (string)value, 64);
|
WriteString(baseAddr, offset, (string)value, 64);
|
||||||
break;
|
break;
|
||||||
//case ItemType.Unicode512:
|
//case ItemType.Unicode512:
|
||||||
// WriteUString(baseAddr, offset, value as string, 512);
|
// WriteUString(baseAddr, offset, value as string, 512);
|
||||||
// break;
|
// break;
|
||||||
}
|
}
|
||||||
offset += type.GetSize();
|
offset += type.GetByteSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteFix32(IntPtr baseAddr, ref int offset, TW_FIX32 f32)
|
static void WriteFix32(IntPtr baseAddr, ref int offset, TW_FIX32 value)
|
||||||
{
|
{
|
||||||
Marshal.WriteInt16(baseAddr, offset, f32.Whole);
|
Marshal.WriteInt16(baseAddr, offset, value.Whole);
|
||||||
if (f32.Fraction > Int16.MaxValue)
|
offset += _twainBytes[ItemType.Int16];
|
||||||
|
if (value.Fraction > Int16.MaxValue)
|
||||||
{
|
{
|
||||||
Marshal.WriteInt16(baseAddr, offset + 2, (Int16)(f32.Fraction - 32768));
|
Marshal.WriteInt16(baseAddr, offset, (Int16)(value.Fraction - 32768));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Marshal.WriteInt16(baseAddr, offset + 2, (Int16)f32.Fraction);
|
Marshal.WriteInt16(baseAddr, offset, (Int16)value.Fraction);
|
||||||
}
|
}
|
||||||
offset += _sizes[ItemType.Fix32];
|
offset += _twainBytes[ItemType.Fix32];
|
||||||
|
}
|
||||||
|
static void WriteFrame(IntPtr baseAddr, ref int offset, TW_FRAME value)
|
||||||
|
{
|
||||||
|
WriteFix32(baseAddr, ref offset, value._left);
|
||||||
|
WriteFix32(baseAddr, ref offset, value._top);
|
||||||
|
WriteFix32(baseAddr, ref offset, value._right);
|
||||||
|
WriteFix32(baseAddr, ref offset, value._bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -123,6 +199,8 @@ namespace NTwain.Data
|
|||||||
/// <param name="maxLength"></param>
|
/// <param name="maxLength"></param>
|
||||||
static void WriteString(IntPtr baseAddr, int offset, string value, int maxLength)
|
static void WriteString(IntPtr baseAddr, int offset, string value, int maxLength)
|
||||||
{
|
{
|
||||||
|
// TODO: mac string is not null-terminated like this?
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
{
|
{
|
||||||
// write zero
|
// write zero
|
||||||
|
9
src/NTwain/Resources/MsgText.Designer.cs
generated
9
src/NTwain/Resources/MsgText.Designer.cs
generated
@@ -95,5 +95,14 @@ namespace NTwain.Resources {
|
|||||||
return ResourceManager.GetString("SourceNotThisSession", resourceCulture);
|
return ResourceManager.GetString("SourceNotThisSession", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Type {0} is not supported..
|
||||||
|
/// </summary>
|
||||||
|
internal static string TypeNotSupported {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TypeNotSupported", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -129,4 +129,7 @@
|
|||||||
<data name="SourceNotThisSession" xml:space="preserve">
|
<data name="SourceNotThisSession" xml:space="preserve">
|
||||||
<value>Source is not from this session.</value>
|
<value>Source is not from this session.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TypeNotSupported" xml:space="preserve">
|
||||||
|
<value>Type {0} is not supported.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
Reference in New Issue
Block a user