Category: Graphics Code  ·  Originally posted May 31, 2012  ·  Last updated May 31, 2012

How to use a scanner (or TWAIN-compatible digital camera) in VB6

Today’s project demonstrates how to implement full scanner support from within a VB6 project. As a bonus, it also provides support for TWAIN-compatible digital cameras.

Before we begin

Because VB6 does not include a native scanner library, some sort of third-party DLL is required for scanner access.  My preferred choice is the free, public-domain EZTW32 library, which I have happily used for many years.  (The first version of EZTW32 was released in 1994!)  This project uses the most recent version of EZTW32 at the time of this writing: v1.19, updated 2009.02.22.  You can check for a newer version of the library here.

There are two versions of the EZTW32 library: a free, public-domain library – called “classic” – and a more sophisticated, paid version – called “pro.”  This project utilizes only the classic version.  The paid version includes many advanced features, and if you are interested in anything beyond simply capturing images from a scanner, it may be worth a look.  A full description of the “pro” version’s feature set is available here.

While the EZTW32 library provides many ways of interacting with the scanner, this project will focus on the following:

Private Declare Function TWAIN_IsAvailable Lib "EZTW32.dll" () As Long
Private Declare Function TWAIN_SelectImageSource Lib "EZTW32.dll" (ByVal hwndApp As Long) As Long
Private Declare Function TWAIN_AcquireToFilename Lib "EZTW32.dll" (ByVal hwndApp As Long, _
 ByVal sFile As String) As Long

The sample project includes a copy of v1.19 of the EZTW32 library.  If you would like to download a newer version of the library, simply copy the new version of EZTW32.dll into the same directory as the executable file (or .VBP file).  It should work without a problem.

Bonus tip: how to load DLLs from any location

Because a 3rd-party library is required to access a scanner in VB6, it is useful to know how to load a DLL from any location.  By default, VB6 will attempt to load a DLL from the computer’s system folder.  This is not ideal when developing portable applications (e.g. applications that can be run without requiring an installer), because it requires the user to manually copy files into their system folder… and that’s bad for a variety of reasons (security, potential for mistakes, etc).  It is possible to load a DLL from other locations using the regsvr32 command, but I don’t like regsvr32 because it adds additional entries to the user’s system registry, and it must be re-run every time the project is moved to a new folder.

So the best solution, in my opinion, is to tell VB to expect the DLL to appear in the same folder as the project itself.  (Alternatively, a /plugins/ sub-directory could be used.)  We do this by adding the following code to the General Declarations section of the project:

Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName _
 As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Dim hLib as Long

Then, in the Form_Load sub, add this code to determine the project directory and tell VB to load any EZTW32 functions from the DLL in that directory:

Dim ProgramPath as String
ProgramPath = App.Path
If Right(ProgramPath, 1) <> "\" Then ProgramPath = ProgramPath & "\"

hLib = LoadLibrary(ProgramPath & "EZTW32.dll")

Finally, add this to the Form_Unload sub to release the DLL when the program terminates:

FreeLibrary hLib

The sample project (available below) demonstrates this technique, so feel free to download that instead of copying-and-pasting the code from this page.

What this project demonstrates

Because this project is focused on the basics of using a scanner, it demonstrates only the following:

  • How to check if the system offers scanner support (e.g. is a scanner driver loaded?)
  • On systems with multiple scanners, allow the user to select which scanner they want to use
  • Load the scanner’s built-in software and allow the user to preview and scan an image
  • Send the scanned image to a temporary file, then load that temporary file into a VB picture box

All of the above also applies to TWAIN-compatible digital cameras, which the software treats just like a scanner.

Finally, as mentioned earlier, EZTW32 has a paid “pro” version that offers additional features. You can learn more about the “pro” version here.


As you may have inferred from its title, EZTW32 relies on the TWAIN protocol for accessing a scanner. TWAIN is one of several ways to interact with a scanner; other common options include WIA (Windows Image Acquisition) on Windows, and SANE (Scanner Access Now Easy) on Linux.

