Dynamically loading DTWAIN DLL at runtime

Top  Previous  Next

Please note: If you are building a 64-bit application, you will be using DTWAIN64.DLL, not DTWAIN32.DLL.

 

Many times, it is desirable to load a dynamic link library at runtime using the Windows API LoadLibrary function.  This allows your application to load a DLL programatically, check at runtime whether a DLL exists, and frees you from specifying an import library in your build settings.  To do this, the Windows API LoadLibrary and GetProcAddress functions are used to accomplish this.

 

If you are programming in C or C++ and would like to use DTWAIN32.DLL or DTWAIN64.DLL using the LoadLibrary( ) call, the DYNDTWAIN_API structure has been created that will allow you to easily use LoadLibrary() .  The DYNDTWAIN_API source files can be found in the DYDTWAIN subdirectory of the installation of DTWAIN.

 

The advantage of using the DYNDTWAIN_API structure is that you do not need to call GetProcAddress for each function -- the structure does this automatically.

 

However, The main advantage of using DYNDTWAIN_API is that your application does not use any DTWAIN import library files.   This allows the Visual C++ programmer to not worry about runtime library compatibility with the DTWAIN import libraries (as was described in the previous section), or even the version of the compiler.  

 

Also, any Windows C or C++ 32/64-bit compiler that recognizes the usual Microsoft extensions of __stdcall and __declspec is able to use DTWAIN easily without trying to create import libraries. If you are using a compiler that doesn't create import libraries, or it is very difficult to create import libraries, the DYNDTWAIN_API interface is what you should use.

 

Even if the compiler doesn't recognize these keywords, the header files can be easily edited to comply with your compiler.  This allows any C++ compiler to use DTWAIN successfully, since there are no import libraries to deal with.


 

To use DYNDTWAIN_API, the following should be done:

 

Remove any and all references to the DTWAIN32.LIB or DTWAIN64.LIB import library files in your project (this includes any VC++ and non-VC++ compilers that have created import libraries for DTWAIN). If you still include the import libraries in your project, you may have compile or link errors. THIS STEP IS VERY IMPORTANT- DO NOT LEAVE IT OUT.

 

Include the "dtwainx2.h" file wherever you need to make a call to a DTWAIN function. Do not include dtwain.h.

 

Include the DTWIMPL.C or DTWIMPL.CPP file in your project, depending on whether you are programming in 'C' or C++, respectively.  Again, this step is very important.  If you are programming in C++, you will create an instance of the DYNDTWAIN_API structure (actually you do not need to create an instance, but  for the purposes of these instructions, it is easier to do it this way).  If you are programming in 'C', declare a DYNDTWAIN_API variable.
 

If you are using Microsoft Visual Studio, and your Visual Studio project uses precompiled header files, uncomment the line in DTWIMPL.CPP that has the following:
 
#include "stdafx.h"

 

  By default, this line is commented out, therefore assumes that your project is not using precompiled headers.  This line must not be commented out if your application
  uses precompiled headers.  If your application uses precompiled headers and this line remains commented out, you will receive the following error (or an error similarly
  worded):
 
  "Unexpected end of file while looking for precompiled header directive"
 
 

Call LoadLibraryA("DTWAIN32") or LoadLibraryA("DTWAIN64") and save the return value.  If the operating system cannot find DTWAIN32.DLL or DTWAIN64.DLL, the returned HMODULE handle will be NULL, and you will have to check for this possible return value.  If this happens, this means that DTWAIN32.DLL or DTWAIN64.DLL couldn't be found on the system path or in your application directory.

 

If the HMODULE handle is valid, call InitDTWAINInterface.  If you are programming in C++, the InitDTWAINInterface is a member of the DYNDTWAIN_API structure and takes one argument:

 

 BOOL DYNDTWAIN_API::InitDTWAINInterface( HMODULE h );

 

 For 'C' programmers, the InitDTWAINInterface takes two parameters and is a standalone function:

 BOOL InitDTWANInterface( DYNDTWAIN_API* pAPI,  HMODULE h );

 

 The pAPI in the 'C' call is a pointer to the DYNDTWAIN_API variable you created in step 2.

 

