Getting Images From Scanners and Webcams using VB.NET

Introduction

In this article I will show how to acquire pictures from imaging peripherals like scanners, webcams and so on, by calling some API functions, provided by the EZTW32.DLL library, and Visual Basic 2005.

To perform this operations we're going to create a wrapper that will expose methods based on the above mentioned API functions. Another purpose of this article is to show how to create CLS-Compliant assemblies and classes covering some code writing guidelines and some executable settings. Don't worry if any of the words above sound new. In this article you will find the right explanation about everything.

But we won't stop at this. We will also see how to use an assembly analysis tool to validate our executable. We will moreover talk about XML comments, a new feature of VB IDE.

To continue reading this article, download the source code from the link above. The archive contains two projects: the class library and a Windows Forms sample, called Esempio2005 (in Italian Esempio means Sample).

If yet not, install the Microsoft .NET Framework 2.0. And obviously you need to check if the EZTW32.DLL is already present on your machine. You should find this library in the System directory (e.g.: "C:\Windows\System32"). If you have one or more imaging peripherals installed, you should already have this library. If this is not your case, you can download the library from the following URL: http://www.dosadi.com/eztwain1.htm.

On this web site you can find different versions of the library, but only the one linked above is freeware. Its last updated was in 1999 but for our purpose it is really good.

Acquiring pictures via Visual Basic 2005 code

The best project type that fits our purpose is a Class Library, so that we will obtain a compiled Dll. Give the project the name you like more, I used EZTwainLibrary.

Just one code file is what we need. But before showing the code I think it's important to tell something more about the Framework and the Common Language Specifications (by now just CLS).

Everything that follows has the purpose to fit as more as possible the CLS. According to the CLS, API declarations, called pinvokes in .NET, must be declared in a separated class. This class must have friend accessibility and its name must be one of the following conventional identifiers: NativeMethods, SafeNativeMethods, UnsafeNativeMethods.

This means that we need to create two classes in the same file. First of all we have to declare a new namespace, called EZTwainLibrary as in the sample code. This namespace contains the main class, EZTwain, with public accessibility, which implements methods and properties for interfacing with imaging peripherals.

A second class is called NativeMethods and contains the API declarations for using the EZTW32.DLL.

Let's begin to write the code, line by line. First of all a pair of Imports directives:

Imports System

Imports System.Runtime.InteropServices

Next step is to mark the assembly as CLS-Compliant.

Some features of Common Language Specifications

As mentioned before, one of this article's purposes is to show how to compile a CLS-Compliant assembly. This means that we have to write compliant code from the beginning. Next steps show what and how to do it.

  • According to the CLS an assembly should be marked as CLS-Compliant. This assures a full compatibility with the .NET platform and can be done by using two attributes: Assembly and CLSCompliant.
  • EZTwain class name: we could choose any other fantasy name but letters capitalization is not random. In fact, always according to the CLS, class names are pascal-cased; if composed of more than one word, the first letter of every word is upper case while the others are lower case, as in EZ and Twain. But there is an exception: when the first word is made of two characters, as in our case, they must be both upper case.
  • Why NativeMethods: as seen before, according to .NET specifications, all pinvokes must reside in a class identified with one of the conventional names mentioned above

Now it's time to mark the assembly as CLS-Compliant. The following code must be put after Imports directives:

'Marks the assembly as CLS-Compliant
<Assembly: CLSCompliant(True)>

Then a new namespace, that will contain the two classes:

Namespace EZTwainLibrary

End Namespace

Namespace notation is the same as for classes.

Then comes the implementation of NativeMethods class, which declares EZTW32.DLL APIs. You can see the code inside the EzTwain.Vb file, in the downloadable archive. Please, check out the documentations link at the bottom of this article. By visiting these web pages you will find very detailed informations about what used APIs do.

As you can see in the source code, NativeMethods has Friend accessibility since it must be reached only from within the project and not outside, and the same applies to its methods. These are declared as shared because they will be used by a class that will implement all shared methods and properties.

CLS also state that a class made of shared methods only, must contain an empty and Private constructor.
We can now implement the EZTwain class, that makes the real job. You can observe the source code in the archive you downloaded before.

Pay attention to the following points:

  • The class has been marked as CLS-Compliant through the CLSCompliant attribute and declared as Public because it will expose methods and properties to the external world;
  • It has been also declared as NotInheritable, because CLS state that if a class is implementing only shared methods, it should not be inherited. The equivalent of NotInheritable in C# is the sealed keyword. It's useful to know this C# keyword because some analysis tools, like Microsoft FxCop, throw exceptions returning messages containing sealed rather than NotInheritable.
  • Methods and properties identifiers are pascal-cased; the first letter is upper case, the others are lower case as in AcquireToClipboard;
  • Parameters are camel-cased; as in outputFileName. The first letter of the first word is lower case, the first letter of the othe words is upper case;
  • There are some identifiers, called discrete, that are recognized by the compiler (since they are used in the base class library) when used by the developer in his own methods, e.g.: Filename. If we want to use a discrete identifier, we have to define it in a different way. Simply it's right to use FileName rather than Filename;
  • As in NativeMethods class, EZTwain implements an empty and Private constructor too, since it exposes only shared methods;
  • The Visual Basic compiler understands whether we create functions that make a job of Get/Set. In case of Get, properties are preferred to methods when properties implementation is not very complex and they do not use too many resources;
  • In VB 2005, methods should return values via the Return keyword rather than assigning a value to the function, even if this does not throw exceptions;
  • CLS state that we should avoid namespaces with less than five elements. In our case it was necessary to leave that namespace, because it is just a sample.

The following is a small example of how EZTwain could be used for acquiring images:

Sub Scan()
       
EZTWain.SelectTwainSource()

