# Maintaining state across a DLL boundary - help very much needed

## Recommended Posts

Hi all, I'm now abandoning my all-singing all-dancing classloader I'm having troubles with in this thread (unless someone gives me a solution!), and using an inferior but simpler alternative instead. However, I'm having absolutely no luck getting anything to work across a DLL boundary, full stop. Can any of you tell me a foolproof way to make sure (as an example) to ensure something added to a std::map in the main application from code in a DLL stays in the map for use by the rest of the application? A bit of code will go a very long way. I've tried all sorts of combinations of __declspecs and externs and statics and compiler/linker settings, but it just won't work. If it's of any use, I'm using MSVC2005. Thanks in advance!

##### Share on other sites
You must use an exported accessor function, or an interface, to the instance of the map in the dll - otherwise, I'm guessing the problem you're having, is that the map is getting instantiated in each module.

So, for example, in my main DLL I have some code that looks like this in a source file called Factory.cpp

namespace{	typedef std::map< UUID, Factory::FactoryFunc > FactoryMapT;	FactoryMapT& GetFactoryMap()	{		static FactoryMapT fm;		return fm;	}}void Factory::Register( const UUID& name, FactoryFunc func ){	FactoryMapT& fm = GetFactoryMap();	Debug::Assert( fm.find( name ) == fm.end(),		L"That CLSID has already been registered." );	fm.insert( FactoryMapT::value_type( name, func ) );}

And in my Factory.h file, I export a couple of methods of the Factory class:

class Factory{public:	typedef Object*(*FactoryFunc)();	CORE_API static void Register( const UUID& clsid, FactoryFunc func );	CORE_API static Object* CreateObject( const UUID& clsid );};

note, that CORE_API is defined as

#if defined WIN32#if defined CORE_EXPORTS	#define CORE_API __declspec( dllexport )#else	#define CORE_API __declspec( dllimport )#endif#elif defined LINUX#define CORE_API#else#error "platform not supported."#endif

Hope this helps.

##### Share on other sites
From what I've heard you shouldn't pass STL objects across DLL boundaries.

Something to do with the DLL having a seperate heap.

I wish I could be more specific, but Im sure someone more knowlegable will be able to expand on ( or disprove [smile] ) what I'm saying.

##### Share on other sites
Quote:
 Original post by rip-offFrom what I've heard you shouldn't pass STL objects across DLL boundaries.Something to do with the DLL having a seperate heap.I wish I could be more specific, but Im sure someone more knowlegable will be able to expand on ( or disprove [smile] ) what I'm saying.

This is basically true as a general rule. You never want to pass a reference to or a copy of an STL object across a DLL boundary unless you guarantee yourself that everything is built with the same STL code and C runtime libraries.

But this also holds true with a variety of other objects, not just STL.

##### Share on other sites
Ah, don't worry, that was just an example. Actually I'm doing much the same thing as you; passing a pointer to a factory function and an identifier for that, to be registered in a factory. I can step through the code and see that the classes in the DLLs are statically calling the register methods, but when I come to read from the factory during main (as a test), there is nothing in it. I'm sure it's to do with the factory getting instantiated multiple times in different address spaces, but I didn't know how to stop this.

I do have a quick question for you, krum: where are each of those code snippets from? Which are compiled into DLLs and which are part of the application/API? What I guess I'm really asking is what parts need to be exported, and where?

##### Share on other sites
Basically, what you must do is ensure that you don't have two things one in main program other in DLL. It looks like your problem is that your global data exist in two instances one in the DLL and other in main app. There isn't any magical transfers of changes. It's just that either main app and dll is using two different or two same datas.

std::map lalala;
[dllexport or whatever] std::map &GetLalala();
and put the
std::map lalala;
only in one dll or only in main app , together with implementation of GetLalala(); that should return it.

##### Share on other sites
Quote:
 Original post by hymermankrum: where are each of those code snippets from? Which are compiled into DLLs and which are part of the application/API? What I guess I'm really asking is what parts need to be exported, and where?

Factory.cpp is compiled into a core.dll.

Consumers would need to include Factory.h - which also includes some static methods to ease object creation. In fact, here's the whole Factory.h:

#ifndef included_pyx_core__Factory_h#define included_pyx_core__Factory_h#include "core/Core.h"#include "core/Object.h"BEGIN_NAMESPACE_PYX;//////////////////////////////////////////////////////////////////////////class Factory{public:	typedef Object*(*FactoryFunc)();	CORE_API static void Register( const UUID& clsid, FactoryFunc func );	CORE_API static Object* CreateObject( const UUID& clsid );};// --------------------------------------------------------------------------template< class T >inline T* CreateObject(){	Object* obj = Factory::CreateObject( T::GetClassID() );	return static_cast<T*>( obj );}// --------------------------------------------------------------------------template< class T >inline bool CreateObject( const UUID& clsid, T** result ){	*result = static_cast<T*>( Factory::CreateObject( clsid ) );	return *result != 0;}// --------------------------------------------------------------------------template< class T >inline bool CreateObject( const UUID& clsid, boost::shared_ptr<T>& result ){	T* obj = static_cast<T*>( Factory::CreateObject( clsid ) );	result = boost::shared_ptr< T >( obj );	return obj != 0;}// --------------------------------------------------------------------------template< class T >class AutoRegister{public:	AutoRegister()	{		Factory::Register( T::GetClassID(), T::CreateObject );	}};// --------------------------------------------------------------------------END_NAMESPACE;#endif // included_pyx_core__Factory_h

Consumers usually include Factory.h either in their precompiled header, or in a source file that uses it (since objects that register with Factory use the AutoRegister class). Usually the only consumer for the Factory is the serialization engine; an application developer wouldn't normally use this to create an object unless they wanted to create an object that had an abstract base type (like the renderer).

##### Share on other sites
Also, come to think of it, is your map instance in a static library that you're linking with the DLLs? If so, that would definitely result in the behavior that you describe.

##### Share on other sites
Thanks very much for that, krum, I think that's pretty much exactly how I'm going to have to implement it now.

Dymytry: Okay, I now see why I have to do it this way. If my actual code were as simple as just a single std::map used as a factory, I'd do that straight away, but unfortunately I'm using a templated class, and my understanding of templated classes is that the implementation must go in the same header file, as mentioned at the bottom of this page. So, is what I'm trying to do basically impossible? Do the requirements of having to separate implementation and declaration, as well as keep them together conflict to such a point that I have to choose one or the other? It's such a shame if that's the case, since otherwise I'd have a pretty swish classloader :(

##### Share on other sites
Actually they don't have to go into the same header. I use .inl files for "inline" code like templates. You just put in a #include "somefilename.inl". I find it keeps code a lot cleaner and does the same thing as having it in the header. Anyways, hope your issue is solved.

##### Share on other sites
Actually they don't have to go into the same header. I use .inl files for "inline" code like templates. You just put in a #include "somefilename.inl". I find it keeps code a lot cleaner and does the same thing as having it in the header. Anyways, hope your issue is solved.

##### Share on other sites
Ah, that's a good idea. I'll do that from now on, actually, I've always thought this way of doing things was a bit messy!

But still, does it solve the problem? It all still has to be compiled into each thing that uses it (the app and each DLL, that is), meaning there will be a separate copy of all static things, which is not what I want at all. Is there any way around this at all? Can some clever C++ guru help out here?