I have a solution set up with 3 projects:
Export.h
#pragma once
#ifdef DLL_EXPORT
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
Lib1.h
#pragma once
#include "Export.h"
class Member { };
class EXPORT Base {
public:
static Member* GetStaticMember();
virtual void SetMember(Member* member) = 0;
protected:
static Member* m_member;
};
class Worker {
public:
void DoSomething();
};
Lib1.cpp
#include "pch.h"
#include "Lib1.h"
Member* Base::m_member;
Member* Base::GetStaticMember() {
return m_member;
}
void Worker::DoSomething() {
Member* test = Base::GetStaticMember(); // RETURNS 0
}
Dll1.h
#pragma once
#include "Lib1.h"
#include "Export.h"
class EXPORT ChildA : public Base {
public:
virtual void SetMember(Member* member) override;
};
Dll1.cpp
#include "pch.h"
#include "Dll1.h"
void ChildA::SetMember(Member* member) {
Base::m_member = member;
Member* test = Base::GetStaticMember(); // RETURNS CORRECT ADDRESS
}
Member* member = new Member();
ChildA* childa = new ChildA();
childa->SetMember(member); // Base::GetStaticMember() inside this RETURNS CORRECT ADDRESS
Worker* worker = new Worker();
worker->DoSomething(); // Base::GetStaticMember() inside this RETURNS 0
When stepping through in the debugger, Base::GetStaticMember() returns the correct address to the member after it is set (but still while inside childa->SetMember(). Once OUTSIDE childa, Base::GetStaticMember() returns 0 instead. When inside worker->DoSomething(), Base::GetStaticMember() is also returning 0. Can anyone explain to me what the cause of this is and how to fix it so that accessing Base::GetStaticMember() either outside or inside methods of the Dll or Lib will return the correct address and not 0?
If you're using a static lib linked to multiple DLL's and/or your EXE, each will get its own static member variable. Think of the mechanics of how the *link phase of each of these happens and you'll see why.
You can turn your static vars into pointers referencing shared memory backed by a memory mapped file, but I warn you it gets tricky to manage. I've done it by maintaining a temp memory-map-file using the name of the class+member+pid as the mapping name (note: the pid was to allow multiple processes to run without stomping on each others shared mem). it worked surprisingly well.