TWAIN has some advantages and disadvantages compared to WIA and SANE. One of TWAIN’s unique characteristics is that it requires the scanner to provide its own user interface. The advantage of this approach is that on a given system, TWAIN-compatible programs all launch the same scanner user interface – the interface provided by the scanner itself. This is good for casual users, because regardless of whether they use this program or Photoshop or GIMP, the scanner interface will always be the exact same. The downside is that if you want to implement custom scanner features or options, TWAIN makes it difficult.

Canon scanner user interface

Because TWAIN relies upon the scanner to provide its own user interface, the user will see a different scan window depending on their scanner brand. My Canon scanner software looks like this.

Another advantage of TWAIN is its longevity. The TWAIN standard has been around since 1992, so pretty much every scanner made in the last 20 years will offer TWAIN drivers. By comparison, WIA didn’t exist until the year 2000, and it wasn’t until Windows Vista that most scanners offered WIA support.

One disadvantage of TWAIN is that Windows Vista and Windows 7 give WIA preferential treatment. If you set up a new scanner using the default Windows Hardware Wizard, it may only load WIA drivers – meaning you’ll need to hunt down the install CD that came with your scanner, or download the latest driver bundle from the scanner manufacturer’s website. I discovered this the hard way when testing this program with my Canon all-in-one printer/scanner/fax. If my program can’t find your scanner, download the free GIMP image software from this link and use the File -> Create… -> Scanner/Camera… option. If my program can’t find your scanner, and GIMP can’t find your scanner, you probably don’t have TWAIN drivers installed. If GIMP works but my program does not, send me a message and I’ll investigate further.

Download the sample project

My sample project is pretty minimalist:

Scanner project user interface

The sample project keeps things simple.

I tried to keep the code as small and simple as possible. Again, the latest version of the EZTW32 dll (v1.19) is included in the download. Future versions of the file should be backwards-compatible; simply replace the existing dll with a newer version.

DISCLAIMER: These download files are regularly scanned to ensure they remain free from malicious content. Unfortunately, some virus scanners will flag these .zip files as suspicious simply because they contain source code and/or executable files. I have submitted my projects to a number of companies in an attempt to rectify these false-positives. Some have been cooperative. Others have not. If your virus scanner alerts you regarding these files, please allow the file to be submitted for further analysis (if your program allows for that). This should help ensure that any false-positive warnings gradually disappear for all users.

This site - and its many free downloads - are funded by donations from visitors like you.
Please consider a small donation to fund server costs and to help me support my family.
Even $1.00 helps. Thank you!


bookmark and share this article

Email this article to a friend Print a copy of this article Subscribe to article comments Bookmark this article on Delicious Submit this article to reddit Submit this article to Digg Submit this article to StumbleUpon Share this article on Facebook Tweet this article

related articles

