A Dynamic Link Library (DLL) exports variables, functions, or resources by name. A client application references these names to use the exported entities. Windows resolves imports from the application to exports in the DLL at load time or runtime (not at link time). This requires additional metadata beyond the standard C++ compilation model to establish these connections.
This guide provides two Visual Studio solutions: one to build the DLL, and another for the client application. The DLL uses the C calling convention, enabling it to be called from applications written in other languages (provided platform, calling convention, and linking convention match).
Step 1: Create the DLL Project
Add a new header file to the project with content similar to this:
// FibonacciDLL.h - Declares functions for Fibonacci sequence operations
#pragma once
#ifdef FIBONACCI_DLL_EXPORTS
#define FIBONACCI_API __declspec(dllexport)
#else
#define FIBONACCI_API __declspec(dllimport)
#endif
// The Fibonacci sequence is defined as F(0) = a, F(1) = b, F(n) = F(n-2) + F(n-1) for n > 1.
// This DLL provides functions to initialize and generate values in such a sequence.
// Initialize the Fibonacci sequence with F(0) = a and F(1) = b.
// Must be called before other sequence functions.
extern "C" FIBONACCI_API void fibonacci_sequence_init(
const unsigned long long a, const unsigned long long b);
// Generate the next value in the Fibonacci sequence.
// Returns true if successful (no overflow), false otherwise.
extern "C" FIBONACCI_API bool fibonacci_sequence_next();
// Retrieve the current value in the Fibonacci sequence.
extern "C" FIBONACCI_API unsigned long long fibonacci_sequence_current();
// Retrieve the current index (position) in the Fibonacci sequence.
extern "C" FIBONACCI_API unsigned fibonacci_sequence_index();
The preprocessor directives at the top define FIBONACCI_API. When FIBONACCI_DLL_EXPORTS is defined (as done by Visual Studio’s DLL project template for FibonacciDLL), FIBONACCI_API uses __declspec(dllexport) to mark functions for export. This modifier tells the compiler/linker to make the function available to other applications.
Step 2: Implement the DLL
Create a .cpp file with the impleemntation, building on the header:
// FibonacciDLL.cpp - Implements exported functions for the DLL.
#include "pch.h" // Use stdafx.h in Visual Studio 2017 and earlier
#include <utility>
#include <limits>
#include "FibonacciDLL.h"
// Internal state variables for the DLL:
static unsigned long long prevValue_; // Previous sequence value
static unsigned long long currValue_; // Current sequence value
static unsigned seqIndex_; // Current sequence position
// Initialize the Fibonacci sequence with F(0) = a, F(1) = b.
void fibonacci_sequence_init(
const unsigned long long a,
const unsigned long long b)
{
seqIndex_ = 0;
currValue_ = a;
prevValue_ = b;
}
// Generate the next value in the sequence. Returns true on success, false on overflow.
bool fibonacci_sequence_next()
{
// Check for overflow in value or index
if ((std::numeric_limits<unsigned long long>::max() - prevValue_ < currValue_) ||
(std::numeric_limits<unsigned>::max() == seqIndex_))
{
return false;
}
// Special case for initial index (0) to return the second initial value
if (seqIndex_ > 0)
{
prevValue_ += currValue_;
}
std::swap(currValue_, prevValue_);
++seqIndex_;
return true;
}
// Get the current sequence value.
unsigned long long fibonacci_sequence_current()
{
return currValue_;
}
// Get the current sequence index.
unsigned fibonacci_sequence_index()
{
return seqIndex_;
}
Build the solution (Build > Build Solution) to generate the DLL. The output should resemble:
1>------ Build started: Project: FibonacciDLL, Configuration: Debug Win32 ------
1>pch.cpp
1>dllmain.cpp
1>FibonacciDLL.cpp
1>Generating Code...
1> Creating library C:\Users\user\Source\Repos\FibonacciDLL\Debug\FibonacciDLL.lib and object C:\Users\user\Source\Repos\FibonacciDLL\Debug\FibonacciDLL.exp
1>FibonacciDLL.vcxproj -> C:\Users\user\Source\Repos\FibonacciDLL\Debug\FibonacciDLL.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Step 3: Create a Client Application for the DLL
To use a DLL, the client needs:
- Declarations of exported entities (from the DLL’s header).
- Link-time info (from the DLL’s import library, not the actual code).
- Runtime access to the DLL (in a loctaion the OS can find).
For DLLs you build (not third-party), avoid duplication by:
- Setting the client project’s include path to the DLL’s header directory.
- Setting the client project’s library path to the DLL’s import library directory.
- Copying the built DLL to the client’s build output directory.
This ensures the client uses the same DLL code you built, avoiding desynchronization.