How do I include classes from inside a Windows .dll file.

This is probably a relatively covered question. I have attempted to follow various other tutorials on this question online, without any success.

I am using Windows 10 64 bit Home Edition. I am using Dev C++ to leverage the 64 bit TDM compiler for C++ on Windows. This is for the sake of 64 bit Windows C++ executable programming.

I have learned that in C++, if I want to include another class, I use the #include statement, and inside "" and using / smbols for directories, I can specify the other class.

Now, what do I need to to if my other class is inside a .dll file?
I am attempting to compile a main method accessing such a class, without
any success. I also will not be using Microsoft Visual Studio.

In my situation, I possess the .dll file and not any .lib file(s).

How can I access such classes, easily, via one line of code if possible?
Last edited on
The library will need to export its classes, and provide in include file with the definitions.

You project includes this include file to get the symbol declarations, and links with the libraries export library to get the code.
If I am after a class inside a .dll file named

Fred.class

could someone please reply with the source code I need to access a class file
within another C++ main method, including all its methods (functions) and fields,
kindly?
How can I access such classes, easily, via one line of code if possible?

Accessing a class from a DLL would be the same as accessing a function from a DLL.

Easy? Not as easy as accessing Win32 system DLL, but not a lot of work.

For Visual Studio 2017:
https://docs.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=vs-2017

If you want to use a static library:
https://docs.microsoft.com/en-us/cpp/windows/walkthrough-creating-and-using-a-static-library-cpp?view=vs-2017

Visual Studio can create 32-bit and 64-bit executables and DLLs easier than Dev C++ can. The Community version is free, and is more C++17 compliant than TDM.

VS makes managing the dependencies much, much easier.
No, I'm not in a position to be using either of the Visual Studios.

Oddly enough, I can successfully compile and then build/generate my own successful, 64 bit .dll file. I just can't #include my classes from within it.

I can also, in my situation, use directories in directories for things if I need to.

Is there a one line or simple Windows solution that exists, so I can plain just access classes as before? Can someone kindly help me from here?

I don't have any .lib files and I don't have any .h files, just knowledge of a class name.

Is there a default Windows .dll loader that I can use to do this, in 64 bit? Can someone include some code to explain such, with the necessary #include statements, if that is a useful line to pursue? I have found

#include "/Program Files (x86)/Windows Kits/8.1/Include/um/windows.h"

(I am hoping to find a simpler way, to avoid using this).

I believe what I am trying to attain is called implicit linking.

At any rate, can someone show me how to code to load my classes, not from the file tree via use of the #include statement, but from inside a 64 bit .dll, with relatively few commands, perhaps in a way very similar to #include?
Last edited on
Here is an example where I'm implementing my own String Class in a dll and exporting it for use by a client...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//dllStrings.h                                
#if !defined(STRINGS_H)
#define STRINGS_H
#define EXPANSION_FACTOR      2
#define MINIMUM_ALLOCATION   16

