[ First ]  [ Previous ]  [ Next ]  [ Last ]  [ Manuals ]

 

Chapter 6.

 

Creating Win32/x86 Dynamic Link Libraries



This chapter explains how to create, compile, and link dynamic link libraries (DLLs) for use on Win32/x86 systems.

This chapter includes the following topics:

For additional information, see "Creating Win32/x86 Applications" and "Standard Libraries for Win32/x86 Overview." These sections contain information on creating executable applications and static library projects. For more information on projects in general, refer to the IDE User Guide.


About Dynamic Link Libraries

A dynamic link library (DLL), or shared library as it is sometimes called, is a collection of functions and data that can be shared by application programs (or other libraries) running on a Win32/x86 system. Unlike a static library, whose contents are incorporated directly into the client application, the code and data of a DLL reside in a separate file, formatted very much like an executable application file itself. Because the contents of a DLL are loaded into memory and linked to the client application dynamically at execution time, the DLL file must be available on the target machine at the time the application is run.


NOTE

To find a list of all the processors you can target, see "x86 Processor."


When you build a DLL, the linker creates two files (where lib_name is the name of your DLL project):


A Primer on Exported Names

DLLs export the names of functions or variables to make them accessible to client programs. For compatibility, CodeWarrior® compilers and linkers follow conventions established by Microsoft® for such exported names. This section describes the Microsoft naming conventions. It does not attempt to explain the reasons behind them. The topics in this section are:


Exporting Names

There are two ways to export a name from a DLL for use by client programs:

1. Directly in your source code, by preceding its declaration with the specifier __declspec(dllexport). This specifier exports the name whose declaration immediately follows it in the source code:


   __declspec(dllexport)    void AnExportedFunction();

   __declspec(dllexport)    int AnExportedVariable;

For more information, see "Calling Conventions for Win32/x86" and the C Compiler Reference.


TIP

This is generally the best method to use when building a DLL to be used only by one of your own programs.


2. With an /EXPORT command in a linker command file. The use of such a command file is optional, and is specified by the Command File setting in the x86 Linker project settings panel; see "x86 Linker" for more information. The /EXPORT command has the following syntax:

/EXPORT: ext_name [=int_name] [,@ordinal] [,DATA]

where

¯ ext_name is the external name seen by the client program.

¯ int_name is the C/C++ name used internally in the DLL's source code, if different from the external name.

¯ The @ordinal option allows you to export a function or variable by number, rather than by name. This feature is an artifact of 16-bit Windows, and generally should not be used in Win32 code.

¯ The optional keyword DATA indicates that the exported name is that of a variable rather than a function.

/EXPORT: also supports [,NONAME] which indicates that a symbol should only be exported by ordinal value. Its name will not appear in the DLL.

/EXPORT:* indicates that all external symbols should be exported under their own name.


TIP

This method of exporting names is more flexible than using the __declspec(dllexport) specifier since it allows you to export a function or variable under a different name from the one by which it is known in the DLL source code. For this reason, this method is often better if you're creating a DLL that is to be used by existing software: you can use the /EXPORT command to export the name in exactly the form the client program expects.



WARNING!

Be careful when exporting variables from a DLL that may need to reference those variables. You may need to use two header files to resolve the issue.



Importing Names

The easiest way to import a function into a program from an external DLL is simply to include the static library in your project, and then declare the imported name in your source code with the keyword extern. No other special action is needed. However, this method applies only to functions and cannot be used to import variables.

A more general method is to use the specifier __declspec(dllimport), which imports the name whose declaration immediately follows it in the source code:


   __declspec(dllimport)    void AnImportedFunction();

   __declspec(dllimport)    int AnImportedVariable;

For more information, see "Calling Conventions for Win32/x86" and the C Compilers Reference.


TIP

This method is the recommended way of importing all external function and variable names. Not only can it be used with variables as well as functions, it is also slightly more efficient even for functions, because it saves one jump instruction at every call.



Name Transformations

A function or variable exported from a DLL can have as many as four different names, which can be used for different purposes and in different contexts:


Linker names

The linker name of an exported function or variable is derived from your original C/C++ name, modified ("decorated") as follows:

becomes


   _CName

If you specify the __stdcall calling convention, the characters @nnn are also appended, where nnn is the number of bytes of parameters the function takes: for example,


   _CName@8

