Using WIA for scanning

I was playing around this morning with scanning images and put together an adapter class that uses the Windows automation library (WIAAUT.DLL) which is part of the WIA automation SDK -- WIA means Windows Image Acquisition.

Here are the imports I used for the code file:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using WIA;

I created a simple enumeration for some of the more common errors that I expected.

public enum WiaScannerError : uint
{
     LibraryNotInstalled = 0x80040154,
     OutputFileExists = 0x80070050,
     ScannerNotAvailable = 0x80210015,
     OperationCancelled = 0x80210064
}

Instead of throwing a COMException I created a special exception class that provides an error code from the aforementioned enumeration.

[Serializable]
public class WiaOperationException : Exception
{
     private WiaScannerError _errorCode;

     public WiaOperationException(WiaScannerError errorCode)
          : base()
     {
          ErrorCode = errorCode;
     }

     public WiaOperationException(string message, WiaScannerError errorCode)
          : base(message)
     {
          ErrorCode = errorCode;
     }

     public WiaOperationException(string message, Exception innerException)
          : base(message, innerException)
     {
          COMException comException = innerException as COMException;

          if (comException != null)
               ErrorCode = (WiaScannerError)comException.ErrorCode;
     }

     public WiaOperationException(string message, Exception innerException, WiaScannerError errorCode)
          : base(message, innerException)
     {
          ErrorCode = errorCode;
     }

     public WiaOperationException(System.Runtime.Serialization.SerializationInfo info, 
          System.Runtime.Serialization.StreamingContext context)
               : base(info, context)
     {
          info.AddValue("ErrorCode", (uint)_errorCode);
     }

     public WiaScannerError ErrorCode
     {
          get { return _errorCode; }
          protected set { _errorCode = value; }
     }

     public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context)
     {
          base.GetObjectData(info, context);
          ErrorCode = (WiaScannerError)info.GetUInt32("ErrorCode");
     }
}

The actual class I created is just for scanners, but you can adapt it to any device that supports WIA.  I've pulled out comments and removed some extra stuff like providing a friendly message for errors for the sake of brevity.

public sealed class WiaScannerAdapter : IDisposable
{
     private CommonDialogClass _wiaManager;
     private bool _disposed; // indicates if Dispose has been called     public WiaScannerAdapter()
     {
     }

     ~WiaScannerAdapter()
     {
          Dispose(false);
     }

     private CommonDialogClass WiaManager
     {
          get { return _wiaManager; }
          set { _wiaManager = value; }
     }

     [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
     public Image ScanImage(ImageFormat outputFormat, string fileName)
     {
          if (outputFormat == null)
               throw new ArgumentNullException("outputFormat");

          FileIOPermission filePerm =
               new FileIOPermission(FileIOPermissionAccess.AllAccess, fileName));
          filePerm.Demand();

          ImageFile imageObject = null;          try          {
               if (WiaManager == null)
                    WiaManager = new CommonDialogClass();

               imageObject =
                    WiaManager.ShowAcquireImage(WiaDeviceType.ScannerDeviceType,
                         WiaImageIntent.ColorIntent, WiaImageBias.MinimizeSize, 
                         outputFormat.Guid.ToString("B"), false, true, true);

               imageObject.SaveFile(fileName);
               return Image.FromFile(fileName);
          }
          catch (COMException ex)
          {
               string message = “Error scanning image“;
               throw new WiaOperationException(message, ex);
          }          finally          {
               if (imageObject != null)
                    Marshal.ReleaseComObject(imageObject);
          }
     }

     public void Dispose()
     {
          Dispose(true);
          GC.SuppressFinalize(this);
     }

     private void Dispose(bool disposing)
     {
          if (!_disposed)
          {
               if (disposing)
               {                    // no managed resources to cleanup               }              // cleanup unmanaged resources              if (_wiaManager != null)
                   Marshal.ReleaseComObject(_wiaManager);

              _disposed = true;
          }
     }
}

Calling the adapter is really easy.  Here's an example that puts the image into a picturebox:

using (WiaScannerAdapter adapter = new WiaScannerAdapter())
{     try     {
          Image image = adapter.ScanImage(ImageFormat.Bmp, @"c:\temp\test.bmp");
          pictureBox1.Image = image;
     }
     catch (WiaOperationException ex)
     {
          MessageBox.Show(ex.Message + “ Error Code: “ + ex.ErrorCode);
     }
}

This article is part of the GWB Archives. Original Author: Anthony Trudeau

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.