Creating a DLL

Visual C++ can create two kinds of unmanaged DLL: a Win32 DLL and an MFC DLL. For simplicity, this chapter creates a Win32 DLL. Creating an MFC DLL relies on the same concepts but makes the MFC libraries available to the code within the DLL.

To create a non-MFC DLL, choose File, New, Project, choose Visual C++ projects on the left and Win32 Project on the right, and enter Legacy for the project name . Click OK and the Win32 Application Wizard dialog box appears. On the Application Settings tab, choose DLL as the Application Type and select the Export Symbols check box. Click Finish and your project will be created.

Writing DLL Header Files

The functions defined in a DLL are exported for other programs to use. To designate a function or variable as exportable, add the keywords __declspec(dllexport) before the type of the variable or the return type of the function.

Two underscores precede the keyword __declspec .

The DLLs in this chapter are used from several kinds of applications. An unmanaged C++ application that uses the DLL needs a header file that defines the functions. In that header file, the keywords __declspec( dllimport ) must precede the type of the variable or the return type of the function.

The DLL header file generated by the wizard uses the preprocessor to enable the same header file to be used both in the DLL itself, which is exporting the functions, and also in the applications that use the DLL, which are importing the functions. Here's how the generated header file looks:

 #ifdef LEGACY_EXPORTS #define LEGACY_API __declspec(dllexport) #else #define LEGACY_API __declspec(dllimport) #endif // This class is exported from the Legacy.dll class LEGACY_API CLegacy { public:     CLegacy(void);     // TODO: add your methods here. }; extern LEGACY_API int nLegacy; LEGACY_API int fnLegacy(void); 

In the DLL itself, which exports the functions, the properties of the project include a preprocessor definition (see Figure 7.1) that defines the LEGACY_EXPORTS symbol. Because the symbol has been defined, the preprocessor will substitute the export declaration for any instances of LEGACY_API . In any code that uses the DLL, the header would be included without defining the LEGACY_EXPORTS symbol, so the preprocessor will substitute the import declaration for any instances of LEGACY_API .

Figure 7.1. The project defines the symbol LEGACY_EXPORTS using the project properties, ensuring the DLL functions are declared as exported.


A DLL can export a C++ class with member functions, global functions, or variables . Because member function names are decorated or mangled, they're a little harder to call from managed C++ than global functions. In this chapter, the sample DLL will only export global functions.

Creating the Sample DLL

The sample code generated for you by the wizard includes the definition of a class, a variable, and a global function. Delete these and add two function definitions to the header file, legacy.h:

 extern "C"  { LEGACY_API bool Log(char* message, SYSTEMTIME* time); LEGACY_API double Add(double num1, double num2); } 

These function declarations are wrapped in the extern "C" specifier so that the export names will be just Log() and Add() . Without that specifier, their names would be more like Log@@YA_NPADPAU_SYSTEMTIME@@@Z() and Add@@YANNN@Z() . The extra symbols are called decoration (some old-timers call it mangling , and you can probably see why) and are used to differentiate between overloads, which have the same name but take different parameters. The extern "C" convention suppresses this decoration.

The Log function is a sample of the sort of functions you are likely to find in a legacy DLL: It uses a traditional C-style string and a pointer to a structure. The structure represents a time and is defined in winbase.h, which is included in windows .h, which in turn is included in the stdafx.h file generated for this project. As a result, no include statements need to be added to legacy.h to use the structure, which is defined as follows :

 typedef struct _SYSTEMTIME {   WORD wYear;   WORD wMonth;   WORD wDayOfWeek;   WORD wDay;   WORD wHour;   WORD wMinute;   WORD wSecond;   WORD wMilliseconds; } SYSTEMTIME, *PSYSTEMTIME; 

The Add() function is simpler than Log() because it works only with fundamental types ( double in this case). This makes the marshalling less complicated when Add() is called from managed code later in this chapter.

The two functions need bodies. The implementation belongs in legacy.cpp. Edit it as follows:

  • Remove the sample code generated by the wizard.

  • Add an include statement for stdio.h after the other include statements.

  • Add the bodies of the two functions, as in Listing 7.1.

Listing 7.1 legacy.cpp Log() and Add()
 LEGACY_API bool Log(char* message, SYSTEMTIME* time) {    FILE* logfile = fopen("C:\log.txt"," a");    fprintf(logfile, "%d/%d/%d - %d:%d %s \r\n",       time->wYear, time->wMonth, time->wDay,       time->wHour, time->wMinute, message);    fclose(logfile);    return true; } LEGACY_API double Add(double num1, double num2) {    return num1 + num2; } 

The Log() function opens a file (the name is hardcoded) in append mode, and then writes a line to the file with the date and time that was passed, pulled apart into the year, month, and so on, and the message that was passed. Then it closes the file.

Build the project and fix any typing errors. Now the DLL is available for use from a variety of applications.

Microsoft Visual C++. NET 2003 Kick Start
Microsoft Visual C++ .NET 2003 Kick Start
ISBN: 0672326000
EAN: 2147483647
Year: 2002
Pages: 141
Authors: Kate Gregory © 2008-2017.
If you may any questions please contact us: