KPU – 01 Write a DLL in C++

To prevent having way too much code and have something reusable one can create a .DLL-file.
This way you have encapsulated your code and, if done correctly, it’s easy accessible.

Creating a .DLL-file

Create a new project under “Visual C++”, take a Win32 template and mark the “Win32 Project”.
Select a folder and a name and hit ‘OK’.

Select a “DLL” in the following window and check “Export” and NOT “Empty Project”.

You get a bunch of code which I will not explain but about half must stay. Here’s what you do:
I have created a project called “LAB1″.

//Lab1.h
#ifdef LAB1_EXPORTS //Project name
#define LAB1_MATH __declspec(dllexport)
#else
#define LAB1_MATH __declspec(dllimport)
#endif

#include

extern "C"
{
	namespace LAB
	{
		LAB1_MATH double AddDoubles(double a, double b);
		LAB1_MATH double AddCharStrings(char* a, char* b);
		LAB1_MATH double AddStrings(std::string a, std::string b);
	}
}

Here we have 3 functions (and no class, I show that later).

//LAB1.cpp
#include "stdafx.h"
#include "LAB1.h"
#include

extern "C"
{
	namespace LAB
	{
		LAB1_MATH double AddDoubles(double a, double b)
		{
			return a + b;
		}

		LAB1_MATH double AddCharStrings(char* a, char* b)
		{
			return atof(a) + atof(b);
		}

		LAB1_MATH double AddStrings(std::string a, std::string b)
		{
			return stod(a) + stod(b);
		}
	};
}

This is the implementation – nothing fancy there.

Check if everything work with Developer Command Promt for VS2012 – navigate to you folder and type the following:

C:\Users\Limro\Documents\IHA\KPU\LAB1\Debug>dumpbin /exports LAB1.dll
Dump of file LAB1.dll
File Type: DLL
...
0 00011195 AddCharStrings = ...
1 00011131 AddDoubles = ...
2 0001102D AddStrings = ...

//If 'extern "C" ' is not on:
2 0001112C ?AddStrings@LAB@@YANV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@Z = ...

This is some of the lines you get.
You see the first 3 (0, 1, 2) have nice names. But if we remove the extern “C” before the declaration of them you get a line a human cannot decrypt without machine power.

Using the DLL-file with Load-Time dynamic linking

Now lets use the files!
Create a new project (same solution if you want) and make it “console” instead of a “.dll”.

Create a reference to your .dll project:

  • Right click on your console project and choose “References…”
  • Add a new reference and select yours
  • Under “Configuration Properties” -> “C/C++” -> “General” add the path to your reference’s .h file
    • Do yourself that favor and use relative path e.g.: ..\LAB1; instead of the full path
//LoadTimeDynamicLinking.cpp
#include "stdafx.h"
#include "LAB1.h"
#include
#include
#include

int _tmain(int argc, _TCHAR* argv[])
{
	int a = LAB::AddDoubles(2.1, 1.9);
	int b = LAB::AddCharStrings((char*)"2.1", (char*)"1.9");
	int c = LAB::AddStrings((std::string)"2.1", (std::string)"1.9");
	std::cout << a << " " << b << " " << c << std::endl;
	getch();
}

Here we have included the .dll-file and can access it through the namespace.

Using the DLL-file with Run-Time dynamic linking

This is a bit harder but can be used in other languages – Java, C# and so on.
Same project as with Load-Time but now the code looks like this:

//RunTimeDynamicLinking.cpp
#include "stdafx.h"
#include
#include
#include
#include
#include

int _tmain(int argc, _TCHAR* argv[])
{
	typedef double (*DLLFUNC1)(double, double);
	typedef double (*DLLFUNC2)(char*, char*);
	typedef double (*DLLFUNC3)(std::string, std::string);

	DLLFUNC1 func1;    // Function pointer
	DLLFUNC2 func2;    // Function pointer
	DLLFUNC3 func3;    // Function pointer

	std::wstring dllFile = TEXT("LAB1.dll");

	HINSTANCE hDLL = LoadLibrary(dllFile.c_str());
	if (hDLL != NULL)
	{
		func1 = (DLLFUNC1)GetProcAddress(hDLL, "AddDoubles");
		func2 = (DLLFUNC2)GetProcAddress(hDLL, "AddCharStrings");
		func3 = (DLLFUNC3)GetProcAddress(hDLL, "AddStrings");

	   if (func1 == NULL)
	   {
		  // handle the error
		  FreeLibrary(hDLL);
		  return -1;
	   }
	   else
	   {
			double d = func1(1.2, 2.8);
			double e = func2((char*)"2.1", (char*)"1.9");
			double f = func3((std::string)"2.1", (std::string)"1.9");
			std::cout << d << " " << e << " " << f << std::endl;
			getch();
	   }
	   FreeLibrary(hDLL);
	}
}

Step by step:

  • Create 3 new typedefs with the expected return type and the parameters they take
  • Create a function for each typedef
  • Tell which DLL file must be used
  • Call LoadLibrary(…) with your DLL
  • If the file is not found the hDLL will remain NULL
  • Assign the values to the function pointers by the function GetProcAddress and write the name from the Developer Command Promt for VS. Note: Without extern “C” these name would be very long.
  • Check if the functions have been found
    • If not something went wrong, so call FreeLibrary(…)
  • Use the functions as if you had define them in the same file
  • Call FreeLibrary(…) to avoid memory leeks.

 

Create a DLL in a class

First a simple header file:

//ClassExportDLL.h
#ifdef CLASSEXPORTDLL_EXPORTS
#define SMOOTH __declspec(dllexport)
#else
#define SMOOTH __declspec(dllimport)
#endif

namespace SmoothDLL
{
	class SMOOTH ClassExportDLL 
	{
	public:
		ClassExportDLL(void);
		void Output(void);
	};
};

Notice there’s no extern “C” here since other languages can’t handle a class.

An implementation:

// ClassExportDLL.cpp
#include "stdafx.h"
#include "ClassExportDLL.h"
#include <iostream>
#include <conio.h>

namespace SmoothDLL
{
	SMOOTH void ClassExportDLL::Output()
	{
		std::cout << "It works" << std::endl;		
		getch();		
	}

	SMOOTH ClassExportDLL::ClassExportDLL()
	{}
}

Compile and create a new project, ClassExportConsole looking like this:

// ClassExportConsole.cpp
#include "stdafx.h"
#include "ClassExportDLL.h"

int _tmain(int argc, _TCHAR* argv[])
{
	SmoothDLL::ClassExportDLL obj = SmoothDLL::ClassExportDLL();
	obj.Output();
}

You should see the text “It works” if all has been compiled correct.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>