Jump to content
  • Advertisement
Sign in to follow this  
Juliean

Static variable across dll

This topic is 2136 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

 

I've started to seperate most of my game engines high-level functions like HDR, deferred lighting etc... into seperate modules, and now I want to make them as sort of a plugin. Thus I've seperated them into a different project, and compiled it into a dll. Now I'm loading this dll from a config file like this:

    HINSTANCE hGetProcIDDLL = LoadLibrary(L"HDR.dll");

    module mod = (module)GetProcAddress(hGetProcIDDLL, "CreateModule");

    pModuleManager->AddModule(L"HDR", mod());

So far so fine, but now the module might use some of my classes which implement the CRTP, using a static variable:

struct BaseSystem
{
    typedef unsigned int Family;

    virtual ~BaseSystem(void) {}

protected:
    static Family family_count; /**< Counter of instanciated systems.
        *   Each system of a different type that is created, or whose family
        *   function is called the first time will increase this counter. The
        *   counter is used as the ID of the next system. */
};

template <typename Derived>
struct System :
    public BaseSystem
{

    virtual ~System(void) override = 0 {}

public:

    /** Returns the "family" type of the system.
     *    This method sets the type id for the specific system struct on
     *  the first call, and returns it from there on. The id is consistent
     *  between the running time of a program and cannot be altered, but
     *  it may alter between different runs, depending on the first creation
     *  order of the systems.
     *
     *  @return The unique id of this system instance
     */
    static Family family(void)
    {
        static BaseSystem::Family Family = family_count++;
        return Family;
    }

};

Basically, its a way for semi-hardtyping a e.g. entity system without having the user declare it an unique id himself. However, when I create a system from the DLL, family_count is 0 again, screwing up the whole thing. Is there any way around this? Eigther some way to make the static variable work across the DLLs, or some way to replace/modify the CRTP to work with a dynamically loaded dll without too much additional work on top of it?

Edited by Juliean

Share this post


Link to post
Share on other sites
Advertisement

Make the variable private and move the function for accessing it into the baseclass and make sure its not duplicated/inlined and inside the same dll as the variable?

Share this post


Link to post
Share on other sites

Make the variable private and move the function for accessing it into the baseclass and make sure its not duplicated/inlined and inside the same dll as the variable?

 

Thats the problem, I think I haven't adressed that correctly. The class posted above is from my main SDK, which is used to create the DLL. So the "variable" comes from declaring a class inside the dll like this:

class HDRRenderSystem:
	public System<HDRRenderSystem>
{
};

So the variable can't really be inside of the DLL for that reason... plus, for the CRTP to work, I can't move the accessor in the base class, CRTP is based on the fact that for every new class you derive with a different template type, a new static variable is created, incrementing the family_count and holding the new family id. Now for different dlls, different such systems can be declared, and each system should get its own unique id through this, just like if all of them where declared inside the main app. Is this in any way/shape or form adaptable to work with such a DLL plugin system?

Edited by Juliean

Share this post


Link to post
Share on other sites
static Family BaseSystem::GenerateFamilyID() {
  return family_count++;
}
    static Family family(void)
    {
        static BaseSystem::Family myFamily = GenerateFamilyID();
        return myFamily;
    }

Why not like this?

Share this post


Link to post
Share on other sites


Why not like this?

 

Ah, now I get what you meant. Unfortunately, this doesn't seem to work as is. Since you mentioned something about making sure it isn't duplicated/inlined, how'd I go about that? Do you mean I need to get rid of all function declarations in the header? Just to make sure, here is how both classes look now completely (I stripped some functions in the code above):

#pragma once

namespace acl
{
	namespace ecs
	{
		class EntityManager;
        class MessageManager;
        struct BaseMessage;
        struct BaseQuery;

		struct BaseSystem
		{
			typedef unsigned int Family;

            virtual ~BaseSystem(void) {}

			virtual void Update(double dt) = 0; 

			virtual void RecieveMessage(const BaseMessage& message) {} 

            virtual bool HandleQuery(BaseQuery& query) const { return false; } 

			static Family GenerateFamilyId(void);

		private:
			static Family family_count;
		};

		template <typename Derived>
		struct System : 
            public BaseSystem 
        {

            virtual ~System(void) override = 0 {}
			
            void Register(EntityManager& entities, const MessageManager& messages)
            {
                m_pEntities = &entities;
                m_pMessages = &messages;
            }

        public:

			virtual void Init(MessageManager& messages) {}

			static Family family(void)
            {
			    static BaseSystem::Family Family = BaseSystem::GenerateFamilyId();
			    return Family;
		    }

        protected:

            EntityManager* m_pEntities;
            const MessageManager* m_pMessages;

		};

	}
}

Anything you see that can probably cause this not to work?

Share this post


Link to post
Share on other sites

To get this to work as written you need to export BaseSystem from a DLL that your application and all the plug-ins can import.

 

Ah, so thats why it wasn't working, I'm using a static .lib right now. Since I'm fairly new to DLLs, could you give me a little assistance? For example, talking about the "exporting system from a dll for the app & plugin", could I simply change my engine/sdk from static libary to dll, then implicitly link to it from the plugin and the app, or do I need to use dynamic loading? Plus, when changing from lib to dll, do I only need to export classes/functions with declaration, or do I need to export interfaces etc.. also?

Edited by Juliean

Share this post


Link to post
Share on other sites
You don't need to explicitly call LoadLibrary()/GetProcAddress(). In fact, since you're trying to use entire C++ classes from your DLLs you basically can't. For example, there's really no syntax for assigning from GetProcAddress() to the implementation of a member function of a base class.

As for what you need to export: for classes you need to export any class that clients will use that has member function definitions or static member variables. You don't need to export an abstract base class that only contains pure virtual member functions. You don't need to export a class that has member function definitions if no clients of the DLL will use that class (but keep in mind that C++ has half a million ways to use a class definition implicitly, so if it goes in a header a client can see you probably need to export it if it has any member function definitions or static variables).

Note that this is advice for trying to keep the code as written. It would probably save headaches long term if you sat down and created a clean DLL interface and adjusted your code to that rather than trying to make a DLL interface from your existing code.

Share this post


Link to post
Share on other sites

Thanks, changing to implicitly linked dll is now working!

 


Note that this is advice for trying to keep the code as written. It would probably save headaches long term if you sat down and created a clean DLL interface and adjusted your code to that rather than trying to make a DLL interface from your existing code.

 

That would be my plan on the long run. As I did with the rest of the project, I'd also like to go sort of an iterative approach here - first make things work, and then improve and improve until it fits my needs and works decently. However seeing what big of a deal this probably is (only trying to make things work so far has caused dozens of small issues, compiler warnings I'll still have to shut off, etc..., mostly due to my extensive use of templates), I agree it wouldn't be too bad to start with a clean interface right away. Being that this is my very first project related to dlls at all (I've never even loaded one directly before), do you have any reference material on how to at least conceptually design a decent DLL interface? I'm not even sure if you are talking about the plugins or the way the engine/sdk is build...

Share this post


Link to post
Share on other sites
A good starting reference would be C++ Coding Standards by Herb Sutter and Andrei Alexandrescu. If you can't find a copy the table of contents is available here which lets you get the essence. For DLLs you want to pay particular attention to any of the items with "module" in the name, but other items are definitely relevant such as number eleven: hide information.

My own personal rule for designing a DLL interface is much more restrictive: don't expose any constructs that can't be expressed in C. No exporting classes, no templates, no name mangled symbols, etc. Abstract base classes with only pure virtual functions are OK since C can be used to use COM interfaces (with quite a bit of grunt work, but still possible).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!