static variables empty when using dynamic loading of library - c++

I have this setup:
ClassA.h - belongs to libA.dll
class ClassA
{
public:
static std::vector<std::string> getStrings();
~ClassA();
static void addToVector(std::string s);
static void setAddAllowed(bool addAllowed);
private:
ClassA();
};
extern "C"
{
extern void addToStrings(std::string s);
}
ClassA.cpp
#include<ClassA.h>
#include<vector>
static std::vector<std::string> strings;
static bool addAllowed = false;
std::vector<std::string> ClassA::getStrings()
{
return strings;
}
void ClassA::addToVector(std::string s)
{
if (addAllowed)
{
strings.push_back(s);
}
}
void ClassA::setAddAllowed(bool add)
{
addAllowed = add;
}
extern void addToStrings(std::string s)
{
ClassA::addToVector(s);
}
ClassB.h - belongs to libB.dll
class ClassB
{
public:
static void addString(std::string s);
};
ClassB.cpp
#include<ClassB.h>
#include<ClassA.h> //not present if libA is dynamically loaded.
void ClassB::addString(std::string s)
{
addToStrings( s ); // problem if addToStrings is called with a function pointer obtained from dynamic loading of libA.dll - libB doesn't depend on libA actually.
}
ClassC.h
class ClassC
{
public:
static void setAddAllowed(bool add);
};
ClassC.cpp
#include<ClassA.h>
#include<ClassC.h>
void ClassC::setAddAllowed(bool addAllowed)
{
ClassA::setAddAllowed(addAllowed);
}
Main.cpp
int main()
{
ClassB::addString("example1");
ClassC::setAddAllowed( true );
ClassB::addString("example2");
ClassB::addString("example3");
std::vector<std::string> v = ClassA::getStrings();
}
with this setup, every thing works fine, I could get the strings in ClassA::getStrings(). But the problem appears - the vector is empty, if I add the strings in ClassB using function pointer obtained from dynamically loaded dll of libA. I get the symbol of extern function addToStrings as function pointer and make a call. In that case, the vector v is empty.
Example code for loading libA and calling the function:
typedef void (*addToStringsFP) (std::string s);
addToStringsFP fp = NULL;
Handle libHandle = NULL;
libHandle = LoadImage("libA",0);
fp = (addToStringsFP)FindSymbol(libHandle,"addToStrings");
This is only to demonstrate how I am loading libA and calling the function pointer. LoadImage, FindSymbol are similar to dlopen(), dlsym() - I can't post actual names.
What am I misunderstanding here ?

I found the answer.
The LoadImage function that I am using is loading a new image into the process instead of looking at already loaded dlls first and then load.
I had to use a different version of the LoadImage which loads the image that is currently in the process- basically a shared image. That solved the problem.
I thought it might be useful to someone who may have some problem albeit not much probable I think.

Related

Best practice for a global config

I have several c++ programs that are all reading a YAML configuration file in /etc/foo/config.yml. I have written a function that reads the config from the file
YAML::Node load_config();
(using the yaml-cpp library).
I would like this configuration to be loaded once, at the beginning of the main() function of my program, and then accessible everywhere as some kind of global variable.
Currently, many of my functions have extra parameters that are just values read from the configuration file. It could be avoided by having this global configuration, making my function definitions and calls much simpler and readable.
Side note: I am also using OpenMP for distributing computation, which means that the configuration must be accessible to all parallel processes.
Could someone give a tiny example of what this would look like when done the right way?
Thanks!
here's one way. It's a variation on the idea of the schwartz counter to manage a global singleton (for example, std::cout itself)
// globals.hpp
#include <istream>
struct globals_object
{
globals_object()
{
// record number of source files which instanciate a globals_object
++init_count_;
}
~globals_object()
{
// The last source file cleans up at program exit
if(--init_count_ == 0)
{
if (pimpl_)
{
delete pimpl_;
}
}
}
// internal implementation
struct impl
{
void load(std::istream& is)
{
// do loading code here
}
int get_param_a() const {
return a_;
}
int a_;
};
// (re)load global state
void load(std::istream&& is)
{
if (pimpl_) delete pimpl_;
pimpl_ = new impl;
pimpl_->load(is);
}
// public parameter accessor
int get_param_a() const {
return get_impl().get_param_a();
}
private:
static int init_count_;
static impl* pimpl_;
static impl& get_impl()
{
return *pimpl_;
}
};
// one of these per translation unit
static globals_object globals;
// globals.cpp
// note - not initialised - will be zero-initialised
// before global constructors are called
// you need one of these in a cpp file
int globals_object::init_count_;
globals_object::impl* globals_object::pimpl_;
// main file
// #include "globals.hpp"
#include <fstream>
int main()
{
globals.load(std::ifstream("settings.yml"));
}
// any other file
// #include "globals.hpp"
#include <iostream>
void foo()
{
std::cout << globals.get_param_a() << std::endl;
}

