I created a static library with class:
class CLog
{
private:
CLog();
...
...
public:
static CLog& GetInstance()
The problem is that every project that links the static library, be it main program or DLL, will get a separate copy of the static variable. This breaks the typical method of creating a singleton.
The simplest way around this is to create another DLL which holds the singleton, rather than a static library. Since only one linker output will contain the static variable, the problem is solved.
In my own case I created a singleton manager that identified each singleton by a unique GUID and ensured that only one copy existed application wide. The singleton manager existed as its own DLL.
The method I used was to export a function called GetLogger from the EXE which provides a pointer to the singleton. GetInstance() implementation is conditional on the _USRDLL preprocessor define. When _USRDLL is set (for the DLL compilation) GetInstance() calls GetModuleHandle() to get a handle to the EXE and loads the function called GetLogger. Here's the code based on your example:
Static lib has Log.h:
class Log
{
private:
Log();
public:
~Log();
static Log& GetInstance()
{
#ifdef _USRDLL
typedef Log* (*GetLoggerFn)();
HMODULE mod = GetModuleHandle( NULL );
GetLoggerFn getLogger = (GetLoggerFn)::GetProcAddress( mod, "GetLogger" );
Log* Instance = getLogger();
return *Instance;
#else
static Log Instance;
return Instance;
#endif
}
void Write(const std::string& str );
};
#define LOG Log::GetInstance()
Static lib has Log.cpp:
#include "Log.h"
void Log::Write(const std::string& str )
{
std::cout << this << " " << str << std::endl;
}
Log::Log()
{
}
Log::~Log()
{
std::cout << "Log destroyed" << std::endl;
}
DLL just has a log statement in DllMain:
#include "../static/Log.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
LOG.Write("Hello from dll");
return TRUE;
}
And EXE looks like this:
#include "stdafx.h"
#include "../static/Log.h"
#include <Windows.h>
extern "C"
{
__declspec( dllexport ) Log* GetLogger()
{
return &LOG;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
LOG.Write("Hello from exe");
HMODULE mod = ::LoadLibraryA( "../Debug/tdll.dll");
::FreeLibrary( mod );
LOG.Write("unloaded library");
return 0;
}