Discussion (18 comments)

  1. Excellent as always.

    By William Sengdara | June 6, 2012, 1:50 am | Reply to this comment
  2. Thanks for this VB6-lesson. It is valuable and interesting to dip into your ‘trick-box’ and to see how a professional like you thinks and works.
    Long live VB6!

    By piper | September 1, 2012, 12:37 am | Reply to this comment
  3. thnx for u r valuable code, i am using canon imageclass mf4450 printer/scanner/fax model to scan the document[drivers r installed],i copied all code from your sample project and run the project and set the scanner setting to remote scanner. but when i click to scan button on my vbform or even in u r sample project, scanner starts scanning progress bar moves and shows the scanning % but it do not pulls the document so blank copy gets scan, i dont know whats the ploblem plz help me i am really stuck….

    By Avinash | November 9, 2012, 4:23 am | Reply to this comment
    • Hi Avinash,

      Here is my advice.

      1) Are you checking for scanner errors? Use a Long-type variable to check the return value of TWAIN_AcquireToFilename(). If it returns a value other than zero, the error occurred during scanning. (The sample project shows the errors that correlate to various return values.) If that function returns zero, the EZTWAIN library believes the scan was successful, and the problem probably lies in VB.

      2) Check the temporary BMP file that is created. Is it blank? If it is, then you’ll need to review your scanner documentation for additional information. If it is not blank, there is no reason you shouldn’t be able to load the picture into VB.

      3) If TWAIN_AcquireToFilename() returns zero and the BMP file is created successfully, then the problem occurs somewhere in the loading-into-VB section. Make sure the Picture Box you are using has AutoRedraw set to True.

      By Tanner | November 9, 2012, 7:46 am | Reply to this comment
      • thank you very much for your valuable reply, i will do it

        By Avinash | November 9, 2012, 11:44 pm |
  4. hi,can i ask you something?
    i have downloaded your project,it worked.
    i want to resize my image around 20kb,how i do it?
    please help me.

    By Richo | March 22, 2013, 1:19 am | Reply to this comment
    • Hi Richo,

      20 kb is extremely small for an image, but you might be able to do it by using the JPEG format at a very low quality. VB doesn’t provide a way to save JPEGs directly, so you’ll need to use a custom piece of code. I recommend this class by John Korejwa:

      By Tanner | March 24, 2013, 7:21 pm | Reply to this comment
      • HI
        you can save contents of picture box to JPG format direct by this code

        Clipboard.SetData Picture1.Picture
        SavePicture Clipboard.GetData, App.Path & “\emad.jpg”

        By ergheegh | January 26, 2014, 1:05 am |
      • Hi ergheegh. Note that the code above does not save a JPEG. It saves a bitmap file with a JPG extension. It’s like taking a Microsoft Word document and changing the file extension to .JPG – the file is still a Word document, and all you’ve done is change the extension. VB6 can only save bitmap images.

        By Tanner | January 27, 2014, 6:51 am |
  5. Why would anyone develop new functionality using a 15 years old development platform? Don’t get me wrong, it’s not trolling (maybe just ignorance).

    Even if you had to maintain and old and giant codebase, wouldn’t make sense to develop such new functionality, like scanning images, in .NET (or whatever else) and include it as an external binary so its possibilities to be reused, test and maintain are at least greater than zero?

    By Ivan Stepaniuk | March 27, 2013, 3:33 am | Reply to this comment
    • Hi Ivan,

      You’re not the first to ask this question, so don’t worry about trolling. :) I’ve talked about this elsewhere, and a full answer would be too long for this comment box, but here are the most obvious points:

      - Portable applications. How many languages can you run from a USB drive on any Windows machine, XP through Windows 8? Certainly not .NET, as the .NET framework is not a guaranteed presence on Windows machines. The VB6 runtimes are included by default on every OS since XP (through Win8, as of this writing).
      - Ease of development. With VB6 and EZTWAIN, a full scanning application – with GUI – can be developed in less than 20 lines of code.
      - Performance. I know this sounds ridiculous, but it’s completely valid. VB6 compiles down to native code. Many modern languages (python, javascript, etc), are outperformed by classic VB, surprisingly.

      Others may have their own reasons, but I think people would be surprised by how much traffic the VB sections of my little site get – let alone large ones like, which still receive new classic VB projects almost daily.

      Really, I think a better question would be – why *wouldn’t* people still use VB6? A good answer is not as obvious as most people might think.

      Hope this helps.

      By Tanner | March 27, 2013, 7:20 am | Reply to this comment
  6. thank q ur scanner vb code

    By siva | April 4, 2013, 3:49 am | Reply to this comment
  7. Hi
    Do you have any code for OCR (character recognition) on bitmap images? If yes, please let me know.

    By zagros kurdi | May 17, 2013, 3:37 am | Reply to this comment
  8. Do you have any source example that doesn’t show the UI?
    All of the preferences are set in code behind.

    By Andhika | November 19, 2013, 12:07 am | Reply to this comment
  9. how can i save the scanned image ??

    By vivek | November 25, 2013, 10:04 pm | Reply to this comment
    • Hi Vivek. The scanner saves the image to a file by default (hence the “TWAIN_AcquireToFilename” function name). If you want to re-save it after it’s been rendered to the picture box, use VB’s SavePicture function.

      By Tanner | November 26, 2013, 6:49 am | Reply to this comment

Share your thoughts below

Comments support the following tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>