Updated string read and fixed sample.

This commit is contained in:
soukoku
2014-04-10 07:30:00 -04:00
parent 9d30efe92a
commit f861cd8c60
13 changed files with 175 additions and 79 deletions

View File

@@ -266,16 +266,16 @@ namespace NTwain.Data
frame.Bottom = (TWFix32)ReadValue(baseAddr, ref offset, ItemType.Fix32); frame.Bottom = (TWFix32)ReadValue(baseAddr, ref offset, ItemType.Fix32);
return frame; // no need to update offset again after reading fix32 return frame; // no need to update offset again after reading fix32
case ItemType.String128: case ItemType.String128:
val = ReadString(baseAddr, offset, 128); val = ReadString(baseAddr, offset, TwainConst.String128 - 2);
break; break;
case ItemType.String255: case ItemType.String255:
val = ReadString(baseAddr, offset, 255); val = ReadString(baseAddr, offset, TwainConst.String255 - 1);
break; break;
case ItemType.String32: case ItemType.String32:
val = ReadString(baseAddr, offset, 32); val = ReadString(baseAddr, offset, TwainConst.String32 - 2);
break; break;
case ItemType.String64: case ItemType.String64:
val = ReadString(baseAddr, offset, 64); val = ReadString(baseAddr, offset, TwainConst.String64 - 2);
break; break;
case ItemType.Handle: case ItemType.Handle:
val = new IntPtr(baseAddr.ToInt64() + offset); val = new IntPtr(baseAddr.ToInt64() + offset);
@@ -294,16 +294,21 @@ namespace NTwain.Data
/// <returns></returns> /// <returns></returns>
static string ReadString(IntPtr baseAddr, int offset, int maxLength) static string ReadString(IntPtr baseAddr, int offset, int maxLength)
{ {
// todo: add support for other platform // does this work cross-platform?
var val = Marshal.PtrToStringAnsi(new IntPtr(baseAddr.ToInt64() + offset));
var sb = new StringBuilder(maxLength); if (val.Length > maxLength)
byte bt;
while (sb.Length < maxLength &&
(bt = Marshal.ReadByte(baseAddr, offset++)) != 0)
{ {
sb.Append((char)bt); // bad source, whatever
} }
return sb.ToString(); return val;
//var sb = new StringBuilder(maxLength);
//byte bt;
//while (sb.Length < maxLength &&
// (bt = Marshal.ReadByte(baseAddr, offset++)) != 0)
//{
// sb.Append((char)bt);
//}
//return sb.ToString();
} }

View File

@@ -1,4 +1,5 @@
using System; using NTwain.Data;
using System;
namespace NTwain namespace NTwain
{ {
@@ -8,30 +9,36 @@ namespace NTwain
public class DataTransferredEventArgs : EventArgs public class DataTransferredEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DataTransferredEventArgs" /> class. /// Gets pointer to the complete data if the transfer was native.
/// </summary>
/// <param name="data">The data pointer.</param>
/// <param name="filePath">The file.</param>
internal DataTransferredEventArgs(IntPtr data, string filePath)
{
Data = data;
FilePath = filePath;
}
/// <summary>
/// Gets pointer to the image data if applicable.
/// The data will be freed once the event handler ends /// The data will be freed once the event handler ends
/// so consumers must complete whatever processing /// so consumers must complete whatever processing before then.
/// required by then. /// For image type this data is DIB (Windows), PICT (old Mac), and TIFF (Linux/OSX).
/// </summary> /// </summary>
/// <value>The data pointer.</value> /// <value>The data pointer.</value>
public IntPtr Data { get; private set; } public IntPtr NativeData { get; internal set; }
/// <summary> /// <summary>
/// Gets the filepath to the transferrerd data if applicable. /// Gets the file path to the complete data if the transfer was file or memory-file.
/// </summary> /// </summary>
/// <value> /// <value>
/// The file. /// The file.
/// </value> /// </value>
public string FilePath { get; private set; } public string FilePath { get; internal set; }
/// <summary>
/// Gets the memory data if the transfer was memory.
/// </summary>
/// <value>
/// The memory data.
/// </value>
public byte[] MemData { get; internal set; }
/// <summary>
/// Gets the final image information if applicable.
/// </summary>
/// <value>
/// The final image information.
/// </value>
public TWImageInfo FinalImageInfo { get; internal set; }
} }
} }