class __declspec(dllexport) String
{
 public:
 String();
 String(const TCHAR);
 String(const TCHAR*);
 String(const String&);
 String(const int, bool);
 String(const int, const TCHAR);
 String(int);
 #ifdef x64
 String(size_t);
 String(SSIZE_T);
 #endif
 String(unsigned int);
 String(double);
 String& operator=(const TCHAR);
 String& operator=(const TCHAR*);
 String& operator=(const String&);
 String& operator=(int iNum);
 #ifdef x64
 String& operator=(size_t iNum);
 String& operator=(SSIZE_T iNum);
 #endif
 String& operator=(unsigned int iNum);
 String& operator=(double dblNum);
 String operator+(const TCHAR);
 String operator+(const TCHAR*);
 String operator+(String&);
 String& operator+=(const TCHAR ch);                                               //Add TCHAR to this
 String& operator+=(const String&);                                                //Adds a String to this and assigns it to left of equal sign
 String& operator+=(const TCHAR*);                                                 //Adds a TCHAR*to this and assigns it to left of equal sign
 bool operator==(String&);                                                         //Compares Strings For Case Sensitive Equality
 bool operator==(const TCHAR*);                                                    //Compares String Against TCHAR* For Case Sensitive Equality
 bool operator!=(TCHAR*);                                                          //Compares String Against TCHAR* For Case Sensitive Inequality
 TCHAR operator()(size_t iZeroBasedOffset);                                        //Returns TCHAR At Zero Based Offset In this
 String Allocate(size_t);                                                          //Allocates a String with a specified buffer size
 String& Make(const TCHAR, size_t);                                                //Returns reference to this with iCount ch TCHARs in it
 String Left(size_t);                                                              //Returns String of iNum Left Most TTCHARs of this
 String Right(size_t);                                                             //Returns String of iNum Right Most TTCHARs of this
 String Mid(size_t, size_t);                                                       //Returns String consisting of number of TTCHARs from some offset
 String Replace(TCHAR*, TCHAR*);                                                   //Returns String with 1st TCHAR* parameter replaced with 2nd TCHAR* parameter
 String Remove(TCHAR*);                                                            //Returns A String With All The TCHARs In A TCHAR* Removed (Individual TCHAR removal)
 String Remove(const TCHAR*, bool);                                                //Returns a String with 1st parameter removed.  2nd is bool for case sensitivity.
 String& Retain(TCHAR* pStr);                                                      //Eliminates From this Any Characters Not Found In pStr (individual character removal)
 int InStr(const TCHAR*, bool blnCaseSensitive, bool blnStartLeft);                //Returns one based case sensitive/insensitive offset of a particular TCHAR pStr in a String, starting from left or right (left=true)
 int InStr(const String&, bool blnCaseSensitive, bool blnStartLeft);               //Returns one based case sensitive/insensitive offset of where a particular String is in another String, starting from left or right (left=true)
 int ParseCount(const TCHAR);                                                      //Returns count of Strings delimited by a TTCHAR passed as a parameter
 void Parse(String*, TCHAR);                                                       //Returns array of Strings in first parameter as delimited by 2nd TTCHAR delimiter
 void Format(double dblNumber, size_t iFldLen, size_t iDecPlaces);                 //Returns this by converting double to String with commas every three digits, in iFDldWidth and iDecimal places
 void Format(double dblNum, int iFldWth, int iDecimal, bool blnRightJustified);    //Modifies this By Converting double to String With int iFieldWidth, int iDecimal Places, and bool blnRightJustified Formatting
 void Format(size_t iNum, int iFldLen, TCHAR cSeperator, bool blnRightJustified);  //Modifies this By Converting size_t To cSeperator Delimited String R/L Justified Within iFldLen String.  iFldLen Can Be Zero And Whole String Is Output In Field Large Enough To Contain It
 void Format(SSIZE_T iNum, int iFldLen, TCHAR cSeperator, bool blnRightJustified); //Modifies this By Converting SSIZE_T To cSeperator Delimited String R/L Justified Within iFldLen String.  iFldLen Can Be Zero And String Is Output
 void Money(double dblNum, size_t iFldLen, size_t iOffsetDollarSign);              //Inserts commas every 3 digits into iFldLen String and inserts '$' sign at one based iOffsetDollarSign
 void Money(double dblNum, size_t iFldLen, bool blnDollarSign);                    //Inserts commas every 3 digits into iFldLen String and inserts '$' sign right in front of leftmost digit
 void SetChar(size_t, TCHAR);                                                      //Sets TCHAR at zero based offset in this
 void LTrim();                                                                     //Returns String with leading spaces/tabs removed
 void RTrim();                                                                     //Returns String with spaces/tabs removed from end
 void Trim();                                                                      //Returns String with both leading and trailing whitespace removed
 int iVal();                                                                       //Returns integral value of String
 int Len();                                                                        //Returns Length Of String Controlled By this
 int Capacity();                                                                   //Returns Maximum Permissable TCHARacter Count (One Less Than Allocation).
 TCHAR* lpStr();                                                                   //Returns TCHAR* To String
 void Print(FILE*, bool);                                                          //Outputs String To Console With Or Without CrLf.
 void Print(FILE*, TCHAR*, bool);                                                  //Outputs String To Console With Or Without CrLf.
 void Print(TCHAR*, bool);
 void Print(bool);
 friend String operator+(TCHAR*, String&);
 ~String();                                                                        //String Destructor

 private:
 TCHAR* lpBuffer;
 size_t iLen;
 size_t iCapacity;
};

__declspec(dllexport) String operator+(TCHAR* lhs, String& rhs);
__declspec(dllexport) String Str(double dblNum);
#ifdef x64
String Str(int iNum);
String Str(unsigned int iNum);
String Str(SSIZE_T iNum);
String Str(size_t iNum);
#else
__declspec(dllexport) String Str(int iNum);
__declspec(dllexport) String Str(unsigned int iNum);
#endif 
Because of the 8192 byte limit here I had to remove a lot of comments. Note carefully the __declspec(dllexport) statements. The locations of some of these can be changed, but the above will work (or should) with mingw. Now you have to realize that within the client there are steps that must be taken too. I'll provide them here shortly....