For more information on the __stdcall specifier, see "Calling Conventions for Win32/x86" and the C Compilers Reference.

C names with the __fastcall calling convention are prefixed with an '@' (at sign) and suffixed with an '@' and the number of bytes in the parameter list. For C++ names, a "mangled" name is generated, allowing the linker to distinguish among different versions of an over-loaded function or operator. The mangled name starts with a question mark, followed by the original C++ name or a special form of that name indicating an operator, followed by the encoded forms of the return type, template arguments, throw types, and function parameters. For example:


	?_DefaultConstructor@CBase1@@SAXXZ
  ??_7SplitDerived@@6B@External and library names

The external and library names of an exported function or variable depend on the method used to export it:

When you use the __declspec(dllexport) declaration specifier to export a function or variable, its linker name (described in the preceding section) also becomes its library name. The external name is then derived as follows:

¯ If the name is not a mangled name and is not declared with the __stdcall specifier, the external name is simply the undecorated C/C++ name, with no leading underscore added.

¯ If the name is mangled or is declared with the specifier __stdcall, the external name is the same as the linker name.

When you use the linker command
   /EXPORT: ext_name

the external name is exactly as specified in the /EXPORT command. The linker then searches for a linker name in the following order:

a. The exact name specified.

b. The specified name with a leading underscore added.

c. Any mangled name or __stdcall name that could have been derived from the name specified. In this case, there must be one and only one match among all names in the link.

The linker name found becomes the library name.

When you use the linker command
   /EXPORT: ext_name=int_name

the external name is exactly as specified in the /EXPORT command. The linker then searches for a linker name as described in the preceding case, but basing the search on the specified internal name (int_name) instead of the external name (ext_name). In the linker name found, the internal name int_name is replaced by ext_name to arrive at the final library name.

An example may help make all this clear. Suppose you have a C++ function named Fiddle, taking 12 bytes of parameters, that is declared with the __stdcall modifier and then exported with the linker command


   /EXPORT: Faddle=Fiddle

This will result in the following names:

¯ The C/C++ name is Fiddle

¯ The linker name is _Fiddle@12

¯ The external name is Faddle

¯ The library name is _Faddle@12


NOTE

In all three of the export cases listed above, an additional library name is created. This additional name is formed by adding the prefix __imp_ to the library name described above. For functions, both the ordinary library name and the one with the __imp_ prefix are placed in the library; for variables, only the __imp_ name is used. This ensures that only variables declared with the __declspec(dllimport) modifier will match the library name.



DLL Initialization

A Win32 DLL can define an optional entry point. If it does, the entry-point function will be called whenever a process or thread attaches to the DLL or when an attached process or thread detaches or terminates. The entry-point function must be declared with the __stdcall specifier (see "Calling Conventions for Win32/x86" and the C Compilers Reference) and must have the following prototype:


  BOOL WINAPI    DllEntry
   (HINSTANCE instDLL,
   DWORD fdwReason,
   LPVOID lpvReserved);

where

The function's boolean return value indicates success or failure.

The entry point for a DLL is specified by the Entry Point Usage setting on the x86 Linker project settings panel (described in detail under "x86 Linker"). This setting can have the following values:

None: The DLL has no entry point. Default: The entry point is the standard library function
   _DllMainCRTStartup@12

found in the MWCRTL.lib and MWCRTLD.lib library.

User Specified: The name of the entry-point function is specified in the Name field of the x86 Linker settings panel.

Any DLL that uses the C/C++ run-time library must use the default entry point in order to initialize the run-time library. In particular, you must use the default entry point if your DLL does any of the following:

Allocates memory Performs file operations Uses C++ static objects with constructors

If you don't perform any of these operations and don't need to do any special initialization, you can safely set Entry Point Usage to None.


NOTE

To give you a chance to perform additional initialization, the standard entry-point function _DllMainCRTStartup calls a user-supplied "hook" function named _DllMain. If you use the default entry point, you must supply a _DllMain, even if all it does is return TRUE to indicate unconditional success.



Creating a Dynamic Link Library

The steps for creating a DLL are essentially the same as those for creating a stand-alone application, but with the following exceptions:

