In this page, we will create a dll and then it will be referenced from a newly created Win32 console application.
I used Visual Studio Express 2012, and the files are here.
A dynamic-link library (DLL) is an executable file that acts as a shared library of functions. Dynamic linking provides a way for a process to call a function that is not part of its executable code. The executable code for the function is located in a DLL, which contains one or more functions that are compiled, linked, and stored separately from the processes that use them.
DLLs also facilitate the sharing of data and resources. Multiple applications can simultaneously access the contents of a single copy of a DLL in memory. Dynamic linking differs from static linking in that it allows an executable module (either a .dll or .exe file) to include only the information needed at run time to locate the executable code for a DLL function.
In static linking, the linker gets all of the referenced functions from the static link library and places it with our code into our executable. Using dynamic linking instead of static linking offers several advantages. DLLs save memory, reduce swapping, save disk space, upgrade easier, provide after-market support, provide a mechanism to extend the MFC library classes, support multi language programs, and ease the creation of international versions.
We can declare C++ classes with the dllimport or dllexport attribute. These forms imply that the entire class is imported or exported. Classes exported this way are called exportable classes.
The following example defines an exportable class. All its member functions and static data are exported:
#define DllExport __declspec( dllexport ) class DllExport C { int i; virtual int func( void ) { return 1; } };
To create a dynamic link library (DLL) project:
To create a dynamic link library (DLL) project:
// MathFuncsDll.h #ifdef MATHFUNCSDLL_EXPORTS #define MATHFUNCSDLL_API __declspec(dllexport) #else #define MATHFUNCSDLL_API __declspec(dllimport) #endif
When the MATHFUNCSDLL_EXPORTS symbol is defined, the MATHFUNCSDLL_API symbol will set the __declspec(dllexport) modifier in the member function declarations in this code. This modifier enables the function to be exported by the DLL so that it can be used by other applications.
When MATHFUNCSDLL_EXPORTS is undefined, MATHFUNCSDLL_API defines the __declspec(dllimport) modifier in the member function declarations. This modifier enables the compiler to optimize the importing of the function from the DLL for use in other applications. By default, MATHFUNCSDLL_EXPORTS is defined when our MathFuncsDll project is built.
namespace MathFuncs { // This class is exported from the MathFuncsDll.dll class MyMathFuncs { public: // Returns a + b static MATHFUNCSDLL_API double Add(double a, double b); // Returns a - b static MATHFUNCSDLL_API double Subtract(double a, double b); // Returns a * b static MATHFUNCSDLL_API double Multiply(double a, double b); // Returns a / b // Throws const std::invalid_argument& if b is 0 static MATHFUNCSDLL_API double Divide(double a, double b); }; }
If we're building the DLL project on the command line, use the /D compiler option to define the MATHFUNCSDLL_EXPORTS symbol.
// MathFuncsDll.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" #include "MathFuncsDll.h" #include <stdexcept> using namespace std; namespace MathFuncs { double MyMathFuncs::Add(double a, double b) { return a + b; } double MyMathFuncs::Subtract(double a, double b) { return a - b; } double MyMathFuncs::Multiply(double a, double b) { return a * b; } double MyMathFuncs::Divide(double a, double b) { if (b == 0) { throw invalid_argument("b cannot be zero!"); } return a / b; } }
Compile the dynamic link library by choosing Build, Build Solution on the menu bar.
If we're using an Express edition that does not display a Build menu (2012 Express version has the Build menu), on the menu bar, choose Tools, Settings, Expert Settings to enable it, and then choose Build, Build Solution.
If we're building a project on the command line, use the /LD compiler option to specify that the output file is to be a DLL. For more information, check /MD, /MT, /LD (Use Run-Time Library) as well. Use the /EHsc compiler option to enable C++ exception handling.
1>------ Build started: Project: MathFuncsDll, Configuration: Debug Win32 ------ 1> stdafx.cpp 1> dllmain.cpp 1> MathFuncsDll.cpp 1> Creating library c:\users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MathFuncsDll.lib and object c:\users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MathFuncsDll.exp 1> MathFuncsDll.vcxproj -> c:\users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MathFuncsDll.dll ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Here we're going to create a C++ app that will reference and use the DLL that we just created.
// MyExecRefsDll.cpp // compile with: /EHsc /link MathFuncsDll.lib #include <iostream> #include "MathFuncsDll.h" using namespace std; int main() { double a = 7.4; int b = 99; cout << "a + b = " << MathFuncs::MyMathFuncs::Add(a, b) << endl; cout << "a - b = " << MathFuncs::MyMathFuncs::Subtract(a, b) << endl; cout << "a * b = " << MathFuncs::MyMathFuncs::Multiply(a, b) << endl; cout << "a / b = " << MathFuncs::MyMathFuncs::Divide(a, b) << endl; try { cout << "a / 0 = " << MathFuncs::MyMathFuncs::Divide(a, 0) << endl; } catch (const invalid_argument &e) { cout << "Caught exception: " << e.what() << endl; } return 0; }
/GS /analyze- /W3 /Zc:wchar_t /I"..\MathFuncsDll\" /ZI /Gm /Od /sdl /Fd"Debug\vc110.pdb" /fp:precise /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\MyExecRefsDll.pch"
/OUT:"C:\Users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MyExecRefsDll.exe" /MANIFEST /NXCOMPAT /PDB:"C:\Users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MyExecRefsDll.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" "C:\Users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MathFuncsDll.lib" /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:"C:\Users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MyExecRefsDll.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"Debug\MyExecRefsDll.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
1>------ Rebuild All started: Project: MathFuncsDll, Configuration: Debug Win32 ------ 1> stdafx.cpp 1> dllmain.cpp 1> MathFuncsDll.cpp 1> Creating library C:\Users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MathFuncsDll.lib and object C:\Users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MathFuncsDll.exp 1> MathFuncsDll.vcxproj -> C:\Users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MathFuncsDll.dll 2>------ Rebuild All started: Project: MyExecRefsDll, Configuration: Debug Win32 ------ 2> stdafx.cpp 2> MyExecRefsDll.cpp 2> Generating Code... 2> MyExecRefsDll.vcxproj -> C:\Users\KHyuck\documents\visual studio 2012\Projects\DynamicLibrary\Debug\MyExecRefsDll.exe ========== Rebuild All: 2 succeeded, 0 failed, 0 skipped ==========
We need to make sure that MyExecRefsDll is selected as the default project. In Solution Explorer, select MyExecRefsDll, and then on the menu bar, choose Project, Set As StartUp Project.
To run the project, on the menu bar, choose Debug, Start Without Debugging. The output should resemble this:
a + b = 106.4 a - b = -91.6 a * b = 732.6 a / b = 0.0747475 Caught exception: b cannot be zero!
For more on porting, please visit
C++ Libraries : Porting - Windows