Using Borland's Command Line Tools
Page 10: Create and Use a DLL

Installation, First Use Multi-File Programs
Static Libraries Static Linked and Dynamic Linked
Make Files [1],  [2],  [3],  [4]  [Summary] Create and Use a DLL
Resource Files [1]

A Dynamic Linked Library, DLL, is created by giving the compiler the option '-WD' for static linked or '-WDR' for dynamic linked.  If you call the linker directly use a '/Twd' option to say a DLL is to be created and use the DLL startup code c0d.obj.

Here is an example of a DLL and a header file for it.  Some things in the code have not been discussed so look a bit odd.  A discussion of those things is at the bottom of this page [Link]

The code related to this page can be downloaded in zip files from the links below.  The header file supplied and DLLs created by both of them can be used by either of C or C++ programs.
   [C++ Language ZIP File]    [C Language ZIP File]
---------ADD_DLL.CPP------
#include <windows.h>

BOOL WINAPI DllEntryPoint(HINSTANCE, DWORD, LPVOID)
  {
  return TRUE;
  }

extern "C"
int __declspec(dllexport) WINAPI DoAdd(int i, int j)
  {
  return i + j;
  }
---------ADD_DLL.H--------
#ifndef ADD_DLL_H /* header for programs USING the DLL */
#define ADD_DLL_H

#ifdef __cplusplus /* if in a C++ program */
  extern "C"
#endif

int __declspec(dllimport) WINAPI DoAdd(int i, int j);

#endif
--------------------------
Here is a program to test the DLL and a make file to create both the DLL and the test program.
------TestDll1.CPP--------
#include <windows.h>
#include <cstdio>

#include "add_dll.h"

using namespace std;

int main()
  {
  printf("Test One: Add_Dll.DLL is Implicitly Loaded\n");
  printf("The sum of 4 + 7 is %d\n", DoAdd(4, 7));
  return 0;
  }
------TestDll1.MAK------
.autodepend

testdll1.exe : add_dll.lib testdll1.cpp
  bcc32 -WCR testdll1 add_dll.lib

add_dll.lib : add_dll.dll
  implib -c add_dll.lib add_dll.dll

add_dll.dll : add_dll.cpp
  bcc32 -WDR add_dll
-----------------------
The import library gave the linker information about add_dll.  It will write that information into the places in memory used by the executable program where those functions are called.

When the program starts Windows loads the DLL and uses that information to alter the calling address in the test program to be the location of the DLL's DoAdd function.  Because the need for the DLL is not in the source code but implied by what was added by the linker the DLL is said to be Implicitly Linked.

Another way the program could use the DLL is to be Explicitly Linked.  The source code explicitly loads the DLL and the address of any needed functions that it contains.
------TestDll2.CPP--------
#include <windows.h>
#include <cstdio>

#include "add_dll.h"

using namespace std;

// The typedef below is of the type of function
// found in the DLL.  It is used to simplify the
// type in the function pointer declaration and
// the cast in the GetProcAddress call

typedef int WINAPI (*FuncPtr)(int, int);


int main()
  {
  printf("Test Two: Add_Dll.DLL is Explicitly Loaded\n");

  HMODULE dll_handle = LoadLibrary("ADD_DLL.DLL");

  if (!dll_handle)
    printf("Error: could not load ADD_DLL.DLL\n");
  else
    {
    int i1 = 4;
    int i2 = 7;
    FuncPtr DoAdd = (FuncPtr) GetProcAddress(dll_handle, "DoAdd");

    if (!DoAdd)
      printf("Error: could not find address of function DoAdd\n");
    else
      printf("The sum of %d + %d is %d\n", i1, i2, DoAdd(i1, i2));

    FreeLibrary(dll_handle); // never omit doing this if it loaded
    }

  return 0;
  }
------TestDll2.MAK------
.autodepend

testdll2.exe : add_dll.dll testdll2.cpp
  bcc32 -WCR testdll2

add_dll.dll : add_dll.cpp
  bcc32 -WDR add_dll