By default, if there is a problem, the return value of InitDTWAINInterface( ) is FALSE.  This is most likely caused by either an invalid HMODULE handle, the DLL is corrupted, or the DLL does not have the proper functions available, i.e. you are using a new version of DYNDTWAIN_API and the DTWAIN32 DLL is an old version that doesn't contain all the current DTWAIN functions.

 

By default, if the symbol _DEBUG is defined, InitDTWAINInterface( ) will cause an assertion error (the program will halt) if the DTWAIN function does not exist in the loaded DTWAIN32.DLL  You can override this behavior and also use older versions of DTWAIN32.DLL by defining the preprocessor constant IGNORE_FUNC_ERRORS.  This will allow you to use the newer version of InitDTWAINInterface( ) with older versions of the DTWAIN library. However, your application must not attempt to make any calls to the DTWAIN functions that do not exist.

 

All the DTWAIN function calls are similar in return type and parameter types as the "normal" DTWAIN functions.

 

When finished using DYNDTWAIN_API, your application must call the Windows API FreeLibrary( ) function on the HMODULE handle from step 3.  Once you call FreeLibrary, you must reinitialize the DYNDTWAIN_API interface again.

 


The following example is an outline of a typical scenario using DYNDTWAIN_API when building a 32-bit application.  If the application is a 64-bit application, then the LoadLibrary( ) call in the code below should be:
 
HMODULE h = LoadLibrary( "DTWAIN64" );

 


 

Using C++:

#include <dtwainx2.h>

 

int main( )

{

   // Declare a DYNDTWAIN_API variable

   DYNDTWAIN_API API;

   DTWAIN_SOURCE Source;

 

   // Load the library

   HMODULE h = LoadLibraryA("DTWAIN32");

 

   // Check if library loaded correctly.  If so, initialize the DTWAIN

  //  interface

    if ( h )

       API.InitDTWAINInterface( h );

   else

       return 0;

 

   // Example DTWAIN calls

 

   // This is DTWAIN_SysInitialize

   API.DTWAIN_SysInitialize();

 

   // DTWAIN_SelectSource

   Source = API.DTWAIN_SelectSource( );

 

   // DTWAIN_AcquireFile

   API.DTWAIN_AcquireFile(Source, "FILE.BMP", DTWAIN_BMP, DTWAIN_USENAME, DTWAIN_PT_DEFAULT, 1, TRUE, TRUE, NULL);

 

   // DTWAIN_SysDestroy

   API.DTWAIN_SysDestroy();

`

   // Once finished with DTWAIN, free the library

   FreeLibrary(h);

}

 

 

Using 'C':

#include <dtwainx2.h>

 

int main()

{

   /* Declare a DYNDTWAIN_API variable */

   DYNDTWAIN_API API;

   DTWAIN_SOURCE Source;

 

   /* Load the library */

   HMODULE h = LoadLibrary("DTWAIN32");

 

   /* Check if library loaded correctly.  If so, initialize the DTWAIN

   interface */

    if ( h )

       InitDTWAINInterface( &API, h );

   else

       return 0;

 

   /*  Example DTWAIN calls */

 

   /* This is DTWAIN_SysInitialize */

   API.DTWAIN_SysInitialize();

 

   /* DTWAIN_SelectSource */

   Source = API.DTWAIN_SelectSource();

 

  /* DTWAIN_AcquireFile */

   API.DTWAIN_AcquireFile(Source, "FILE.BMP", DTWAIN_BMP, DTWAIN_USENAME, DTWAIN_PT_DEFAULT, 1, TRUE, TRUE, NULL);

 

   /* DTWAIN_SysDestroy */

   API.DTWAIN_SysDestroy();

 

   /* Once finished with DTWAIN, free the library */

   FreeLibrary(h);

}


For more advanced C++ programmers, you may want to encapsulate the DYNDTWAIN_API interface within another class so that the calls to LoadLibrary and FreeLibrary are done on construction and destruction, respectively.  It wasn't done here so as to provide the most flexibility.

 

Also note that for C++, the functions are *static*.  Therefore creation of an instance of DYNDTWAIN_API is not necessary (but was included in the examples above).

 

If your compiler doesn't support __stdcall or __declspec keywords, you will have a problem compiling your program.  Note that it is very rare for a 32-bit Windows C / C++ compiler to not support these keywords.  Even if the compiler doesn't support these keywords, the modules are easily editable to remove these words (or change them if the compiler uses different keywords).