View File

@@ -11,7 +11,7 @@
<!--<iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>--> <!--<iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>-->
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description> <description>$description$</description>
<releaseNotes>V0.9 release is updated for TWAIN 2.3 and contains some refactoring that may require updating existing code.</releaseNotes> <releaseNotes>This release supports TWAIN 2.3.</releaseNotes>
<copyright>$copyright$</copyright> <copyright>$copyright$</copyright>
<tags>twain scan</tags> <tags>twain scan</tags>
</metadata> </metadata>

View File

@@ -39,7 +39,7 @@ namespace NTwain
/// <summary> /// <summary>
/// Gets the tentative image information for the current transfer if applicable. /// Gets the tentative image information for the current transfer if applicable.
/// This may differ from the final image depending on the transfer mode used. /// This may differ from the final image depending on the transfer mode used (mostly when doing mem xfer).
/// </summary> /// </summary>
/// <value> /// <value>
/// The image info. /// The image info.

View File

@@ -11,9 +11,10 @@ namespace NTwain.Triplets
{ {
internal ExtImageInfo(ITwainStateInternal session) : base(session) { } internal ExtImageInfo(ITwainStateInternal session) : base(session) { }
public ReturnCode Get(TWExtImageInfo info) public ReturnCode Get(out TWExtImageInfo info)
{ {
Session.VerifyState(7, 7, DataGroups.Image, DataArgumentType.ExtImageInfo, Message.Get); Session.VerifyState(7, 7, DataGroups.Image, DataArgumentType.ExtImageInfo, Message.Get);
info = new TWExtImageInfo();
return PInvoke.DsmEntry(Session.GetAppId(), Session.SourceId, Message.Get, info); return PInvoke.DsmEntry(Session.GetAppId(), Session.SourceId, Message.Get, info);
} }
} }

View File

@@ -31,6 +31,10 @@ namespace NTwain.Triplets
File.Exists(path); File.Exists(path);
} }
static readonly bool IsWin = Environment.OSVersion.Platform == PlatformID.Win32NT;
static readonly bool IsOSX = Environment.OSVersion.Platform == PlatformID.MacOSX;
static readonly bool IsLinux = Environment.OSVersion.Platform == PlatformID.Unix;
// define sig for each different data type since "object" doesn't work // define sig for each different data type since "object" doesn't work
#region wrapped calls #region wrapped calls

View File