See "Creating an Application" for step-by-step instructions on creating an application project. For details on the various project settings and panels available, see "Target Settings for Win32/x86" as well as the relevant sections of the IDE User Guide, and the C Compilers Reference.


TIP

The easiest way to begin a DLL project with all the appropriate settings and libraries is by selecting the predefined Win32 C DLL or Win32 C++ DLL stationery from the New Project dialog.


1. Create a new project.

Choose File > New. The New dialog appears, as shown in Figure 6.2.

New dialog:

2. Select the project category.

Select the Win32 DLL Stationary from the list in the Project tab.

3. Name the project.

Type a name for your project in the Project name field. By convention, a project name ends with .mcp. You may use the Location field or Set button to choose a different location to store the project. Then click OK.

4. Choose stationery.

There are two stationaries to choose from. Which one you use will depend on the task at hand. Select the preferred stationary from the Project Stationary area of the New Project dialog, as shown in Figure 6.3. Then, click OK.

New Project dialog:

5. Add source files to the project.

The project window appears, as shown in Figure 6.4. Most stationery projects contain source files that are just placeholders. If they contain any code at all, the code will not have been written with your project in mind. Thus, these placeholder files need to be deleted and replaced with your own code.

Project window:

If you do not already have source files prepared, then you will need to write them. Click New Text File in the CodeWarrior IDE tool bar. An edit window appears, as shown in Figure 6.5. Write your source code, then choose File > Save. The Save document as dialog appears, as shown in Figure 6.6. Type a name for your source file in the File name field, then click Save.

Edit window:
Save document as dialog:

Once you have written your source files or if you already have source files written, select the Source folder in the project window, then choose Project > Add Files. The Select files to add dialog appears, as shown in Figure 6.7. Navigate to your source files, select them (use Control-click to select multiple files), then click Add. The Add Files dialog appears, as shown in Figure 6.8. Add the files to the preferred targets by enabling the options in the Targets area, then click OK.

Select files to add dialog:
Add Files dialog:

6. Remove the source file placeholders from your project.

Select the placeholder files in the Sources folder of the project window and choose Edit > Delete.

7. Examine Target settings.

Choose Edit > Target Settings, where Target is the name of the project's currently selected target. The Target Settings window appears, as shown in Figure 6.9. Use this window to specify various optional settings for your project. The exact settings you can specify depend on:

For Win32/x86 projects, you must specify settings for the target platform, the project type, the compiler, and the linker. There are various other, optional settings that you can specify as well. To learn more about specifying settings beyond what we do here, refer to "Target Settings for Win32/x86."

Target Settings window:

8. Specify target settings.

The Target Settings panel appears by default in the Target Settings window. The settings in this panel are preset by the project stationery, but you can change them if you necessary. See "Target Settings" for more information on the Target Settings panel.

9. Set the project type.

Select x86 Target in the Target Settings Panels area. The x86 Target panel appears, as shown in Figure 6.10. Again, the settings are preset for you by the project stationery, but you can modify them if you wish. See "x86 Target" for more information on the x86 Target panel.

x86 Target project settings panel[x eighty-six Target project settings panel]; project settings panels:

x86 Target[project settings panels:x eighty-six Target]>x86 Target panel:

10. Specify language settings.

Select C/C++ Language in the Target Settings Panels area. The C/C++ Language panel appears, as shown in Figure 6.11. Ordinarily, the default settings are fine as they are in this panel, but you are free to change them. For more information about setting language preferences, refer to the C Compilers Reference.

C/C++ Language project settings panel[C CPlusPlus Language project settings panel]; project settings panels:

C/C++ Language[project settings panels:C CPlusPlus Language]>C/C++ Language panel:

11. Specify additional settings.

You can continue to examine other target settings panels and change any settings you wish. For more information on the various panels and settings available, see "Settings Panels for Win32/x86" as well as the relevant sections of the IDE User Guide, and the C Compilers Reference. When you are finished examining project settings, click OK to save your settings and close the Target Settings window.

12. Create New Targets

If you want, you can click on the Targets tab of the project window and choose Project > Create New Target. This allows you to add a special target group to better organize your build. You can also delete targets in this view. If you want to have certain files included in some targets but not in others, select the file in the project window and choose View > Project Inspector. The Project Inspector window appears, as shown in Figure 6.12. This window allows you to view information about a selected files and to assign files to specific targets. Click the Targets tab, then enable or disable the options in the Targets area to include or exclude the file from the targets in the project. Refer to the IDE User Guide for more information on managing multiple targets.