continued....
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class __declspec(dllimport) String
{
 public:
 String();                                                                         //Uninitialized Constructor
 String(const TCHAR);                                                              //Constructor Initializes With A TCHAR.
 String(const TCHAR*);                                                             //Constructor Initializes String With TCHAR*
 String(const String&);                                                            //Constructor Initializes String With Another String (Copy Constructor)
 String(const int, bool);                                                          //Constructor Creates String With User Specified Capacity and optionally nulls out
 String(const int, const TCHAR);                                                   //Constructor initializes String with int # of TCHARs
 String(int);                                                                      //Constructor initializes String with int converted to String
 #ifdef x64
 String(size_t);                                                                   //Constructor initializes String with size_t object converted to String
 String(SSIZE_T);
 #endif
 String(unsigned int); 
...
...
...
};

__declspec(dllimport) String Str(double dblNum);
#ifdef x64
   extern "C" __declspec(dllimport) String Str(int iNum);
   extern "C" __declspec(dllimport) String Str(unsigned int iNum);
   extern "C" __declspec(dllimport) String Str(SSIZE_T iNum);
   extern "C" __declspec(dllimport) String Str(size_t iNum);
#else
   __declspec(dllimport) String Str(int iNum);
   __declspec(dllimport) String Str(unsigned int iNum);
#endif
   



This code is from mingw builds. To reiterate the situation (which is exactly what you want I think), I am defining, declaring, and implementing a String Class in a dll. The class is fully exported and used within a client of the dll. In the client all one needs is the class header, and the import statements to use the class's methods. Hope it helps.
In terms of over arching architectural issues, here are some things that in the fullness of time you may want to ruminate over...

Doing things such as this reveals something of a weakness of C++ in the sense that such exported classes are not usable across multiple languages or even multiple C++ compilers. For example, if you were to build the dll with mingw it would be sheer luck if the code could be utilized by a client built with MSVC. In fact, there is no guarantee it would be usable across different versions of mingw. This is because, while the C++ language specification defines rather strictly what is legal in a source code sense, it makes no guarantees about what the binary footprint of an object shall be.

It is for reasons such as this that Microsoft created the COM (Component Object Model) and OLE (Object Linking and Embedding). Using those technologies, its possible to create objects in Dlls which can be exported and used across multiple versions of C++ compilers and even multiple languages.
I havn't coded in 10 months since I retired, but here is a simplified, compilable example for you. We'll create a CBox Class that calculates a simple cubic foot volume once the length, width, and height are set....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef CBox_h
#define CBox_h

class __declspec(dllexport)CBox
{
 public:
 CBox(double,double,double);  //Constructor
 ~CBox();                     //Destructor
 double GetLength() const;    //m_Length accessor
 double GetWidth()  const;    //m_Width accessor
 double GetHeight() const;    //m_Height accessor
 double Volume()    const;    //Returns Volume() of Box

 private:
 double m_Length;
 double m_Width;
 double m_Height;
};
#endif 


Here would be the CBox.cpp definitions file....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//CBox.cpp
//g++.exe -DBUILD_DLL -O1 -Os -c CBox.cpp -o dllCBox.o
//g++.exe -shared -Wl,--output-def=libdllCBox.def -Wl,--out-implib=libdllCBox.a -Wl,--dll dllCBox.o -o dllCBox.dll -s -s 

#include "CBox.h"

CBox::CBox(double dblLength, double dblWidth, double dblHeight)
{
 this->m_Length=dblLength;
 this->m_Width=dblWidth;
 this->m_Height=dblHeight;
}

CBox::~CBox()
{
 //destructor
}

double CBox::GetLength() const
{
 return this->m_Length;
}

double CBox::GetWidth()  const
{
 return this->m_Width;
}

double CBox::GetHeight() const
{
 return this->m_Height;
}

double CBox::Volume()    const
{
 return m_Length*m_Width*m_Height;
}


In the above CBox.cpp file you can see the mingw command line compilation strings...

1
2
//g++.exe -DBUILD_DLL -O1 -Os -c CBox.cpp -o dllCBox.o
//g++.exe -shared -Wl,--output-def=libdllCBox.def -Wl,--out-implib=libdllCBox.a -Wl,--dll dllCBox.o -o 


It takes - as far as I know, both strings to build the dll with mingw. The first one gives you the dllCBox.o object file/code.

The 2nd string will output a def file - libdllCBox.def, and also dllCBox.dll, which should contain your exported class - here Class CBox. At this point it can be used in a host linking to it, so long as a few things are taken care of. First, here is a simple host....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//g++ Host.cpp -O1 -s -o Host.exe -s libdllCBox.a
#include <cstdio>

