Abstract

In Windows imaging applications, the most used API for scanning is TWAIN www.twain.org.
Unfortunately, the new .NET Framework has no built-in support for TWAIN. So we have to work with the interop methods of .NET to
access this API. This article doesn't explain this interop techniques, and good knowledge of the
TWAIN 1.9 specifications is assumed! The sample code included doesn't present a
finished library, only some essential steps for a minimal TWAIN adaption to .NET applications.

Details

First step was to port the most important parts of TWAIN.H, these are found in TwainDefs.cs. The real logic for
calling TWAIN is coded in the class Twain, in file TwainLib.cs.. As the TWAIN API is exposed by the Windows
DLL, twain_32.dll, we have to use the .NET DllImport mechanism for interop with legacy code. This DLL has the
central DSM_Entry(), ordinal #1 function exported as the entry point to TWAIN. This call has numerous parameters,
and the last one is of variable type! It was found to be best if we declare multiple variants of the call like:

For some sort of 'callbacks', TWAIN uses special Windows messages, and these must be caught from the application-message-loop.
In .NET, the only way found was IMessageFilter.PreFilterMessage(), and this filter has to be activated with a call
like Application.AddMessageFilter(). Within the filter method, we have to forward each message to
Twain.PassMessage(), and we get a hint (enum TwainCommand) back for how we have to react.

Sample App

The sample is a Windows Forms MDI-style application. It has the two TWAIN-related menu items Select Source... and
Acquire... Once an image is scanned in, we can save it to a file in any of the GDI+ supported file formats (BMP, GIF,
TIFF, JPEG...)

Limitations

All code was only tested on Windows 2000SP2, with an Epson Perfection USB scanner and an Olympus digital photo camera. The
scanned picture is (by TWAIN spec) a Windows DIB, and the sample code has VERY little checking against error return codes and
bitmap formats. Unfortunately, no direct method is available in .NET to convert a DIB to the managed Bitmap class... Some known
problems may show up with color palettes and menus.

Comments and Discussions

I downloaded the source code and I tried to run it but I keep getting "BadImageFormatException" This exception is thrown by the code in class Twain(TwRC rc = DSMparent(appid, IntPtr, Zero, TwDG.Control, TwDAT, Parent, TwMSG.OpenDSM, ref hwndp) I'm new to this TWAIN.

I have an Epson Workforce DS-510 scanner and it has duplex scanning feature.
This device is Twain Compatible as it's said in its manuel, but with this program i can not scan both front and rear side.
It just only scans one side which is front i belive,

is there anyone here who had succeeded inserting codes for duplex scanning before?
it is gonna really save my days, guys!

On that selection list, you can only see the drivers list that installed on your system, not the connected ones or disconnected ones. So if there will be one scanner or specific one, you have to set that scanner as default first of all.

I am using Epson GT-15000 scanner. When I run the application, everything works fine for the first couple of times, and then the scanner hangs in the middle of Data Transfer. The "Ready" light on the scanner keeps blinking, and nothing happens. I am forced to turn the scanner off.

Hi NETMaster. I downloaded your source and also your demo.The demo works perfect, nice, like a charm. But when I open the source in visual studio 2013 and run the project, it gives me the "BadImageFormatException was unhandled" exception. Here's the details of the exception :

An unhandled exception of type 'System.BadImageFormatException' occurred in TwainGui.exeAdditional information: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)

please tell me where the problem is.Thanks very much in advance,Mahdi Tahsildari

HiI have the same problem, My pc is running at 64-bit. I think this is about if your pc is using 32 or 64 bit driver for your scanner. To test, download twack_32 and twack_64, and see which of the two apps will run your scanner.

Now with regards to the exception: Go to Project properties > under Build tab > under Platform target, check Prefer 32-bit.

First, thank you for the great works! I ran into an issue. The application crashed when I quit after scanning. It shows "vshost32.exe has stopped working". Here are my settings: Windows 7 x64, Visual Studio 2013, target x86 and .net framework 4.5. Please help me if you know the answer!

In my requirement, I should display only twain drivers supported scanners. But when I call Select Source, it is showing all the list of scanners, cameras in it. Can I get only twain ones alone by setting any property?

2) How to perform automatic scanning of image when placing an ID card in the ID scanner device?

3) How to perform Scanning operation for the Front and Back side of ID card?

4) How to perform Scanning of UV( Ultraviolet) and IR(Infrared) type ID Cards?

5) After scanning the images how to edit feature's like Calibrate, Resolution, Height, Width, Color, Image Brightness, Image Contrast, Invert Images? If so by which method and parameters can be applied?

Hi I saw that this question was not answered so maybe I can help.you should set XferCount = -1 to scan all papers in scanner else for single page set XferCount = 1 .So in TwainLib.cs: TwCapability cap = new TwCapability( TwCap.XferCount, -1 );instead ofTwCapability cap = new TwCapability( TwCap.XferCount, 1 );

WE HAVE A DLL TO SCAN AN IMAGE AND GET DATA FROM FILE SCANNED SEPARATING PARTS AND STORING DATA OBTAINED IN DATABASE.THE QUESTION IS, WHERE THE TWAIN STANDARD SAVE THE TEMP FILE OF THE IMAGE OBTAINED.I NEED TO MAKE A MODIFICATION TO PUT THE FILE IN A ROOT WITHOUT SCAN IMAGESO SORRY FOR MY ENGLISH.PLEASE, HELP ME.

I am using an updated version of TwainLib for a duplex card scanner. But the PassMessage only returns TwainCommand.Null TwainCommand.Not. It is not able to validate a valid Twain command. What am I missing please?

Hi and thanks for very helpful twain guide.I have a problem with source selecting. I know that my scanner twain driver name is for example 'scanner x500 TWAIN' and it is a third position on list. On second computer it is a first position. Is it possible to set a scaner name on source code? I need to abandon source selecting and hard set accurate name of scanner because I don't know which position on list will be.Thanks

First of all you should pass TwMSG.GetFirst value to DSMident method, this method will select first diver name, after that code will check condition ,the driver name which you passed is equal to the displayed driver name or not. If it is not equal will get pass TwMSG.GetNext value to DSMident method so that next driver name is passed, when displayed driver name and driver name which you are passing are equal, the condition will exit or else the process continues untill the last driver in the list.

I tried doing this but then it causes a crash constantly after its been set. I keep getting "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." It causes then when CloseSrc() is called when trying to do an init/aquire

I found this project very useful unless you need a high reliable TWAIN scanning solution for your commercial product.

This is free, there are several over-priced solutions from TWAIN official partners and in my opinion do not worth the price. But recently I found a small, low-cost and professional .net twain scanning library. Never regret it.