I came from a C#/Java background, so I'm trying to figure out how to create a C++ dll that behaves similar to a C# dll.
I have experimented with __declspec(dllexport)
and __declspec(dllimport)
, but I have only managed to get it to work on static methods. I am sure this is due to my limited understanding.
How can I export classes in C++ (in its entirety including private members) and be able to instantiate them on the referencing end as I would with C#? Some pointer to an online resources/tutorial will also do it.
I started using the MFC dll template, and honestly I have no idea what 90% of them is for and why I'm inheriting from CWinApp. I tried to tag the class with CCppPracticeLibraryApp
but it would no longer compile.
// CppPracticeLibrary.h : main header file for the CppPracticeLibrary DLL
//
#pragma once
#ifndef __AFXWIN_H__
#error "include 'stdafx.h' before including this file for PCH"
#endif
#include "resource.h" // main symbols
#ifdef CCppPracticeLibraryApp_EXPORTS
#define CCppPracticeLibraryApp_API __declspec(dllexport)
#else
#define CCppPracticeLibraryApp_API __declspec(dllimport)
#endif
// CCppPracticeLibraryApp
// See CppPracticeLibrary.cpp for the implementation of this class
//
class CCppPracticeLibraryApp : public CWinApp
{
public:
CCppPracticeLibraryApp();
static CCppPracticeLibraryApp_API void SayHelloWorld();
// Overrides
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
the definition file:
//CppPracticeLibrary.cpp : Defines the initialization routines for the DLL.
#include "stdafx.h"
#include "CppPracticeLibrary.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define CCppPracticeLibraryApp_EXPORTS
BEGIN_MESSAGE_MAP(CCppPracticeLibraryApp, CWinApp)
END_MESSAGE_MAP()
// CCppPracticeLibraryApp construction
CCppPracticeLibraryApp::CCppPracticeLibraryApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
void CCppPracticeLibraryApp::SayHelloWorld()
{
printf( "Hello world");
}
// The one and only CCppPracticeLibraryApp object
CCppPracticeLibraryApp theApp;
// CCppPracticeLibraryApp initialization
BOOL CCppPracticeLibraryApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
The client/referencing method
// TestConsoleApplication.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "TestConsoleApplication.h"
#include "CppPracticeLibrary.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
/*CCppPracticeLibraryApp* testCallingLibrary = new CCppPracticeLibraryApp();
testCallingLibrary->SayHelloWorld();*/
CCppPracticeLibraryApp::SayHelloWorld();
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
I would like to be able to uncomment the following lines in the above code:
/*CCppPracticeLibraryApp* testCallingLibrary = new CCppPracticeLibraryApp();
testCallingLibrary->SayHelloWorld();*/
From MSDN
To export all of the public data members and member functions in a class, the keyword must appear to the left of the class name as follows:
class __declspec(dllexport) CExampleExport : public CObject
{ ... class definition ... };
Also, consider that there are more ways to do this, like .DEF
-files.
Take your time to read through the explanations on the MSDN-site.
With __declspec(dllexport) and __declspec(dllimport) you just create kind of an api which can be used to export methods or members from your dll. By exporting this methods you can access it from another dlll. What you can do is to create a header file where you will define your export macro.
ifdef MYPROJECT_EXPORTS
define MYPROJECT_EXPORTS__declspec( dllexport )
else
define MYPROJECT_EXPORTS__declspec( dllimport )
endif
and when you declare your method, if you want to export it, you just need to put your macro before your method declaration, like this:
MYPROJECT_EXPORTS void myMethod();
And also you have to add your symbol into the Preprocesor Definitions ( in MS Visual Studio --> Project Properties --> C/C++ -->Preprocessor --> Prerocessor Definitions.
In order to export all members of a class you can include the declspec
in it's declaration like below.
class __declspec(dllexport) ExportedClass
{
//....
};
You must read this very interesting article on CodeProject on this subject.
Note that if you build a DLL with C++ classes at the boundaries (including MFC classes, or STL classes), your DLL client must use the same VC++ compiler version and the same CRT flavor (e.g. multithreaded DLL debug CRT, multithreaded DLL release CRT, and other "more subtle" settings, e.g. same _HAS_ITERATOR_DEBUGGING
settings) to build the EXEs that will use the DLL.
Instead, if you export a pure C interface from the DLL (but you can use C++ inside the DLL, just like Win32 APIs), or if you build COM DLLs, your DLL clients can use a different version of VC++ compiler (and even different CRTs) to use your DLL.
Moreover, pay attention also to what the aforementioned article defines as "C++ Mature Approach" (i.e. using an abstract interface).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With