Keep a shared library from using its own exports

Good evening,
I have a library that imports another library which exports a function, lets call it foo(). I want my library to serve as a wrapper for the other library. That means, I want my library to export a function foo() which internally calls the function foo() from the other library. Something like this:
myfoo.hpp:
__attribute__((visibility("default"))) void foo(); //my foo() export
myfoo.cpp:
#include "myfoo.hpp"
#include "wrapperfoo.hpp"
void foo()
{
wrapperfoo();
}
wrapperfoo.cpp:
#include "wrapperfoo.hpp"
#include "theotherapifoo.hpp"
void wrapperfoo()
{
::foo(); //PROBLEM!! This seems to call my own exported foo from myfoo.hpp!!!
}
The problem is that both dynamic libraries get linked into the executable and my wrapperfunction seems to recursively call my own exported foo function over and over despite wrapperfoo.cpp not including myfoo.hpp!
What can I do to prevent this from happening and access the other libraries foo()?
One workaround would be to dynamically link the library using dlopen() or similar.
#include <cstring>
#include <dlfcn.h>
#include <stdexcept>
struct OriginalLibrary {
using FunPtr = void(*)();
OriginalLibrary()
: m_lib([] {
if (void * const lib = dlopen("libdl.so", RTLD_NOW))
return lib;
throw std::runtime_error(dlerror());
}())
, m_foo(getFunSym("foo"))
{}
~OriginalLibrary() noexcept { dlclose(m_lib); }
FunPtr getFunSym(char const * const name) {
if (void * const sym = dlsym(m_lib, name)) {
FunPtr f;
// Assuming function and data pointers are of
// same size and binary-compatible on your arch:
std::memcpy(&f, &sym, sizeof(f));
return f;
}
throw std::runtime_error(dlerror());
}
void * const m_lib;
void (* m_foo)();
};
// WARNING! Global symbol! (you might want to solve this in some other manner)
OriginalLibrary original;
void foo() { return original.m_foo(); }

Undefined reference to function from static pointer

I'm experimenting around with dll loading on runtime and I have a problem: I have a little helper class which is istanciated in the main program. The pointer to this object is handed to the loaded dll. To test it, i want to call a function from the class (printLine). But I can't compile the dll because I get a:
Utility.o: In function `ZN7Utility6onInitEv':
D:\Benutzer\Jan\Desktop\Programmierprojekte\Game Engine 5.0\Utilities\Debug/../Utility.cpp:7: undefined reference to `ModuleHelper::printLine(std::string)'
collect2.exe: error: ld returned 1 exit status
These two files are the only content of the dll:
Utility.h:
#ifndef UTILITY_H_
#define UTILITY_H_
#include <iostream>
#include <Definitions.h>
#include <ModuleHelper.h>
class Utility
{
public:
Utility();
~Utility();
static void onInit();
static void onUpdate();
static char* getName();
static char** getDependencies();
static int getCountDependencies();
static char* getServeAs();
static void setModuleHelper(ModuleHelper* helper);
private:
static constexpr char* name = "Utility";
static constexpr char** dependencies = nullptr;
static constexpr int countDependencies = 0;
static constexpr char* serveAs = "";
static ModuleHelper* moduleHelper;
};
extern "C" //GAME_API is a dllexport macro
{
char* GAME_API getName()
{
return Utility::getName();
}
char** GAME_API getDependencies()
{
return Utility::getDependencies();
}
int GAME_API getCountDependencies()
{
return Utility::getCountDependencies();
}
char* GAME_API getServeAs()
{
return Utility::getServeAs();
}
noargfunc GAME_API onInit()
{
return Utility::onInit;
}
noargfunc GAME_API onUpdate()
{
return Utility::onUpdate;
}
void GAME_API setModuleHelper(ModuleHelper* moduleHelper)
{
Utility::setModuleHelper(moduleHelper);
}
}
#endif /* UTILITY_H_ */
Utility.cpp:
#include "Utility.h"
ModuleHelper* Utility::moduleHelper; //with "= nullptr" or "= NULL" it didn't work either
void Utility::onInit()
{
moduleHelper->printLine("Hello from Utilities"); //wrapper for std::cout
}
void Utility::onUpdate()
{
}
char* Utility::getName()
{
return name;
}
char** Utility::getDependencies()
{
return dependencies;
}
int Utility::getCountDependencies()
{
return countDependencies;
}
char* Utility::getServeAs()
{
return serveAs;
}
void Utility::setModuleHelper(ModuleHelper* helper)
{
moduleHelper = helper;
}
An undefined reference means that the IMPLEMENTATION is not found.
it looks like you just included the header file in order to use the library.
The main problem (the linker error - not runtime!) is that you may forgot to link the library. (Project References in Visual Studio)
Anyway you will find your next error if you CAN compile and link your code.
ModuleHelper* Utility::moduleHelper; //with "= nullptr" or "= NULL" it didn't work either
if you initialize moduleHelper with NULL and then dereference the pointer with "->" trying to do sth you will get a null-pointer exception.
You have to initialize it... (could be = new ModuleHelper). Since I don't know the used library you have to read the documentation yourself.