@@ -37,6 +37,7 @@ namespace NTwain
object _callbackObj; // kept around so it doesn't get gc'ed object _callbackObj; // kept around so it doesn't get gc'ed
TWUserInterface _twui; TWUserInterface _twui;
static readonly CapabilityId[] _emptyCapList = new CapabilityId[0];
private IList<CapabilityId> _supportedCaps; private IList<CapabilityId> _supportedCaps;
/// <summary> /// <summary>
@@ -53,7 +54,7 @@ namespace NTwain
{ {
_supportedCaps = this.GetCapabilities(); _supportedCaps = this.GetCapabilities();
} }
return _supportedCaps ?? new CapabilityId[0]; return _supportedCaps ?? _emptyCapList;
} }
private set private set
{ {
@@ -289,6 +290,7 @@ namespace NTwain
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
{ {
_callbackObj = null; _callbackObj = null;
SupportedCaps = null;
} }
return rc; return rc;
} }
@@ -776,7 +778,7 @@ namespace NTwain
{ {
lockedPtr = MemoryManager.Instance.Lock(dataPtr); lockedPtr = MemoryManager.Instance.Lock(dataPtr);
} }
OnDataTransferred(new DataTransferredEventArgs(lockedPtr, null)); OnDataTransferred(new DataTransferredEventArgs { NativeData = lockedPtr });
} }
} }
finally finally
@@ -808,7 +810,7 @@ namespace NTwain
var xrc = DGAudio.AudioFileXfer.Get(); var xrc = DGAudio.AudioFileXfer.Get();
if (xrc == ReturnCode.XferDone) if (xrc == ReturnCode.XferDone)
{ {
OnDataTransferred(new DataTransferredEventArgs(IntPtr.Zero, filePath)); OnDataTransferred(new DataTransferredEventArgs { FilePath = filePath });
} }
} }
@@ -826,11 +828,16 @@ namespace NTwain
if (xrc == ReturnCode.XferDone) if (xrc == ReturnCode.XferDone)
{ {
State = 7; State = 7;
TWImageInfo imgInfo;
if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
if (dataPtr != IntPtr.Zero) if (dataPtr != IntPtr.Zero)
{ {
lockedPtr = MemoryManager.Instance.Lock(dataPtr); lockedPtr = MemoryManager.Instance.Lock(dataPtr);
} }
OnDataTransferred(new DataTransferredEventArgs(lockedPtr, null)); OnDataTransferred(new DataTransferredEventArgs { NativeData = lockedPtr, FinalImageInfo = imgInfo });
} }
} }
finally finally
@@ -862,13 +869,93 @@ namespace NTwain
var xrc = DGImage.ImageFileXfer.Get(); var xrc = DGImage.ImageFileXfer.Get();
if (xrc == ReturnCode.XferDone) if (xrc == ReturnCode.XferDone)
{ {
OnDataTransferred(new DataTransferredEventArgs(IntPtr.Zero, filePath)); TWImageInfo imgInfo;
if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
OnDataTransferred(new DataTransferredEventArgs { FilePath = filePath, FinalImageInfo = imgInfo });
} }
} }
private void DoImageMemoryXfer() private void DoImageMemoryXfer()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
TWSetupMemXfer memInfo;
if (DGControl.SetupMemXfer.Get(out memInfo) == ReturnCode.Success)
{
TWImageMemXfer xferInfo = new TWImageMemXfer();
try
{
xferInfo.Memory = new TWMemory
{
Flags = MemoryFlags.AppOwns | MemoryFlags.Pointer,
Length = memInfo.Preferred,
TheMem = MemoryManager.Instance.Allocate(memInfo.Preferred)
};
var xrc = ReturnCode.Success;
do
{
xrc = DGImage.ImageMemFileXfer.Get(xferInfo);
if (xrc == ReturnCode.Success ||
xrc == ReturnCode.XferDone)
{
State = 7;
byte[] buffer = new byte[(int)xferInfo.BytesWritten];
// todo: need lock before use?
IntPtr lockPtr = IntPtr.Zero;
try
{
lockPtr = MemoryManager.Instance.Lock(xferInfo.Memory.TheMem);
Marshal.Copy(lockPtr, buffer, 0, buffer.Length);
}
finally
{
if (lockPtr != IntPtr.Zero)
{
MemoryManager.Instance.Unlock(lockPtr);
}
}
// now what?
}
} while (xrc == ReturnCode.Success);
if (xrc == ReturnCode.XferDone)
{
TWImageInfo imgInfo;
//TWExtImageInfo extInfo;
//if (SupportedCaps.Contains(CapabilityId.ICapExtImageInfo))
//{
// if (DGImage.ExtImageInfo.Get(out extInfo) != ReturnCode.Success)
// {
// extInfo = null;
// }
//}
if (DGImage.ImageInfo.Get(out imgInfo) == ReturnCode.Success)
{
//OnDataTransferred(new DataTransferredEventArgs(IntPtr.Zero, null));
}
else
{
Trace.TraceError("Failed to get image info after ImageMemXfer.");
imgInfo = null;
}
}
}
finally
{
State = 6;
if (xferInfo.Memory.TheMem != IntPtr.Zero)
{
MemoryManager.Instance.Free(xferInfo.Memory.TheMem);
}
}
}
} }
private void DoImageMemoryFileXfer() private void DoImageMemoryFileXfer()
@@ -886,6 +973,7 @@ namespace NTwain
{ {
xferInfo.Memory = new TWMemory xferInfo.Memory = new TWMemory
{ {
Flags = MemoryFlags.AppOwns | MemoryFlags.Pointer,
Length = memInfo.Preferred, Length = memInfo.Preferred,
TheMem = MemoryManager.Instance.Allocate(memInfo.Preferred) TheMem = MemoryManager.Instance.Allocate(memInfo.Preferred)
}; };
@@ -900,8 +988,22 @@ namespace NTwain
if (xrc == ReturnCode.Success || if (xrc == ReturnCode.Success ||
xrc == ReturnCode.XferDone) xrc == ReturnCode.XferDone)
{ {
State = 7;
byte[] buffer = new byte[(int)xferInfo.BytesWritten]; byte[] buffer = new byte[(int)xferInfo.BytesWritten];
Marshal.Copy(xferInfo.Memory.TheMem, buffer, 0, buffer.Length); // todo: need lock before use?
IntPtr lockPtr = IntPtr.Zero;
try
{
lockPtr = MemoryManager.Instance.Lock(xferInfo.Memory.TheMem);
Marshal.Copy(lockPtr, buffer, 0, buffer.Length);
}
finally
{
if (lockPtr != IntPtr.Zero)
{
MemoryManager.Instance.Unlock(lockPtr);
}
}
outStream.Write(buffer, 0, buffer.Length); outStream.Write(buffer, 0, buffer.Length);
} }
} while (xrc == ReturnCode.Success); } while (xrc == ReturnCode.Success);
@@ -962,6 +1064,7 @@ namespace NTwain
} }
finally finally
{ {
State = 6;
if (xferInfo.Memory.TheMem != IntPtr.Zero) if (xferInfo.Memory.TheMem != IntPtr.Zero)
{ {
MemoryManager.Instance.Free(xferInfo.Memory.TheMem); MemoryManager.Instance.Free(xferInfo.Memory.TheMem);
@@ -974,7 +1077,12 @@ namespace NTwain
if (File.Exists(finalFile)) if (File.Exists(finalFile))
{ {
OnDataTransferred(new DataTransferredEventArgs(IntPtr.Zero, finalFile)); TWImageInfo imgInfo;
if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success)
{
imgInfo = null;
}
OnDataTransferred(new DataTransferredEventArgs { FilePath = finalFile, FinalImageInfo = imgInfo });
} }
} }
} }

