CS-360, DLLs
Fall, 2000
R. Eckert


DYNAMIC LINK LIBRARIES

DLL--Basic building block of Windows; provide reusable code that can
     be shared by many applications simultaneously. Windows itself is a
     set of DLLs.

  A file containing ftns that can be called by other pgms or DLLs.

  Provides a way for a process to call a ftn that is not part of its
  executable code.

  Two methods of calling a ftn in a DLL:

     Load-time dynamic linking (early binding)--app makes an explicit
     call to a DLL ftn. DLL is automatically loaded (if not already
     there) when the program that needs it is loaded. In other words, the
     links to the DLL ftns are established as soon as the app and the DLL
     have been loaded into memory. This requires that the executable
     module of the app be bult by linking with the DLL's inport library,
     which supplies the info needed to locate the DLL ftn when the app
     starts.

     Run-time dynamic linking (late binding)--DLL can be loaded after
     execution of the app begins. The app calls LoadLibrary() to load the
     DLL when it is required and then GetProcAddress() to get the start
     address of the required DLL function. After the app no longer needs 
     the DLL it should call FreeLibrary() to cause Windows to remove the 
     DLL (if no other app is using it).


  File extension .DLL makes the DLL implicitly available to apps.
  (DLLs with other file extensions have to be loaded explicitly with
  LoadLibrary()--again, see printer notes.)

  DLL ftns are not directly executable--must be called.

  A DLL usually doesn't display a window or receive messages.

  A DLL Can be accessed by any number of apps; i.e., DLLs are a Windows
  solution to problem of sharing code (and data) between apps.

  DLL Code is loaded only once; any pgm using a ftn in an already-loaded
  DLL will be linked to the loaded DLL dynamically. This is very
  important in a multitasking system in which hundreds of apps may be
  trying to access some of the same functions.

  Provides for extending Windows--add new ftns in a DLL or write a new
  DLL.


ADVANTAGES OF DYNAMIC LINKING--

  Since many processes can use a DLL simultaneously, sharing a single
  copy in memory, memory space is saved and swapping is reduced.

  Ftns in a DLL can be changed without recompiling/relinking the apps
  that use them. (For statically-linked object code, the apps must be
  relinked when the ftns change.) This is especially useful for after-
  marketing modifications; e.g., a display driver DLL could be modified
  to support a new display.

  Pgms written in different programming languages can call the same DLL
  ftns, as long as pgms follow the functions' calling conventions.
  (Careful with stack conventions.)

POTENTIAL DISADVANTAGES OF DYNAMIC LINKING--

  The app is not self-contained. The DLL module must be present.

  Some commercial apps install DLLs in the Windows System directory
  without regard for the possibility that an old DLL with the same name
  is being overwritten. In the worst case, this could cause other apps
  that count on using ftns in the old DLL to not function properly.


SOME DETAILS OF DLL OPERATION--

DLLs don't have their own stack--instead use the stack of the calling
pgm.

DLLs have their own local heap for static variables (e.g., strings). So
all pgms accessing a DLL static variable can alter it. This can cause
problems.

If a DLL has to manage data for calling pgms, it should allocate a
separate memory block for each calling pgm's data. It can use the
caller's instance handle as an ID to keep track of which data block
belongs to which pgm.

But global blocks allocated by a DLL "belong" to the calling pgm. So any
block blocks allocated by Pgm 1 will be freed when it is terminated, even
if the DLL is still in memory to serve Pgm 2. (Usually a desireable
behavior.)

BUILD DETAILS--

The linker must be told that ftns located in a DLL are available for
calling from another pgm or another DLL. One way to do this is to define
an "EXPORT" macro and declare our DLL ftns as "EXPORT". For example,
assume we have the following revstr() function defined in a DLL:

BOOL CALLBACK revstr(HANDLE, int);

In our DLL module's header file we could do the following:

#define EXPORT extern __declspec(dllexport)  /* define EXPORT macro */
EXPORT BOOL CALLBACK revstr(HANDLE, INT);    /* declare the ftn as EXPORT */

