Microsoft KB Archive/148832

{|
 * width="100%"|

HOWTO: Export Functions from a 16-bit DLL

 * }

Q148832

-

The information in this article applies to:


 * Microsoft Visual C++, 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"

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" </li></ol>

Mydll.def Sample Code
<pre class="CODESAMP">  ; 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).</li>  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. <pre class="CODESAMP">  // 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; } </li> On the Options menu, click Project, and in the Linker input Libraries setting, add Mydll.lib, and build the application.</li></ol>

To build the application from command line:

 Hand code the Myapp.def file shown in the "Myapp.def Sample Code" section of this article.</li>  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" </li></ol>

Myapp.def Sample Code
<pre class="CODESAMP">  ; 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:

<pre class="CODESAMP">  ; 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 : _IK kb16bitonly kbGenInfo kbVC

Issue type : kbhowto

Technology : kbVCsearch kbAudDeveloper kbvc150 kbvc100 kbVC151 kbVC152