Project Inspector window:

13. Build your project.

After your project is created and its contents and all necessary settings are specified, you are ready to compile and debug your code. Choose Project > Make to compile and link your project. If all goes well, the IDE stores the resulting output file in your project folder under the name you specified in the x86 Target settings panel. For more information on compiling and linking, refer to the IDE User Guide. In addition, if you have checked the SYM Format option on the x86 Processor panel and Generate SYM File on the x86 Linker panel, the CodeWarrior IDE will generate a symbol file, which you will need for debugging your code.

14. Run your application.

Once you have successfully built your DLL, you can add it to your application project. If all goes well, congratulations! You have used the CodeWarrior IDE to build a running Win32/x86 DLL. If not, see "Debugging for Win32/x86" and the IDE User Guide for information on debugging.


Choosing Libraries for a DLL Project

This section describes which libraries to include in your Win32 DLL projects. For a more in-depth discussion, see "Libraries and Runtime Code for Win32/x86."

Generally, you will create a DLL project with project stationery, so you will not need to add libraries on your own. But, if you change certain project options, this section explains which libraries you may need to change.

The topics in this section include:

  • C/C++ Libraries
  • Win32 SDK Libraries
  • MFC Libraries

  • C/C++ Libraries

    Table 6.1 lists some of the CodeWarrior libraries you might need to add to a C or C++ DLL project. Note that if you are building a C++ DLL, you must also include the C runtime libraries.

    Libraries for a Win32 DLL project (Partial List):

     

    Library
    Use
    mwcrtl.lib  
    Metrowerks C/C++ Runtime  
    mwcrtldll.lib  
    The import library for the DLL runtime, MSL C, and MSL C++ dynamic linked libraries  
    ansicx86.lib  
    MSL C library  
    ansicppx86.lib  
    MSL C++ library  
    ansic_winsioux.lib  
    MSL WinSIOUX library  

    In addition to the standard libraries, there are variations for specialized compilers. These include 3DNow!, Microsoft Exceptions, and Debug versions. Versions of libraries with a final "D" before the filename extension have debug information embedded in them. For example, mwcrtld.lib is the debug version of the Metrowerks C/C++ runtime library.


    NOTE

    Libraries with a 60 number in them are intermediate steps in creating the final library.


     


    Win32 SDK Libraries

    Any libraries that you may need to include to resolve (at link time) Win32 API calls made in your code are discussed on the World Wide Web at:


    http://msdn.microsoft.com


    This site includes information on all the libraries you may need, including the commonly used ones listed in Table 6.2. For a more in-depth discussion, see "Libraries for Win32 Development."

    Common Win32 SDK Libraries (Partial List):

     

    Library Name
    Functionality
    Comdlg32.lib  
    Implements common dialog-related code  
    Gdi32.lib  
    Implements GDI calls for graphical rendering  
    Kernel32.lib  
    Implements OS-level calls  
    User32.lib  
    Implements other graphics-related Win32 API calls  


    MFC Libraries

    Any libraries that you need to include to resolve (at link time) Microsoft Foundation Classes (MFC) API calls you made in your code are discussed on the World Wide Web at:


    http://msdn.microsoft.com


    This site includes information on all the libraries you may need, including the commonly used ones listed in Table 6.3. Documentation and resources, including more sample code, for using MFC is also found there.

    Common MFC Libraries :

     

    Library Name
    Functionality
    mfc421.lib  
    MFC Static Library  
    mfc421d.lib  
    MFC Static Library (Debug)  

    Note that you can also build your DLL to include the MFC DLL instead of statically linking-in the MFC libraries. This is an option that is made available to you when you use project stationery, as described in "Creating a Dynamic Link Library." This allows the size of your application to be smaller because the MFC DLL file that is required would need to be installed or already present on the computer on which you are running it.

     


    [ First ]  [ Previous ]  [ Next ]  [ Last ]  [ Manuals ]

    Visit the Metrowerks website at: http://www.metrowerks.com
    For assistance contact Metrowerks Technical Support at: cw_support@metrowerks.com
    Copyright © 2000, Metrowerks Corp. All rights reserved.

    Last updated: July 21, 2000