class __declspec(dllimport)CBox
{
 public:
 CBox(double,double,double);  //Constructor
 ~CBox();                     //Destructor
 double GetLength() const;    //m_Length accessor
 double GetWidth()  const;    //m_Width accessor
 double GetHeight() const;    //m_Height accessor
 double Volume()    const;    //Returns Volume() of Box

 private:
 double m_Length;
 double m_Width;
 double m_Height;
};

int main()
{
 CBox Box(2.0, 3.0, 4.0);

 printf("Box.GetLength() = %3.2f\n",Box.GetLength());
 printf("Box.GetWidth()  = %3.2f\n",Box.GetWidth());
 printf("Box.GetHeight() = %3.2f\n",Box.GetHeight());
 printf("Box.Volume()    = %3.2f\n",Box.Volume());

 return 0;
}


Note again the command line compilation string at top. It tells the linker that some of the necessary object code will be in libdllCBox.a. Otherwise, in terms of the compiler, it will find the header (declarations) for CBox right in the source code (you can put that in an include if you like).

Anyway, above is a fully buildable example showing one way it can be done. I only do command line compilation because for years now the IDE's have become too complicated.
-In my situation, I am using someone else's (public domain) .dll file. I cannot
alter its content to put in this kind of exporting information.

-I have learned from elsewhere that given the recent compiler that I am using,
that it is possible to link to .dll files. I am presuming that this means I can
thereby just #include C++ classes from inside the .dll. Is this the case?

-If the .dll file is the only other file that I have, is this still possible?

-Since I am using 64 bit TDM on 64 bit Windows, is there anyone who can tell
me what the updated link instruction is? Can I do so to a *.dll file, in a path?

-I am using Dev-C++. Whereabouts should I go to include such a TDM .dll linking
update instruction for the sake of the TDM compiler?
Last edited on
First off, do you know if the dll was built as a 32 bit binary, or a 64 bit binary? You specified you are working in a 64 bit environment and building 64 bit. If the dll is not 64 bit, it won't work. Period.

Second, do you know if the object you wish to access within the dll is a COM object? If so, then you seem to be going about the matter incorrectly. COM objects are accessed through the Windows COM subsystem - not include files.

Thirdly, if the dll wasn't built with the exact build system you are using, there's no guarantee it will work for you, whether you have a lib file or not. That's because every compiler vendor is free to layout binary code as it suits them - there is no standard. That brings us back to the reason for COM/OLE.

Implicit linking is fine if you have standard exported functions. One simply gets a pointer to the function and calls the address through the pointer (properly dealing with function parameters, of course). However, if a class is exported from a dll there are some really nasty issues. Knowledge of the VTable structure and binary layout of the class is necessary to know where the class methods are located ( I'd be surprised if you had that).
That observation kind of brings us back to COM, doesn't it? COM objects have a specified standard binary layout, which is why they can be accessed from multiple programming languages, and without include files or lib/a files.

Also, the 32 bit verses 64 bit build issues aren't difficult to deal with for the builder of the dll. Generally there is only one source code, and the source is run through a 32 bit build system to create the 32 bit dll, and a 64 bit build system to create the 64 bit dll. Of course, for someone such as yourself posessing the dll and trying to use it, it is important to know which one you have!

Accessing a class from a DLL would be the same as accessing a function from a DLL.


With all due respect to FurryGuy, in my opinion, the above is only true if the same build system was used for both host and server, and one has the lib file created through the dll build process (as kbw said). That apparently leaves Poweruserm up the creek without a paddle, or, in more common internet slang - SOL.

That is the reason folks who provide dlls to others - for sale, free, whatever, most generally export functions rather than classes. If functions are exported and one doesn't have the *.lib file, then its only a little bit more hassle to do implicit linking through LoadLibrary(....) and GetProcAddress(....). Then one can call the functions off function pointers. Of course, the header is needed by the compiler so it knows about the function signatures and parameters.

Again, and I feel like I'm beating a dead horse, but that's why COM/OLE was developed, i.e., to solve these nasty problems.
Thanks for the examples, freddie1.
All of this only applies to my situation if I am in a position to alter the .dll. If I can't, these examples don't apply to my situation. I have started up a separate thread, I believe, asking for some assistance with using the compiler to handle this situation for me. Maybe I can get some assistance over there!

http://www.cplusplus.com/forum/windows/248226/
Last edited on
Topic archived. No new replies allowed.