How to create a C++ dll with Visual Studio?

Following previous post How to create a CLR wrapper of C++ for using in C#, I will continue with C++ project in this post. C++ is not my main programming language anymore in last 10 years but I would like to keep some ‘important’ things (to me) of C++ projects before I have to leave it again in next 5 years for focusing on web development. I would like to spend more time for web development (backend and frontend) where C#, Javascript, HTML and CSS are in a more dominant position. In this post, I’ll write down the steps to create a C++ DLL by Visual Studio. This DLL can again be wrapped by a wrapper like in previous post and consumed in C#.

1. Prerequisites

A little knowledge of C++, a Visual Studio 2013 (you can use other Visual Studio. It differs at some steps but you’ll easily find it) and this post How to create a CLR wrapper of C++ for using in C#.

2. Create DLL and consume it

2.1 Dll project

– In Visual Studio, create a new project of Blank Solution

Blank Solution

– Right click on solution, add new Visual C++ project of Class Library with name of CppLibrary

Class Library

– Right click on CppLibrary project in Solution Explorer, go to Properties. Be sure these following settings are set
+ Configuration: All Configurations
+ Configuration Type: Dynamic Library(.dll)
+ Common Language Runtime Support: No Common Language Runtime Support (we would like to use pure C++, no .NET Framework support)

Properties

NOTE: Static library(.lib) is “merged” into the final .exe file when the whole project is compiled. For the outside user, this library type isn’t visible. Dynamic library (.dll) on the other hand remains separate from the final .exe file. In this post we’ll make a dynamic library.

– Delete all content in CppLibrary.h and CppLibrary.cpp files. Delete AssemblyInfo.cpp because we don’t use CLR in our project, the syntax in this file will cause compiling errors.
– We copy the old math functions from previous post to this .dll with some modifications to export functions for using in 3rd party components.

CppLibrary.h

#pragma once

#ifdef COMPILE_CPP_LIBRARY
#define	CPP_LIBRARY_EXPORT __declspec(dllexport)
#else
#define CPP_LIBRARY_EXPORT __declspec(dllimport)
#endif

#include <stdexcept>

class CPP_LIBRARY_EXPORT CppLibrary
{
public:
	double Add(double arg1,double arg2);
	double Subtract(double arg1, double arg2);
	double Multiply(double arg1,double arg2);
	double Divide (double arg1,double arg2);
};

The dllexport and dllimport storage-class attributes are Microsoft-specific extensions to the C and C++ languages. You can use them to export and import functions, data, and objects to or from a DLL (From Microsoft).

In code listing above, we make small modifications by adding macros in header file. In this macro we’re telling compiler that when our DLL is being compiled then include CppLibrary.h as usual. But when it’s referenced by other project and that project get compiled, then just export all functions of CppLibrary class to that project (export but not compile our DLL again). Please not that macro will export complete class (all public functions) thanks to macro CPP_LIBRARY_EXPORT decorated before CppLibrary.

If you only want to export some of functions then you can add CPP_LIBRARY_EXPORT before function declaration. This macro also helps to protect the project using DLL from exporting again our DLL functions.

The #define creates a macro, which is the association of an identifier or parameterized identifier with a token string. After the macro is defined, the compiler can substitute the token string for each occurrence of the identifier in the source file.(From Microsoft)

CppLibrary.cpp

// This is the main DLL file.
#pragma once
#include "stdafx.h"
#include "CppLibrary.h"

double CppLibrary::Add(double arg1,double arg2)
{
	return arg1+arg2;
}

double CppLibrary::Subtract(double arg1,double arg2)
{
	return arg1-arg2;
}

double CppLibrary::Multiply(double arg1,double arg2)
{
	return arg1*arg2;
}

double CppLibrary::Divide(double arg1,double arg2)
{
	if (arg2 == 0)
		throw std::invalid_argument("arg2 can't be zero");
	return arg1/arg2;
}

– So that macro works as we want, for avoiding recompiling, we need to add macro COMPILE_CPP_LIBRARY to Preprocessor

Add Preprocessor

– If everything is fine, you’ll get .dll file and .lib file at output folder. This .lib file is only created when we use keyword dllexport

Lib file

2.2 Consume DLL project

– Now we’ll create a console app to consume our DLL. In Visual Studio create a Win32 Console Application with Empty project and name it as CppConsole

Win32 Console Application

Empty project

– Right click on CppConsole project and Add –> References…

Add Reference

Add New Reference… and select CppLibrary

Add new reference

– Don’t forget to include library project path in Additional Include Directories

Additional Include Directories

– Call DLL code in console app

#include <iostream>
#include "CppLibrary.h"

int main()
{
	CppLibrary *cppLibrary = new CppLibrary();
	double result = cppLibrary->Add(1.4,2.7);
	std::cout<<"Result is " <<result<<"\n";

	try
	{
	result = cppLibrary->Divide(3.8,0);
	std::cout<<"Result is " <<result<<"\n";
	}
	catch (const std::invalid_argument& e)
	{
		std::cerr<<"Invalid argument : " << e.what() << '\n';
	}

	free(cppLibrary);
	getchar();
	return 0;
}

2.3 Precompiled header

All C++ compiles have one serious performance problem because compiling C++ is a long and slow process. Each of source code file has its own #include section on top. Compiling all these huge header structures which form a part of Windows API and other large API libraries (for example Qt framework) is very, very, very… slow. I think each C++ compiler has its own solution for this performance problem. Visual Studio solves this performance one by a trick called precompiled headers. This trick bases on the fact that although each source code file has its own #include section but the included libraries are almost the same and duplicated. So if we push all of these includes into one file, compile once and the compiler doesn’t have to compile each #include from scratch every time. The compiler compiles each #include only once and reuse it next time. That magic header file in Visual Studio is called Stdafx.h
In our DLL project, we have a 2 files Stdafx.h and Stdafx.cpp. To save time for compiling, we should put all dependencies header file into Stdafx.h. Please note that #includes has to be put in appropriate order according to their dependencies.
To be sure that precompile header is enabled, you can go to Properties –> Configuration Properties –> C/C++ –> Precompiled Headers

Precompiled Headers

You can change default precompiled header name in this section. If you get an error Cannot open precompiled header file, change action from Use to Create. Compile and change it back to Use. You can then use Stdafx.h like other header files through #include directive.

3. Conclusions

Creating a C++ dll is not too complicated. What we need is a appropriate macro and settings in project.

Source code : https://bitbucket.org/hintdesk/dotnet-cpp-how-to-create-a-c-dll-with-visual-studio

Leave a Reply

Your email address will not be published. Required fields are marked *