Imports
 EZTwainLibrary
        EZTwain.AcquireToFilename(Me.Handle, "C:\MyImage.Bmp"
End Sub

Inside the downloadable source code you will find a sample Windows Forms application (called Esempio2005) which shows some of our assembly capabilities.

Writing methods and properties in a .NET-style

Now it's the moment for a walkthrough inside two methods exposed by our EZTwain class: IsTwainInstalled and AcquireToNative methods.

IsTwainInstalled, which determines whether EZTW32.DLL is installed or not, calls a method implemented by the new My namespace. This is not the best place to talk about this revolutionary namespace but here I can say that My implements further classes which provide full access to many important situations, like current-user, file-system, network connections. To get the same functionalities in VB 6 we had to write hundreds lines of code, very often referring to Windows API. Now everything is easier.

AcquireNative is declared Overloads. This operator lets the developer define more instances of the same method, but with different parameters and implementations. In our case, the first overload acquires an image from a scanner, saves it to disk given the user-specified filename handling the calling window. Returns an integer value, the same returned by its related API. The second overload acquires an image from a scanner and saves to a new temporary file, handling the active window. Returns a string containing the full pathname of the new temporary file, so that the user can manage the new image file.

The Version property uses a System.Globalization.CultureInfo.InvariantCulture parameter during the conversion to string of the library version value. CLS state that when you convert a numeric value as an integer or a double to a string, calling the .ToString method, it's important to specify a valid string format depending on the client operanting system culture.

This can be done implementing the IFormatProvider interface, which provides methods for strings formatting. In our code sample we used the System.Globalization.CultureInfo.InvariantCulture  type to return a culture-indipendent string.

XML comments

Being superior to its predecessors Visual Basic 2005 lets you add XML-formatted comments while writing code.  If you know Visual Basic .NET 2003, you can remember how this was possible only installing an IDE add-in called VB-Commenter, while this feature was always part of Visual C# development. Finally this feature has been implemented directly into Visual Basic 2005 IDE. Documenting source code through XML comments can be very useful if you develop Dlls instead of stand-alone applications. In fact there are some programs, like NDoc, which can create compiled help files starting from XML comments, building compiled files very similar to Visual Studio documentation, where every namespace or class is shown describing its methods, properties and so on.

To insert XML comments, just put the cursor on the line before the code you want to describe and write three apostrophes. The IDE will automatically add a collapsible XML block, where you can add comments about what the coming code is implementing as shown in the following picture:

acquiringimage-in-vb.net.gif
 
Signing the assembly

To complete assembly creation it's necessary to create a strong name. This means signing the assembly with a digital sign (password protected or not). This tells the .NET Framework that the assembly comes from a certified source. In this way the .dll will be definitively CLS-Compliant.

Do you know what the Global Assembly Cache (GAC) is?. It is a folder created by the .NET Framework. In this folder reside all the registered assemblies, depending on .NET version. If an assembly is in the GAC it does not need to be copied every time into the folder where resides the application that uses it as reference, since the Common Language Runtime already know where registered assemblies are located. If different applications reference the same assembly, you should consider to install that assembly into the GAC.

Whenever we would like to install our assembly into the GAC, it's necessary to sign it. Visual Studio 2005 lets you make this operations from within the IDE. In the previous versions of Visual Studio .NET this could be done adding some particular lines of code into the AssemblyInfo.Vb file and running certain command line utilities.

In Visual Studio 2005 open the "My Project" window. When you get the project properties, select the "Signing" tab. Apply a flag onto the "Sign the assembly" checkbox, create a new strong name or choose an existing one, with even a password. The IDE will make the rest of the job and you will be able to see how the new file appears in the Solution Explorer.

The source code that comes with this article has already a strong name file, called EZTwain.Pfx. It's password is strongname.

Build the solution

After a long job we are ready to build the solution. Our assembly is now ready to use in our applications and can be also installed into the Global Assembly Cache.

Assembly analysis

The .NET Framework SDK 2.0 complains a very useful tool, called Microsoft FxCop. This tool implements analysis tools to understand if assemblies are CLS Compliant or not. FxCop is not automatically installed together with the SDK, but a link to its setup can be find in the Start menu.

Now let's try to analyze our assembly via the Add targets command of the Project menu. Then just click on Analyze. Though we have tried to be the most sharp as possible, you we'll see how some exceptions are thrown. But this is normal since: parameters names are made of single words, but FxCop tells that this can happen even if the developer is sure to have correctly written the code. So this can be ignored.

FxCop shows warnings about unused locals, but you can see that some of these locals are added by the IDE into some hidden files so to prevent user modifies. In the other cases it is due to particular situations concerning API functions.

Since we got a few warnings, for the reasons I just talked about, we can say that our job is good. If you want to better understand how analysis results can change, just remove CLSCompliant attributes or the NotInheritable keyword or change properties to methods or put all pinvokes into EZTwain class removing the NativeMethods one. If you repeat the analysis now, you will get many more exceptions.

Red-marked errors are more dangerous, while blue errors can be corrected in a second time...but don't forget it! For further details about every error just click on each message. If you are connected to the Internet you will be able to use hyperlinks to be redirected to the application's web site.

Microsoft FxCop is hosted on workspace onto the GotDotNet web site, at the following URL:http://www.gotdotnet.com/team/fxcop/ and can be downloaded stand-alone too, outside the Framework SDK.

Documentation

Here is a small list of web sites where I found further informations about EZTW32.DLL API:

It's really important to visit the PowerBasic Support Forum above because inside the provided .bas module you can find very detailed comments about what EZTW32.DLL APIs do, so to better understand also my source code.

Conclusion

In this article we learnt some important features about .NET Framework, Common Language Specifications and we saw how to analyze an assembly to get it .NET compliant.


Similar Articles