View File

@@ -120,7 +120,7 @@ namespace NTwain
{ {
lockedPtr = MemoryManager.Instance.Lock(dataPtr); lockedPtr = MemoryManager.Instance.Lock(dataPtr);
} }
OnDataTransferred(new DataTransferredEventArgs(lockedPtr, file)); OnDataTransferred(new DataTransferredEventArgs { NativeData = lockedPtr, FilePath = file });
} }
//} //}
//else if (group == DataGroups.Audio) //else if (group == DataGroups.Audio)

View File

@@ -1,26 +0,0 @@
using NTwain;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using NTwain.Values;
using System.Runtime.Serialization;
namespace NTwain.Tests
{
[TestClass]
public class DataTransferredEventArgsTests
{
[TestMethod]
public void Constructor_Sets_Correct_Properties()
{
// just some non-default values to test
IntPtr data = new IntPtr(10);
string file = "THIS IS A TEST.";
DataTransferredEventArgs target = new DataTransferredEventArgs(data, file);
Assert.AreEqual(data, target.Data, "Data mismatch.");
Assert.AreEqual(file, target.FilePath, "File mismatch.");
}
}
}

View File

@@ -54,9 +54,6 @@
</CodeAnalysisDependentAssemblyPaths> </CodeAnalysisDependentAssemblyPaths>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="DataTransferredEventArgsTests.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Data\TWIdentityTest.cs"> <Compile Include="Data\TWIdentityTest.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>

View File

