Access class members from DLL (NOT LIB!!!) - c++

I have a dll and I even have the header files for the dll, but I don't have the implementation neither the lib file for the dll. I try to load up the dll with the QLibrary class and get class instance from it. I successfully retrieved the class after 2hours, but when I try to call a function on the object I get unresolved external symbol which tells me that the dll did not exported properly. For simplicity I re-created the issue with the following sources:
DLL-Project (testlibrary_global.hpp):
#ifndef TESTLIBRARY_GLOBAL_HPP
#define TESTLIBRARY_GLOBAL_HPP
#include <QtCore/qglobal.h>
#if defined(TESTLIBRARY_LIBRARY)
# define TESTLIBRARYSHARED_EXPORT Q_DECL_EXPORT
#else
# define TESTLIBRARYSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // TESTLIBRARY_GLOBAL_HPP
DLL-Project (testlibrary.hpp):
#ifndef TESTLIBRARY_HPP
#define TESTLIBRARY_HPP
#include "testlibrary_global.hpp"
#include <QDebug>
class TESTLIBRARYSHARED_EXPORT TestLibrary {
public:
TestLibrary();
~TestLibrary();
void Test();
};
extern "C" TESTLIBRARYSHARED_EXPORT TestLibrary* getInstance();
#endif // TESTLIBRARY_HPP
DLL-Project (testlibrary.cpp):
#include "testlibrary.hpp"
TestLibrary::TestLibrary() {
qDebug() << "Constructor called!";
}
TestLibrary::~TestLibrary() {
qDebug() << "Destructor called!";
}
void Test() {
qDebug() << "Hello from library!";
}
TestLibrary *getInstance() {
return new TestLibrary();
}
This is very straight forward, does not contain anything fancy really. As you can see I kept the class default as the QtCreator does did not change anything, except added another function with extern "C" and the export defined in global. the purpose of this would be to get an object from the dll itself, (since I have the .h and .dll nothing else). Now for the loader application, again dirty yet simple basic stuff:
#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>
#include "testlibrary.hpp"
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QString libPath = QString("C:/Users/johorvat/Documents/QTProjects/build-TestLibrary-Desktop_Qt_5_2_0_MSVC2010_32bit_OpenGL-Debug/debug/TestLibrary.dll");
QLibrary lib(libPath);
bool loaded = lib.load();
QString error = lib.errorString();
qDebug() << "Loaded: " << loaded;
typedef TestLibrary* (*Prototype)();
Prototype Func = (Prototype) lib.resolve("getInstance");
if (Func) {
TestLibrary* tl = Func();
if (tl) {
qDebug() << "Yey, I gotta clazz!";
}
}
return a.exec();
}
I added the header file to the project because i have it anyway. I used QLibrary to load up the dll and retrieved the getInstance method from it with which I could get an instance of the TestLibrary class. However if I try to call the Test() method of TestLibrary within the if(tl) { ... } i get an unresolved external symbol error message that tells me it can't find the definition of the Test method.
What am I missing in here?
P.S.: I won't get lib files so let's focus on the problem with the dll loading :).
Regards,
Joey

Well since you've written void Test() { in your .cpp file and not void TestLibrary::Test { your function isn't being defined and so it isn't exported at all.
EDIT:
After this code like that works fine and prints "Hello" in qDebug (dll should be compiled in debug, I failed on that the first time)
QFunctionPointer raw = lib.resolve("?Test#TestLibrary##QEAAXXZ");
TestPrototype testFunc;
*(QFunctionPointer*) &testFunc = raw;
(tl->*testFunc) ();
Decorated function name is not very nice but I don't know what exactly can be done about it :) And also you'll get differently mangled names with different compilers so using Qt in this case will not be cross-platform anyway.

Related

Call main executable's functions from plugin compiled using Clang