-----------------------
Oddities in the code

   BOOL WINAPI DllEntryPoint(HINSTANCE, DWORD, LPVOID)

This is the beginning function for a DLL, similar to how main or WinMain is the beginning function for a program.  The argument names are not required in a function prototype.  In the actual function code for C++ only any of the argument names that are not used in the function may be omitted and that results in the compiler not giving the warning that a calling argument that is not used.

Were this to be C language instead of C++ then the names for the arguments would have to be given and the warning about unused calling arguments is avoided by placing
    #pragma argsused
on the line immediately before the function.

Windows actually has two such functions.  A DLL must have one of DllEntryPoint or DllMain.  Windows' documentation says that DllMain can be used optionally as the entry point.

Microsoft's newer Windows documentation speaks of DllMain as the function that is normally used. But it does the same thing as DllEntryPoint which has been used for years. This newer documentation does not describe why this was changed.
    [Link to DllMain Documentation]

WINAPI is a macro in the Windows header files.

  #define WINAPI __stdcall

The keyword __stdcall specifies a type of calling convention (more about calling conventions below [Link]).

   extern "C"
   int __declspec(dllexport) WINAPI DoAdd(int i, int j)

extern "C" is a directive to a C++ program telling it to not form the public name of the function (the name the linker sees) as C++ normally does.

__declspec(dllexport) tells the compiler to mark the function as an export, a function to be placed into the DLL's list of those which an external program or another DLL can call.

Note that the header file to be used by the code using the DLL has __declspec(dllimport), a declaration of just the reverse.  It causes the function to be marked as an import a function which is located somewhere else.

The compiler supports many calling conventions.  Each of those varies in how the calling arguments are passed to a function, in how the space used by those arguments is freed at the end of the function and in how the public name of the function is formed.

Public names are very important.  A mismatch in those names will cause the linker to stop with an error.  Also the public name is what is used as the calling argument for GetProcAddress.

The default calling convention is C.  C++ also uses it but alters how the name is formed, adding letters encoding the calling arguments at the end of the name.  This is the mechanism by which C++ overloaded functions are handled.  Each has a different set of calling arguments.  The argument list in the function call matches the encoded argument types at the end of the public name.

The WINAPI or __stdcall convention is slightly more efficient.  It is the most common one used for functions exported from DLLs.  Here is an example of how the public names for functions using these three calling calling conventions are formed.
  extern "C" int DoAdd(int i, int j)
  Public Name: _DoAdd

  extern "C" int WINAPI DoAdd(int i, int j)
  Public Name: DoAdd

  int DoAdd(int i, int j)
  Public Name: @DoAdd$qii
You can generate a list of the imported or exported public names for an executable or DLL with the tdump tool.  A command line like the ones below will show the public names of exports and imports.  When it is an import (-em is used) then the DLL name from which it is to be imported will also be shown.

   tdump -ee myprog.exe
   tdump -em mydll.dll

If you repeat the -em line above but with a period after the 'm' (with -em.), then only the names of the files from which it imports will be shown. (If your TDUMP is newer you may need to use two dots instead of one, -em.. instead of -em.)
 
[Next Page: Resource Files 1]

:: Main | Search | Site Map
 
:: Algorithms & Code
:: Assembly & Low Level
:: Borland/CodeGear
:: C & C++
:: CGI
:: CDROM Info
:: COM/DCOM/CORBA
:: Communications
:: Compression
:: Cryptography
:: File Formats
:: General Software
:: Games & Graphics
:: Hardware
:: HTML, Web Development
:: Linux/Unix/BSD
:: Microsoft
:: Miscellaneous
:: Neural Nets
:: New Links
:: Programming Articles
:: Programming Languages
:: Protocols
:: Sfwe Publications
:: Sfwe Sellers
:: Std Template Lib/STL
:: Tutorials, Refs: C/C++
:: Tutorials, Refs: Other
:: Utilities & Tools
:: XML & XHTML
:: Windows, Win32
:: 8051 & Embedded
  Programming Pages 
::  #1 #2 #3 #4 #5 #6 #7
Valid HTML 4.01 Strict