HOWTO: Export Functions from a 16-bit DLL
ID: Q148832
|
The information in this article applies to:
-
Microsoft Visual C++ for Windows, 16-bit edition, versions 1.0, 1.5, 1.51, 1.52
SUMMARY
This article describes how to export functions from a 16-bit Dynamic
Link Library (DLL). The topics discussed include:
- How the memory model affects function declarations.
- Segment setup - what does SS!=DS mean?
- Function Prolog and Epilog options.
- How to declare functions as exported -- through function declaration or
module-definition file (.def file)?
- The C-run-time libraries for DLLs.
Sample code is also included along with the associated compiler and linker
options.
If you are exporting callback functions, please see the following article
in the Microsoft Knowledge Base:
Q100659
Exporting Callback Functions Not Required in Win32-Based Apps
MORE INFORMATION
How the Memory Model Affects Function Declarations
The code and data for the DLL will reside in segments that are separate
from the segments that hold the code and data for the .exe file. The .exe
file and the DLL share the stack of the .exe file, so you do not need to do
anything special to pass data as arguments from the .exe file to the DLL.
Because the calling function (in the .exe file) resides in a segment
separate from the called function (DLL), the called function must be
declared as FAR (or __far). Because the data of the calling function
resides in a segment separate from the called function, pointer arguments
and pointer return values in the declaration of the called function must
also be declared as FAR. The FAR declaration can be explicit (specified by
the function declaration) or implicit (specified by the memory model).
To declare a function as FAR explicitly, precede the function name with FAR
or __far, as in this example:
int FAR Function ();
To declare a pointer as FAR explicity, precede the asterisk with FAR or
__far, as in this example:
int FAR *pInt;
Segment Setup - What Does SS!=DS Mean?
DLL functions use the stack of the calling function, so the DLL's segment
addresses for the stack segment and for the data segment are not the same.
The Visual C++ compiler can make assumptions about the value of these
segment registers. Therefore, when creating a DLL, you must inform the
compiler not to make assumptions of this nature.
There are two options that the Visual C++ compiler recognizes concerning
SS!=DS. The option used for DLLs is SS!=DS, which means that the DS is not
loaded on function entry. The DS register will be loaded in the Prolog code
for the function. On the command-line options for the compiler, this option
is specified by /Axw where the x is either S, M, or L (small, medium, or
large memory model).
Function Prolog and Epilog Options
If any function in the DLL is declared with __export, the DLL should be
compiled with the compiler option to generate prolog/epilog code for
Protected Mode DLL Functions (/GD). This option will only generate the
prolog/epilog code for functions declared with __export. To generate the
same prolog/epilog code for functions declared FAR (explicitly or
implicitly), select the compiler option to "Generate for __far Functions"
(/GEf). This will not export the functions, however. You will need to
specify the exported functions in the EXPORTS section of the module-
definition file (.def file).
How to Declare Functions as Exported
You have two options to export a function in a DLL, either use __export in
the function declaration, or make an entry for the function in the EXPORTS
section of the .def file. Using __export is straight-forward, but you will
have much more control over how exactly the function is exported if you
choose to use the .def file. These two options are not exclusive. For more
information about these options, please see the following article in the
Microsoft Knowledge Base:
Q77986
Using _export Keyword or DEF File EXPORTS Statement
To use __export in the function declaration, precede the function name with
the __export keyword, as in this example:
int FAR _export Function ();
If you choose to use the .def file option, you must know the decorated
function name (function names are decorated both in C and C++ by the
compiler). You will find the decorated name in the .map file generated by
the linker. This means that if you don't know the decorated name, you must
first link the DLL without exported functions. Then find the decorated
names in the .map file, construct the EXPORTS section of the .def file, and
link the DLL again. C functions are decorated with a leading underscore.
C++ functions have a more complex decoration.
For a more detailed discussion of the EXPORTS section of the .def file,
please see the Visual C++ documentation.
The C-Run-Time libraries for DLLs
The C-run-time libraries for DLLs are XdllcYw.lib. Where X is the memory
model and Y is the math library option. For example, Ldllcew.lib is the
C-run-time library for large-memory-model DLLs using the standard math
library. Do not use XlibcYw.lib; these are the C-run-time libraries for
Windows-based applications, not for DLLs. For more information about
library-naming conventions, please see the following article in the
Microsoft Knowledge Base:
Q28173
C Run-time Library History and Naming Conventions
Step-by-Step Example to Build the DLL
To build the DLL from the IDE:
- On the Project menu, click New, and select Windows dynamic-link library.
- Name it Mydll.
- Add the following Mydll.c file to the project. If you now build the
project, the IDE will create the .def file (Mydll.def) shown in the
"Mydll.def Sample Code" section of this article. Then it will use this
.def file to build the DLL.
// MyDLL.c
#include "windows.h"
// This is a FAR function that returns a FAR pointer to an integer.
// It takes as arguments a FAR pointer to an integer and
// a FAR pointer to a character array.
// Note that this function is exported.
// Note also that because you're compiling with a large memory model,
// all occurrences of FAR may be omitted here.
int FAR * FAR __export DLLfunc1 (int FAR *Marker, LPSTR Message)
{
char Title[200];
wsprintf(Title,"Marker Number %d",*Marker);
MessageBox(NULL,Message,Title,MB_OK);
return Marker;
}
To build the DLL from the command line:
- Hand code the Mydll.def file shown in the "Mydll.def Sample Code"
section of this article.
- Use the following commands in sequence:
Compile with:
CL /ALw /GD /c MyDLL.c
Link with:
LINK /NOD /NOE MyDLL.obj,MyDLL.DLL,,LDLLCEW LIBW,MyDLL.DEF
Create Import Library:
IMPLIB MyDLL.LIB MyDLL.DLL
Mydll.def Sample Code
; MyDLL.DEF
LIBRARY MYDLL
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
HEAPSIZE 1024
EXPORTS
WEP PRIVATE
; To implement your own Windows Exit Procedure add the following
; function to your application (referring to it in the .def file isn't
; necessary). The extern "C" is only required if module is C++.
; extern "C" int FAR PASCAL _WEP(int)
; {
; /* Your WEP functionality goes here */
; return 1;
; }
Step-by-Step Example to Build the Application
To build the application from the IDE:
- On the Project menu, click New, and select Windows application (.EXE).
- Add the following Myapp.c file to the project. Again, the IDE will
create the Myapp.def shown in the "Myapp.def Sample Code" section of
this article.
// MyApp.c
#include "windows.h"
// This is a FAR function that returns a FAR pointer to an integer.
// It takes as arguments a FAR pointer to an integer and
// a FAR pointer to a character array.
// Note also that since we are compiling with a medium memory model,
// all occurrences of FAR below are required.
// Note that the NEAR pointers to MainMarker and MainMessage are
// converted to FAR in the function call to DLLfunc1 by the compiler.
int FAR * FAR DLLfunc1 (int FAR *Marker, LPSTR Message);
int FAR PASCAL WinMain (
HINSTANCE hInstCurrent,
HINSTANCE hinstPrevious,
LPSTR lpszCmdLine,
int nCmdShow)
{
int MainMarker = 123;
char *MainMessage = "My WinMain message";
DLLfunc1(&MainMarker,MainMessage);
return 0;
}
- On the Options menu, click Project, and in the Linker input Libraries
setting, add Mydll.lib, and build the application.
To build the application from command line:
- Hand code the Myapp.def file shown in the "Myapp.def Sample Code"
section of this article.
- Use the following commands in sequence:
Compile with:
CL /AM /GA /c MyApp.c
Link with:
LINK /NOD /NOE /STACK:8096 MyApp.obj,MyApp.exe,,LLIBCEW LIBW MyDLL,
MyApp.DEF
Myapp.def Sample Code
; MyApp.DEF
NAME MYAPP
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
;STACKSIZE 8096 ;Uncomment this line if /STACK:8096 is not used in
;command line build for LINK. IDE build sets this option
; by default
EXPORTS
; ===List your explicitly exported functions here===
Modified Version of Mydll.def File
If you do not use the __export keyword for the exported function, you need
to modify the Mydll.def file where the decorated name of the function is
added in the EXPORTS section as shown here:
; MyDLL.DEF
LIBRARY MYDLL
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
HEAPSIZE 1024
EXPORTS
_DLLFunc1
WEP PRIVATE
; To implement your own Windows Exit Procedure add the following
; function to your application (referring to it in the .def file is
; not required.) The extern "C" is only required if module is C++.
; extern "C" int FAR PASCAL _WEP(int)
; {
; /* Your WEP functionality goes here */
; return 1;
; }
When building the DLL from the IDE, select "Generate for __far Functions"
in the compiler's "Windows Prolog/Epilog" category.
When building the DLL from the command line, add the /GEf option as shown
here:
CL /ALw /GD /GEf /c MyDLL.c
Additional query words:
1.52a 1.52b 1.52c
Keywords : kbcode kb16bitonly kbGenInfo kbVC
Version : WINDOWS:1.0,1.5,1.51,1.52
Platform : WINDOWS
Issue type : kbhowto
Last Reviewed: August 8, 1999