I'm writing a program (macOS, clang++ compiler, only AppleSilicon at the moment) that I can extend later by providing custom plugins (dynamic library, loaded at runtime) which use main program's public interface.
test.hpp - public interface:
#if defined(MAGIC_PLUGIN)
# define MAGIC_EXPORT /* nothing */
#else
# define MAGIC_EXPORT __attribute__((visibility("default")))
#endif
MAGIC_EXPORT
void testCall();
test.cpp - main programm:
#include <stdio.h>
#include <dlfcn.h>
#include "test.hpp"
// Declare a function to call from a loaded plugin
typedef void (* plugin_call_func)(void);
int main(int argc, char** argv) {
// Load library
const char* libraryName = "plugin.dylib";
void* library = dlopen(libraryName, RTLD_NOW);
if (library == nullptr) {
printf("Cannot open library\n");
return 1;
}
// Get function from loaded library
plugin_call_func pluginCall = reinterpret_cast<plugin_call_func>(
dlsym(library, "pluginCall"));
if (pluginCall == nullptr) {
printf("Cannot find the pluginCall function\n");
return 2;
}
// Execute loaded function
pluginCall();
// Forget function and close library
pluginCall = nullptr;
auto libraryCloseResult = dlclose(library);
if (libraryCloseResult != 0) {
printf("Cannot close library\n");
return 3;
}
return 0;
}
// Public function, should be called from a plugin
void testCall() {
printf("Test call\n");
}
plugin.cpp - plugin's source:
#define MAGIC_PLUGIN
#include <stdio.h>
#include "test.hpp"
__attribute__((visibility("default")))
extern "C" void pluginCall(void) {
printf("Plugin call\n");
testCall();
}
First, I compile main app:
clang++ -std=c++20 -fvisibility=hidden -target arm64-apple-macos12 test.cpp -o test
The nm --defined-only test shows these symbols:
0000000100003ee4 T __Z8testCallv
0000000100000000 T __mh_execute_header
0000000100003dcc t _main
Mangled __Z8testCallv is what I need. Everything looks good so far. But then I try to compile the plugin as dynamic library...
clang++ -std=c++20 -fvisibility=hidden -dynamiclib -g -current_version 0.1 -target arm64-apple-macos12 plugin.cpp -o plugin.dylib
and get this error:
Undefined symbols for architecture arm64:
"testCall()", referenced from:
_pluginCall in plugin-38422c.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Well, it's kind of fair, I can understand this, because the dynamic library does not know that testCall is somewhere implemented. So I want to say it that it does not have to worry about testCall's existence.
I tried to research how to do this, looked up man pages, read tons of stack overflow answers, and what I only found that works is adding these flags to linker:
-Wl,-undefined,dynamic_lookup
It works, the library compiles and the app works as expected. But I don't really want to use dynamic_lookup because it will mark every undefined symbol in the library as resolved, which may lead to some bad consequences. I want to tell the linker only about existence of the main program's public symbols.
What am I missing? Is there any better solution than dynamic_lookup?
Your best bet is to manually do the work that's done by the library loader. That is: populating function pointers. After all, the plugin->main binding is already done manually, so doing the same thing the other way around makes sense.
You can make this process essentially transparent by carefully crafting the header shared by the plugin and main application. The only tricky part is handling ODR for plugins that are composed of multiple source files.
Since this is a C++ question, here's what it could look like with a RAII wrapper. The ODR conundrum is handled via the PLUGIN_MAIN macro that should only be defined in one of a plugin's sources.
test_plugin.hpp
using pluginCall_fn = void(*)();
using testCall_fn = void(*)();
#if !defined(MAIN_APPLICATION)
#if defined(PLUGIN_MAIN)
#define EXPORTED_FROM_MAIN __attribute__((visibility("default")))
#else
#define EXPORTED_FROM_MAIN __attribute__((visibility("default"))) extern
#endif
extern "C" {
// Declare symbols provided by the plugin
__attribute__((visibility("default"))) void pluginCall();
// etc...
// Declare/define pointers that will be populated by the main application
EXPORTED_FROM_MAIN testCall_fn testCall;
// etc...
}
#undef EXPORTED_FROM_MAIN
#else // In the main app.
#include <stdexcept>
// Declare "symbols" provided by the main application
void testCall();
// Utility class to load/unload a dynamic library.
// Probably belongs in its own header...
struct loaded_library final {
loaded_library(const char* libName)
: handle_(dlopen(libName, RTLD_NOW)) {
if(!handle_) {
throw std::runtime_error("failed to load plugin");
}
}
loaded_library(const loaded_library&) = delete;
loaded_library& operator=(const loaded_library&) = delete;
loaded_library(loaded_library&& rhs) : handle_(rhs.handle_) {
rhs.handle_ = nullptr;
}
loaded_library& operator=(loaded_library&& rhs) {
handle_ = rhs.handle_;
rhs.handle_ = nullptr;
return *this;
}
~loaded_library() {
if(handle_) {
dlclose(handle_);
}
}
template<typename T>
T get_symbol(const char* symbol) {
T result = reinterpret_cast<T>(dlsym(handle_, symbol));
if(!result) {
throw std::runtime_error("missing symbol");
}
return result;
}
private:
void* handle_;
};
// Plugin interface.
struct loaded_plugin final {
loaded_plugin(const char* libName)
: lib_(libName) {
// Load functions from plugin
pluginCall = lib_.get_symbol<pluginCall_fn>("pluginCall");
// ...
// Assign callbacks to plugin
*lib_.get_symbol<testCall_fn*>("testCall") = &testCall;
// ...
// Call the plugin's init function here if applicable.
}
pluginCall_fn pluginCall;
private:
loaded_library lib_;
};
#endif
plugin.cpp
#define PLUGIN_MAIN
#include "test_plugin.hpp"
#include <stdio.h>
void pluginCall() {
printf("Plugin call\n");
testCall();
}
test.cpp
#define MAIN_APPLICATION
#include "test_plugin.hpp"
int main(int argc, char** argv) {
const char* libraryName = "plugin.dylib";
loaded_plugin plugin(libraryName);
plugin.pluginCall();
}
// Public function, should be called from a plugin
void testCall() {
printf("Test call\n");
}
You may find that this code is a bit on the fragile side of things, since a few different portions of test_plugin.hpp need to be kept in sync.
This can be worked around with the use of X-Macros, at the cost of confusing IDEs and hurting code legibility. I wouldn't go down that road until the APIs in question become unwieldingly large.

