I would like to give back to the community here by posting some code on how to use WIA for an ADF scanner.
The lack of C# examples makes it difficult for the average coder to figure out. Firstly, please understand that I am relatively new to csharp and this is my first attempt at coding with WIA. I am sure there are parts that could be done better and I'm still not convinced I'm doing it the correct way, however it works which is better than any other example I could find.
An Important note for those who are not aware: WIA only works on windows ME, XP and Vista. Vista uses a newer version of WIA and I have not tested this code on Vista yet. I have only tested with XP. TWAIN is more compatible with different operating systems.
Unfortunately when using a flatbed scanner with an ADF (Auto Document Feeder) tray the example does not work. My project required using an HP scanjet 5590 scanner. The users would be scanning up to 100 pages at a time.
Firstly, you will need the WIA Automation Library 2.0 to be added as a reference in your project. This library can be downloaded from Microsoft's website. You are looking for wiaaut.dll.
Once you've got the library installed and added as a reference in your project you may need the following variables in your class:
These are probably in an enum somewhere in the class as well if you look hard enough. Please take note of the DeviceID string. I initially coded my scanning to select which scanning device on one button's event and then scan on another button's event. To be able to determine which scanner was selected you will need to remember the DeviceID.
The following code is part of some code that gave me a breakthrough in how to determine if there is another page waiting to be scanned in the ADF tray. It is required in order for the main code to work.
public const uint FEEDER = 0x00000001;
public const uint FLATBED = 0x00000002;
public const uint FEED_READY = 0x00000001;
public const uint WIA_RESERVED_FOR_NEW_PROPS = 1024;
public const uint WIA_DIP_FIRST = 2;
public const uint WIA_DPA_FIRST = WIA_DIP_FIRST + WIA_RESERVED_FOR_NEW_PROPS;
public const uint WIA_DPC_FIRST = WIA_DPA_FIRST + WIA_RESERVED_FOR_NEW_PROPS;
// Scanner only device properties (DPS)
public const uint WIA_DPS_FIRST = WIA_DPC_FIRST + WIA_RESERVED_FOR_NEW_PROPS;
public const uint WIA_DPS_DOCUMENT_HANDLING_STATUS = WIA_DPS_FIRST + 13;
public const uint WIA_DPS_DOCUMENT_HANDLING_SELECT = WIA_DPS_FIRST + 14;
public const uint BASE_VAL_WIA_ERROR = 0x80210000;
public const uint WIA_ERROR_PAPER_EMPTY = BASE_VAL_WIA_ERROR + 3;
Now comes the most important part. The actual scanning. Most of it should be commented sufficiently enough.
CommonDialogClass class1 = new CommonDialogClass();
Device d = class1.ShowSelectDevice(WiaDeviceType.UnspecifiedDeviceType, true,false);
if (d != null)
this.DeviceID = d.DeviceID;
//no scanner chosen
WIA.CommonDialog WiaCommonDialog = new CommonDialogClass();
bool hasMorePages = true;
int x = 0;
int numPages = 0;
DeviceManager manager = new DeviceManagerClass();
Device WiaDev = null;
foreach (DeviceInfo info in manager.DeviceInfos)
if (info.DeviceID == this.DeviceID)
WIA.Properties infoprop = null;
infoprop = info.Properties;
//connect to scanner
WiaDev = info.Connect();
WIA.ImageFile img = null;
WIA.Item Item = WiaDev.Items as WIA.Item;
img = (ImageFile)WiaCommonDialog.ShowTransfer(Item,wiaFormatJPEG,false);
//one would do image processing here
//Save to file
string varImageFileName = "c:\\test" + x.ToString() + ".jpg";
//file exists, delete it
img = null;
catch (Exception ex)
MessageBox.Show("Error: " + ex.Message);
Item = null;
//determine if there are any more pages waiting
Property documentHandlingSelect = null;
Property documentHandlingStatus = null;
foreach (Property prop in WiaDev.Properties)
if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_SELECT)
documentHandlingSelect = prop;
if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_STATUS)
documentHandlingStatus = prop;
hasMorePages = false; //assume there are no more pages
if (documentHandlingSelect != null)
//may not exist on flatbed scanner but required for feeder
//check for document feeder
if ((Convert.ToUInt32(documentHandlingSelect.get_Value()) & WIA_DPS_DOCUMENT_HANDLING_SELECT.FEEDER) != 0)
hasMorePages = ((Convert.ToUInt32(documentHandlingStatus.get_Value()) & WIA_DPS_DOCUMENT_HANDLING_STATUS.FEED_READY) != 0);
On the HP scanjet I'm using if it does not find any pages in the ADF then it does a single scan from the glass tray. This still works. In the example above I am just saving the images to the root of c: drive and overwriting any existing images with the same name.
In the comments where I've put "Image Processing" you can do you image manipulation like cropping, resizing, rotating, etc. before saving the image. There are supposedly built in functions to do this in the WIA automation library but I have been unsuccessful in getting them to work. I am instead using the multitude of image editing examples available on the net to do all those things.
The only thing that concerns me with this code is that on every loop it reconnects to the scanner. I would have thought the logical thing would be to connect once and then tell it to scan another page. As much as I tried I could not get that to work. In the end this was the only way that seemed to work correctly and I have not had any issues with it.
Thanks for such a nice explanation. I am trying to run this code on XP (SP3) and using Fujitsu 6140 ADF scanner. The issue is the code keeps running even the feeder is empty. documentHandlingSelect.get_Value() always returns 1. Is there any way to rectify this?
It's been 5 years since I posted the original info and not long after I switched to Java and php for coding predominantly, so my c# is a bit out of practice.
I havn't worked with ASP much, but since I understand it's a server-side language (like php) I don't see it working for accessing the WIA unless the scanner was connected to the server - in which case I don't see the app being very useful. So my guess would be that you cannot do it.