Exposing application API and data to DLL

I have a dll plugin ,myDLL.cpp, which has the following code:
#include "myDLL.h"
#include "MainApp.h"
class A{
public:
// NOTE: SomeType is defined in main application code.
A(SomeType* data) : m_data{data}
void MemberFunc(){
// NOTE: do_something should access data in main application.
m_data->do_something();
}
private:
SomeType* m_data;
};
// exported function
A* createInstance(SomeType* data){
return new A(data);
}
In the main application I have:
stc::vector<int> IntArray;
class SomeType{
SomeType(){
IntArray.resize(1000);
}
void do_something(){
// manipulate IntArray's contents.
IntArray[rand() % IntArray.size()] = rand();
}
};
typedef A*(_createInstance)(SomeType*);
void main(){
// Load the Dll and get createInstance()
_createInstance createInstance = LoadMyDLL();
SomeType someType;
A* a = createInstance(&someType);
a->MemberFunc();
// Free the instance of A and unload the DLL.
UnloadMyDLL(a);
}
The dll code now can use the API of the main application, but it can't access the right data. When I put a break point at m_data->do_something(); and enter the method call, then I see that IntArray is empty. What am I doing wrong and how do I solve the problem?
I could succesfully run your example without experiencing your problem:
I assumed that in your headers there are only the class definitions and not definition of its member functions
So I buid a DLL project. But it failed producing the dll because of the missing do_something() function. Normal, because with your architecture it should be defined in the application not in the DLL ! I could solve the problem by making do_something() virtual.
Then I build the application. I first chose for simplicity and linked the application with the DLL (no loading issues). Unfortunately it didn't find either MemberFunc() nor createInstance(). I could solve this by exporting the DLL entry.
FInally I updated the application, to have a dynamic load of the library. For avoiding unnecessary hassle of having to find back MemberFunc(), I made it virtual as well.
In all the tests above, I had absolutely no problem. IntArray was always correct. In debug mode I could see it with the expected content, as soon as it entered the scope.
My conclusion, from these tests and looking at your snippet (expecially with doSomething not being virtual): your problem is probably that have defined SomeType class with functions and eventually IntArray in Main.h.
If this is the case, your DLL refers to its own copy of these elements and not as you think to those in main ! THis explains why you don't see the expected values !
Solution:
File MainApp.h:
class SomeType{
public:
SomeType();
virtual void do_something();
};
File MyDLL.h:
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class A {
public:
A(SomeType* data);
virtual void MemberFunc(); // access through vtable. No need to link
private:
SomeType* m_data;
};
extern "C" { // use unmangled name for easo of use of dynamic loaded DLL
MYDLL_API A* createInstance(SomeType* data);
};
File MyDLL.cpp:
#define MYDLL_EXPORTS
#include "MainApp.h"
#include "MyDLL.h"
A::A(SomeType* data) : m_data{ data } {}
void A::MemberFunc(){ m_data->do_something(); }
extern "C" {
MYDLL_API A* cdecl createInstance(SomeType* data){ return new A(data); }
}
File main.cpp:
#include <Windows.h>
#include <iostream>
#include <vector>
#include "MainApp.h"
#include "MyDLL.h"
using namespace std;
vector<int> IntArray;
SomeType::SomeType(){
IntArray.resize(1000);
IntArray[0] = 1; IntArray[1] = 101; IntArray[2] = 10101;
}
void SomeType::do_something(){
for (int i = 0; i < 4; i++) // read
cout << IntArray[i] << endl;
IntArray[3] = 2702; // write
}
int main(int ac, char**av)
{
HINSTANCE LoadMe = LoadLibrary(L"MyDLL.dll");
if(LoadMe != 0)
cout << "DLL Library successfully loaded!\n";
else throw exception("DLL library failed to load!\n");
typedef A*(*_createInstance)(SomeType*);
_createInstance fcreateInstance = (_createInstance) GetProcAddress(LoadMe, "createInstance");
if (fcreateInstance)
cout << "DLL function found !\n";
else throw exception("Function not found in DLL!\n");
SomeType someType;
A* a = fcreateInstance(&someType);
a->MemberFunc();
cin.get();
}