@@ -93,7 +93,7 @@ namespace Tester
static void twain_DataTransferred(object sender, DataTransferredEventArgs e) static void twain_DataTransferred(object sender, DataTransferredEventArgs e)
{ {
if (e.Data != IntPtr.Zero) if (e.NativeData != IntPtr.Zero)
{ {
Console.WriteLine("Got twain data on thread {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Got twain data on thread {0}", Thread.CurrentThread.ManagedThreadId);
} }

View File

@@ -63,9 +63,9 @@ namespace Tester.WPF
protected override void OnDataTransferred(DataTransferredEventArgs e) protected override void OnDataTransferred(DataTransferredEventArgs e)
{ {
if (e.Data != IntPtr.Zero) if (e.NativeData != IntPtr.Zero)
{ {
Image = e.Data.GetWPFBitmap(); Image = e.NativeData.GetWPFBitmap();
} }
else if (!string.IsNullOrEmpty(e.FilePath)) else if (!string.IsNullOrEmpty(e.FilePath))
{ {

View File

@@ -69,10 +69,10 @@ namespace Tester.Winform
pictureBox1.Image.Dispose(); pictureBox1.Image.Dispose();
pictureBox1.Image = null; pictureBox1.Image = null;
} }
if (e.Data != IntPtr.Zero) if (e.NativeData != IntPtr.Zero)
{ {
//_ptrTest = e.Data; //_ptrTest = e.Data;
var img = e.Data.GetDrawingBitmap(); var img = e.NativeData.GetDrawingBitmap();
if (img != null) if (img != null)
pictureBox1.Image = img; pictureBox1.Image = img;
} }
@@ -284,7 +284,7 @@ namespace Tester.Winform
{ {
var list = _twain.CapGetSupportedSizes(); var list = _twain.CapGetSupportedSizes();
comboSize.DataSource = list; comboSize.DataSource = list;
var cur = _twain.GetCurrentCap<SupportedSize>(CapabilityId.ICapSupportedSizes); var cur = _twain.GetCurrentCap(CapabilityId.ICapSupportedSizes).ConvertToEnum<SupportedSize>();
if (list.Contains(cur)) if (list.Contains(cur))
{ {
comboSize.SelectedItem = cur; comboSize.SelectedItem = cur;
@@ -293,7 +293,7 @@ namespace Tester.Winform
private void LoadDuplex() private void LoadDuplex()
{ {
ckDuplex.Checked = _twain.GetCurrentCap<uint>(CapabilityId.CapDuplexEnabled) != 0; ckDuplex.Checked = _twain.GetCurrentCap(CapabilityId.CapDuplexEnabled).ConvertToEnum<uint>() != 0;
} }
private void LoadDPI() private void LoadDPI()
@@ -301,7 +301,7 @@ namespace Tester.Winform
// only allow dpi of certain values for those source that lists everything // only allow dpi of certain values for those source that lists everything
var list = _twain.CapGetDPIs().Where(dpi => (dpi % 50) == 0).ToList(); var list = _twain.CapGetDPIs().Where(dpi => (dpi % 50) == 0).ToList();
comboDPI.DataSource = list; comboDPI.DataSource = list;
var cur = _twain.GetCurrentCap<int>(CapabilityId.ICapXResolution); var cur = (TWFix32)_twain.GetCurrentCap(CapabilityId.ICapXResolution);
if (list.Contains(cur)) if (list.Contains(cur))
{ {
comboDPI.SelectedItem = cur; comboDPI.SelectedItem = cur;
@@ -312,7 +312,7 @@ namespace Tester.Winform
{ {
var list = _twain.CapGetPixelTypes(); var list = _twain.CapGetPixelTypes();
comboDepth.DataSource = list; comboDepth.DataSource = list;
var cur = _twain.GetCurrentCap<PixelType>(CapabilityId.ICapPixelType); var cur = _twain.GetCurrentCap(CapabilityId.ICapPixelType).ConvertToEnum<PixelType>();
if (list.Contains(cur)) if (list.Contains(cur))
{ {
comboDepth.SelectedItem = cur; comboDepth.SelectedItem = cur;