This will tell the linker that revstr() is exportable.


WRITING A DLL--

Most DLL's contain the ftn: DllMain()--like WinMain():

   First ftn executed when DLL is loaded into memory by Windows

   Performs initialization stuff

   Runs only once (when DLL is loaded):

 int CALLBACK DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID
 pvReserved)

Parameters passed to DLL from Windows:

hInstance--DLL's instance handle. IF the DLL uses resources that require
an instance handle (e.g., DialogBox), you should save hInstance as a
global or static variable. Also if it calls ftns that require an instance
handle [e.g., LoadString()], you will need to have access to hInstance.

fdwReason--one of four values that indicate why Windows is calling
DllMain().

pReserved--Reserved.

The function could perform initialization code (e.g., initializing
static data).

DllMain() should return nonzero ==> Initialization was a success. (Value
goes back to Windows.)  [0==> initialization failed, and Windows will not
run the program that calls the DLL.]

For most simple cases, all that DllMain() has to do is:

   return(1);


BUILDING THE DLL (with Mikcrosoft VC++ Developer Studio)--

1. From Developer Studio, Use "File / New", and choose "Win32 Dynamic-
Link Library" from the Projects tab. Give the DLL project a name, as
usual.

2. Create or copy the source file(s) (.c or .cpp) that contain the DLL function
definitions, the header file(s) (.h), and the resource script file (.rc),
if present, to the directory containing the DLL project. Be sure that all
DLL function declarations are "EXPORTed" in the .h file (see above).

3. Use "Project / Add to Project / Files" to add the source (.c or .cpp)
files and the .rc file (if present) to the project.

4. Build the project.

If the build is successful, the project's Debug directory will have the DLL
(.DLL) file as well as the the import library (.LIB) file containing the
information needed for dynamic linking.


BUILDING AN APP THAT USES THE DLL (VC++)--

Now you can build an app that uses functions in the DLL. The process is
as follows:

1. Use "File / New" as usual to create the "Win32 Application" as usual.

2. Create or copy the source (.c or .cpp), header (.h), and resource
(.rc) files that constitute the app to the directory created for the
app's project by Developer Studio.

3. Copy the .LIB file from the DLL's Debug directory (see above steps)
into the app's directory created for the project by Developer Studio.

4. Use "Project / Add to Project / Files" to add the app's source (.c or
.cpp) files and the .rc file (if present) to the project. Do the same to
add the DLL's .LIB file to the project.

5. Build the project. This will produce the .EXE file in the app's Debug
directory, as usual.

6. Copy the .DLL file from the DLL's Debug directory (see above steps) to
the Debug directory of the app. (Remember that the DLL must be present.)

7. Run the .EXE file.


COMPILING AND USING A DLL, AN EXAMPLE--

    DLL:
       Source file:  REVSTR.C -- provides ftn BlockRev()
       Header file:  REVSTR.H -- declares and exports ftn BlockRev()

    App that uses the DLL:
       Source file:  DLLCALL.C -- Calls the BlockRev() ftn
       Header file:  DLLCALL.H -- Normal declarations
       Header file:  REVSTR.H -- compiler must know about BlockRev()
       Resources:    DLLCALL.RC

Follow the procedures outlined above to build the DLL and the app.


WHAT THE PROGRAM DOES--

The DLLCALL pgm uses the BlockRev() ftn in the DLL to reverse the order
of the characters in a character string in response to user selecting
"Show Strings" from the menu. DLLCALL's WndProc() gets a string from the
resource file, allocates a global memory block, and calls BlockRev() in
the REVSTR DLL, which reverses the characters in the string. Both the
original and the reversed strings are displayed.


WINDOWS AND IMPORT LIBRARIES--

Most of the Windows ftns we've been using reside in DLLs (e.g., GDI.EXE)

We've used these ftns without having to import them or link their import
library file (IMPORT.LIB) to our apps.

Microsoft compiler/linker does this automatically.