Explicitly Linking to Classes in DLL's

I have a class that is currently in a .lib file:
class __declspec(dllexport) ReportData {
public:
list<FileData *> ReportFileData;
list<SupressionData *> ReportSupressionData;
static char *ClientName;
static char *DataRecieved;
std::string GenFileConfTemplate();
~ReportData()
{
ReportFileData.clear();
ReportSupressionData.clear();
}
};
I can add this lib file to my project and create instances of this class no problem.
My question is, how can i move this to a DLL and dynamically load it, and create instances of this class. What i'm wanting to do is move some common functionality into this dll and share it across multiple projects.
I want to be able to re-compile the dll if needed when changes are made and have the projects use the must recent version; as of now, using a lib, I have to recompile every project after I recompile the dll for the changes to take place, and because the way this system was originally designed, there are 100+ projects that will use this lib/dll and I don't want to recompile 100 different projects each time a change is made.
So, please give me your expert opinions on how i should go about doing this.
I'll be using the dll inside of my projects like so:
ReportData *rd = new ReportData();
ReportData::ClientName = "test";
rd->ReportFileData.push_back(new FileData("testing", 10, 1));
rd->ReportFileData.push_back(new FileData("testing 2", 20, 1));
std::cout << rd->GenFileConfTemplate();
delete rd;
I ended up with something like this:
typedef Foo* (__stdcall *CreateFunc)();
int main()
{
HMODULE dll (LoadLibrary ("..\\LLFileConfirmDLL\\LLFileConfirmDLL.dll"));
if (!dll) {
cerr << "LoadLibrary: Failed!" << endl;
std::cin.get();
return 1;
}
CreateFunc create (reinterpret_cast<CreateFunc>(GetProcAddress (dll, "create")));
if (!create) {
cerr << "GetProcAddress: Failed!" << endl;
std::cin.get();
return 1;
}
Foo *f = create();
cerr << f->Test();
FreeLibrary (dll);
std::cin.get();
return 0;
}
struct FOOAPI Foo
{
Foo();
virtual ~Foo();
virtual int Test();
};
Foo::Foo()
{
}
Foo::~Foo()
{
}
int Foo::Test()
{
return 5;
}
extern "C" __declspec(dllexport) Foo* __stdcall create()
{
return new Foo;
}
You can do this the way COM does it:
Export a CreateInstance() function.
Pass a void** and unique identifier to CreateInstance().
Your consuming DLL calls LoadLibrary() on the library DLL and calls CreateInstance().
CreateInstance() does the new ReportData and returns it in the void** out param.
Edit:
Something like:
extern "C"
BOOL CreateObject(REFCLSID rclsid, void** ppv) {
BOOL success = false;
*ppv = NULL;
if (rclsid == CLSID_ReportData) {
ReportData* report_data = new ReportData();
if (report_data) {
*ppv = report_data;
success = true;
}
} else if (...) {
... other objects ...
}
return success;
}
Of course, now you have to worry about things like who will free the object, making sure the DLL doesn't get unloaded, etc.
See also DllGetClassObject, DllCanUnloadNow, etc.