How to export a function of a regular MFC DLL that is statically linked to MFC to use with a non MFC Win32 Console App in C++

I am very new in C++ world and this kind of task.
I am having a hard time to resolve this issue.
Any help is kindly appreciated!
I have created a regular MFC DLL that is statically linked to MFC. (This is the first time i ever created a MFC project)
MFC DLL Header File Content
// Serial.h
#pragma once
#ifndef __AFXWIN_H__
#error "include 'pch.h' before including this file for PCH"
#endif
#include "resource.h" // main symbols
class SerialApp : public CWinApp
{
public:
SerialApp();
__declspec(dllexport) void __cdecl SerialApp::Init();
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
MFC DLL Definition File Content
// Serial.cpp
#pragma once
#include "pch.h"
#include "framework.h"
#include "Serial.h"
#include <iostream>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
BEGIN_MESSAGE_MAP(SerialApp, CWinApp)
END_MESSAGE_MAP()
SerialApp::SerialApp()
{
}
SerialApp theApp;
BOOL SerialApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
extern "C"
{
__declspec(dllexport) void __cdecl SerialApp::Init()
{
AfxDebugBreak();
std::cout << "Succeded";
}
}
Win32 Console Application Content
#include <iostream>
#include <Windows.h>
int main()
{
//Load the DLL
HMODULE lib = LoadLibrary(L"D:\\C++ PROJECTS\\serial\\Debug\\Serial.dll");
//Create the function
typedef void(*Init_t)(void);
Init_t Serial = (Init_t)GetProcAddress(lib, "Init");
std::cout << GetLastError(); // This output's 127
if (!Serial) {
//ERROR. Handle it.
}
__declspec(dllimport) void __cdecl Init(void);
//Init(); //LNK2019 unresolved external symbol "__declspec(dllimport) void __cdecl Init(void)"
std::getchar();
}
When i use this approach:
__declspec(dllimport) void __cdecl Init(void);
Init();
//I am getting the linker error LNK2019 unresolved external symbol "__declspec(dllimport) void __cdecl Init(void)"
When i use this approach:
typedef void(*Init_t)(void);
Init_t Serial = (Init_t)GetProcAddress(lib, "Init");
std::cout << GetLastError();
//I am getting error code 127 from the GetLastError() function. (The specified procedure could not be found)
When i use this approach:
#include "Serial.h"
int main()
{
SerialApp pSerial;
pSerial.Init();
std::getchar();
}
//Serial.h forces me to include 'pch.h' before itself. if i include 'pch.h' into Win32 Console App before Serial.h It end's up with about 1000's of errors.
For Win32 Console Application Project:
1. C/C++ -> General -> Additional Include Directories is set to: D:\C++ PROJECTS\serial\Serial
2. Linker -> Input -> Additional Dependencies is set to : Serial.lib
3. Both Serial.lib and Serial.dll are included in the project and in the Debug folder.
4. Both MFC Dll Project and Win32 Console Projects are compiled in Debug x86 mode.
Questions
What i am doing wrong?
Is this even possible?
Thank you!
The question is resolved by #dxiv's comment:
You cannot import a member function like SerialApp::Init to a non-MFC app,
because that app does not know about the SerialApp class, and cannot
know about it since SerialApp is derived from CWinApp which is an MFC
class, while your app is non-MFC. If you want to export a free
function from the DLL, then make it __declspec(dllexport) void __cdecl Init(void); outside the SerialApp class, or any class for that matter.
1. I removed the declaration __declspec(dllexport) void __cdecl SerialApp::Init(); from the header file.
2. Rewrite the definition of Init() in the Serial.cpp file as:
extern "C"
{
__declspec(dllexport) void __cdecl Init()
{
std::cout << "Succeded";
}
}
3. I call the function in Win32 Console App as:
int main()
{
//Load the DLL
HMODULE lib = LoadLibrary(L"D:\\C++ PROJECTS\\serial\\Debug\\Serial.dll");
//Create the function
typedef void(*Init_t)(void); // <- You can name Init_t whatever you want.
Init_t Serial = (Init_t)GetProcAddress(lib, "Init");
if (!Serial) {
std::cout << GetLastError();
return 1;
}
Serial(); //<- Init() Function Call from Serial.dll
std::getchar();
return 0;
}
And all worked great!
Thank you everyone, who make time to read and answer my Question!

Linker unresolved external symbols - can't find functions in dll

I am working in Visual Studio C++.
I made an class with a non-static function and packaged it as a dll. Here is the code to generate my dll:
// head file
#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_
#include <string>
#include <memory>
#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport)
#else
#define MATHFUNCSDLL_API __declspec(dllimport)
#endif
MATHFUNCSDLL_API class Functions
{
public:
MATHFUNCSDLL_API void func(int, std::string);
};
extern "C" MATHFUNCSDLL_API Functions * __cdecl create_class();
#endif
// cpp file
#include "stdafx.h"
#include "Functions.h"
#include <iostream>
void Functions::func(int id, std::string name)
{
std::cout << "Your ID: " << id << ". Your name: " << name << std::endl;
}
Functions * create_class()
{
std::cout << __FUNCTION__ << std::endl;
return new Functions();
}
Now I have a C++ project that loads this dll dynamically. Here is the code:
#include <iostream>
#include <Windows.h>
#include "../../testDmcDLL/testDmcDLL/Functions.h"
typedef Functions *(__stdcall *f_funci)();
int main(int argc, char ** argv)
{
HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\Documents\\Visual Studio 2013\\Projects\\testDmcDLL\\Debug\\testDmcDLL.dll");
f_funci func_create_class = (f_funci)GetProcAddress(hGetProcIDDLL, "create_class");
Functions * pf = func_create_class();
////LNK error////pf->func(1, "toto");
system("pause");
return 0;
}
I can make sure that hGetProcIDDLL and func_create_class have been initialized successfully (I've tested them with if, but here I removed the if).
When I run this project, I can see that create_class is shown on the console because there is std::cout << __FUNCTION__ << std::endl; in that function. So everything looks fine.
However, when I compile it with the code pf->func(1, "toto") uncommented, I get a linker (LNK2019) error:
Error 1 error LNK2019: unresolved external symbol
"__declspec(dllimport) public: void __thiscall
Functions::func(int,class std::basic_string,class std::allocator >)"
(__imp_?func#Functions##QAEXHV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
referenced in function _main c:\documents\visual studio
2013\Projects\testLoadDmcDLL\testLoadDmcDLL\main.obj testLoadDmcDLL
The class definition is not quite right with the exports, it should be of the form;
class MATHFUNCSDLL_API Functions // MATHFUNCSDLL_API moved
{
public:
void func(int, std::string); // MATHFUNCSDLL_API removed
};
Once a class is exported, all its members are exported.
You don't mention how MATHFUNCSDLL_EXPORTS is defined during compilation (from the command line or possibly in the stdafx.h), but make sure it is defined when building the dll, but not when building the exe. Be sure to link against the .lib produced with the .dll.
Notes on the LoadLibrary and GetProcAddress usage; if you require the dll to be loaded dynamically, you need to get the C++ class member function bound to the exported function. I've not seen a successful implementation of this or if it is even reasonable possible. If the use of the LoadLibrary and GetProcAddress is required, consider using an abstract class and create the object in a factory of some sort.
You don't detail the motivation for the dynamic loading of the dll, but consideration could also be given the delay loading the dll.
If the motivation is to delay the loading of the dll, but the same dll is always used, then the delay-load linking may help. If the motivation is to load an unknown dll (by name/location) based on some runtime parameter (or configuration), then the virtual base class and a single C-style function as a factory for the object is probably the preferred solution.
There is a good code project article on this describing various solutions for this. In particular using the abstract base class is very portable.
If you don't rely on the import library but call GetProcAddress, you need to do that for every function you're importing. You never called GetProcAddress for __imp_?func#Functions##QAEXHV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z (which is how your Functions::func is mangled in the DLL).
Also, be aware that you get a function pointer from GetProcAddress. While that points to the code implementing pf->func, function pointers aren't called with member function call syntax.
The root problem is that GetProcAddress really is designed for C, not C++.

dll export function pointer (best way to provide exported function hooking)

I am trying to export a function pointer for a function to be called. What I am after is when a function in a dll/exe needs to call a function exported by another library it gets the function pointer and calls that. The reason for this is I want to provide a hooking mechanism and I figured function pointers would be the quickest and easiest way because I can change what they point to easily are runtime.
So I found this Exporting a function pointer from dll and I cant get it to work. Whenever I call it to get the function pointer I get an error that it cant find the entry point. So the error isnt that the function pointer is working but the function to get the function pointer isnt working. I believe it is a function signature issue. Here is an example:
Colors.h
#ifndef __COLORS
#define __COLORS
#ifdef MYDLL_EXPORTS
/*Enabled as "export" while compiling the dll project*/
#define DLLEXPORT __declspec(dllexport)
#else
/*Enabled as "import" in the Client side for using already created dll file*/
#define DLLEXPORT __declspec(dllimport)
#endif
#include <string>
#include <vector>
class Colors
{
private:
std::string myColor;
static DLLEXPORT std::vector<std::string> allColors;
public:
Colors(){};
Colors(std::string MyColor);
virtual DLLEXPORT std::string getMyColor();
virtual DLLEXPORT void addToColors(std::string color);
std::vector<std::string> getAllColors();
};
typedef Colors* (*create)(std::string);
DLLEXPORT create createColors();
Colors* createColors2(std::string color);
#endif
colors.cpp
#define MYDLL_EXPORTS
#include "Color.h"
std::vector<std::string> Colors::allColors;
Colors::Colors(std::string MyColor)
{
this->myColor = MyColor;
this->allColors.push_back(this->myColor);
}
std::vector<std::string> Colors::getAllColors()
{
return this->allColors;
}
std::string Colors::getMyColor()
{
return this->myColor;
}
Colors* createColors2(std::string color)
{
return new Colors(color);
}
DLLEXPORT void Colors::addToColors(std::string color)
{
this->allColors.push_back(color);
}
DLLEXPORT create createColors()
{
return &createColors2;
}
main.cpp
#define MYDLL_EXPORTS
#include <iostream>
#include <Windows.h>
#include "Color.h"
int main()
{
Colors red("red");
Colors blue("blue");
Colors* dlltest;
//Define the function prototype
typedef Colors* (*createNewColor)();
BOOL freeResult, runTimeLinkSuccess = FALSE;
HINSTANCE dllHandle = NULL;
createNewColor dllCreateNewColor = NULL;
//Load the dll and keep the handle to it
dllHandle = LoadLibrary(L"libs/testerdll.dll");
// If the handle is valid, try to get the function address.
if (NULL != dllHandle)
{
//Get pointer to our function using GetProcAddress:
dllCreateNewColor = (createNewColor)GetProcAddress(dllHandle,"createNewColor");
// If the function address is valid, call the function.
if (runTimeLinkSuccess = (NULL != dllCreateNewColor))
{
dlltest = dllCreateNewColor();
std::cout << "Color of dll class: " << dlltest->getMyColor() << std::endl;
}
else
{
std::cout << "Failed to locate function" << std::endl;
}
//Free the library:
//freeResult = FreeLibrary(dllHandle);
}
else
{
std::cout << "Failed to load library" << std::endl;
}
std::vector<std::string> colorslist = red.getAllColors();
for (std::string color : colorslist)
{
std::cout << color << std::endl;
}
return 0;
}
Dll project
dllmain.cpp
// testerdll.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "Color.h"
__declspec(dllexport) Colors* createNewColor()
{
create temp1 = createColors(); //seems to fail here
return nullptr;
}
Yes I know I have memory leaks etc. this was just a quick example code to replicate the problem.
To return the function, you need to get it's address, and return that
e.g.
__declspec(dllexport) create createNewColor()
{
create temp1 = createColors;
return temp1;
}
However, this system (using std::string as a return type, requires that both the .exe and the .dll use the same DLL based runtime library.
stackoverflow : passing reference to STL over function boundary
C++ does not define a calling convention between files. This means that different compilers may set up C++ objects slightly differently. Microsoft limited that with the definition of COM, but that still is a possibility.
Also for visual studio, there are separate heaps (new / delete) between runtime instances. When you link against the dynamic library, all dlls and exes in the process share this DLL. But then they all need to be updated together.
So this process can work, but be wary about :-
Sharing C++ types between binaries (DLL/EXE) - no ABI
Using new in DLL, and delete in EXE. (different heaps).
STL objects are also problematic, as they are a mixture of header implementation (compiled into the binary), and DLL implementation (compiled into C++ runtime).

How to implement a Singleton in an application with DLL

I have an application (in MS Visual Studio) that contains 3 projects:
main (the one that contains the main function)
device (models some hardware device)
config (contains some configuration for both other projects)
So the dependency graph is:
main depends on device, which depends on config
main depends on config
The config project contains a Singleton, which holds some configuration parameters.
I decided to turn the device project into a DLL. When i did this, it seems that i got two instances of the Singleton in the config project! I guess this is a classic problem, which might have a good solution. So how can i fix this?
I reproduced the problem with the following (relatively small) code. Of course, in my case there are some 30 projects, not just 3. And i would like to make just 1 DLL (if possible).
// config.h
#pragma once
#include <string>
#include <map>
class Config
{
public:
static void Initialize();
static int GetConfig(const std::string& name);
private:
std::map<std::string, int> data;
};
// config.cpp
#include "config.h"
static Config g_instance;
void Config::Initialize()
{
g_instance.data["one"] = 1;
g_instance.data["two"] = 2;
}
int Config::GetConfig(const std::string& name)
{
return g_instance.data[name];
}
// device.h
#pragma once
#ifdef _DLL
#define dll_cruft __declspec( dllexport )
#else
#define dll_cruft __declspec( dllimport )
#endif
class dll_cruft Device
{
public:
void Work();
};
// device.cpp
#include "device.h"
#include <iostream>
#include "config.h"
void Device::Work()
{
std::cout << "Device is working: two = " << Config::GetConfig("two") << '\n';
}
// main.cpp
#include <iostream>
#include "config.h"
#include "device.h"
int main()
{
std::cout << "Before initialization in application: one = " << Config::GetConfig("one") << '\n';
Config::Initialize();
std::cout << "After initialization in application: one = " << Config::GetConfig("one") << '\n';
Device().Work();
std::cout << "After working in application: two = " << Config::GetConfig("two") << '\n';
}
Output:
Before initialization in application: one = 0
After initialization in application: one = 1
Device is working: two = 0
After working in application: two = 2
Some explanations on what the code does and why:
Main application starts
The first print is just to show that the singleton is not initialized yet
Main application initializes the singleton
The first print shows that the initialization worked
Main application starts the "hardware device"
Inside the DLL, the singleton is not initialized! I expect it to output two = 2
The last print shows that the singleton is still initialized in main application
When I ran into this same problem I solved it by creating another DLL whose sole purpose is to manage the singleton instance. All attempts to get a pointer to the singleton call the function inside this new DLL.
You can decide where singleton should reside and then expose it to other consumers.
Edited by OP:
For example, i want that the config instance appear only in the EXE (not DLL).
Turn the instance into a pointer
static Config* g_instance;
Add a separate initializing function to device's exported functions:
void InitializeWithExisting(Config* instance) {g_instance=instance;}
After initializing the singleton normally, use the second initialization:
Config::Initialize();
Config::InitializeWithExisting();
I believe that defining and accessing singleton instance this way might solve your problem:
Config& getInstance()
{
static Config config;
return config;
}
This way you also don't need to have (and call) the Initialize method, you can use constructor for initializing, that will be called automatically when you call getInstance for the first time.