Get Singleton in a static library from DLL

Eb3291f61c6a5e09cabefb4348f193d6
0
Dom_152 101 Feb 09, 2007 at 20:49

Hello all!

I have hit a bit of a problem. I’ll try and explain as best I can but I’m not great at doing this so bear with me. In my project I have a static library which has many things, namely a singleton “Root” object which can be accessed from any other part of the library. This Root object is created by the user in their own application when using the library something like this:

DF::Root *root = new Root();

Now along with the static library I have external “Modules” or DLLs. Now My problem is that I want to be able to access the same Root singleton from my DLL. I have linked by DLL to the static library and in one of the methods I call something like this:

DF::Root->GetSingletonPtr()->GetLogger()->Log(“Direct3D 9 Render Device created succesfully”, DF::EMT_NORMAL);

But calling GetSingletonPtr() from the DLL does not get the one that the static library is using, in fact it returns nothing because there is no Root object that the DLL can get to. So What I’m asking is how can I get my DLL to access the singleton being used by the static library?

Sorry if that didn’t make much sense. If you need me to clarify something let me know. Thanks in advance.

EDIT: What I want to achieve is something like the Ogre engine. It’s a similar setup to mine but it seems to be able to use the singleton from the DLLs fine…

10 Replies

Please log in or register to post a reply.

4973f1872cf6539fc6424193c1cc7ee2
0
freezzo 101 Feb 09, 2007 at 21:14

Perhaps I am misinterpreting your question, but it sounds like you want your DLL to access something in your app/library?

Perhaps I’m wrong, but isn’t the idea of a DLL to be a library that your app can pull from and use the functionality from? The DLL techinically wouldn’t know about anything going on in the app or another library?

Eb3291f61c6a5e09cabefb4348f193d6
0
Dom_152 101 Feb 09, 2007 at 21:27

I was under the impression that a DLL was loaded into the same, for want of a better word, “memory pool” as the application using it. So shouldn’t it be able to access the memory I want it to?

4973f1872cf6539fc6424193c1cc7ee2
0
freezzo 101 Feb 09, 2007 at 21:39

Maybe your right but i thought you write DLL’s to be “application” independant, so with that being said, how would the DLL know what the applilcation contains?

You should be able to plug a dll into any application and use the functionality of it without having to set up your own variables for it to read from.

Think of DirectX

You add the header file and include the library for your game, build your exe.

then when you deploy, the machine has to have the DX dll’s to run. All the objects you use in your game are derived from the dx library/dll.

This is my understanding of it, but perhaps im wrong.

A5a585844c9192f8cfbdfa41bb2d7761
0
dag239 101 Feb 09, 2007 at 21:44

If you included the same static library in your DLL as you did in your app, and the declaration of a variable pointing to the object which your DLL is trying to access is found in the static library’s code, your application and your DLL are both going to have their own > SEPERATE < copy of the variable.

If you initialize the variable in your application, your application’s copy of the variable will have a value, but when you refer to that variable in the DLL, you will be refering to the DLL’s copy of that variable. Static libraries are built into your applications and DLLs, not connected to during runtime, so their variables aren’t shared among all things that use them.

Use static libraries only for reuseable methods that don’t depend on outside variables, such as useful math functions:

float dot3( vec3 v );

Now, if you declare a variable in the DLL, and make it available to the application:

Your DLL’s source:

MYDLLAPI SomeClass *theOneClass = NULL;

Then your application can set that variable:

theOneClass = new SomeClass( );

Then when your DLL acts on that class:

MYDLLAPI void SomeFunction( void )
{
if( theOneClass )
theOneClass->DoSomething();
..
}

It will be affecting an object provided by the application, which the application can also use at will.
You could also pass an instance of an object class defined in a static library to the DLL.

MYDLLAPI void DoSomethingToSomething( SomeClass *pob )
{
pob->DoSomething();
..
..
}

Eb3291f61c6a5e09cabefb4348f193d6
0
Dom_152 101 Feb 09, 2007 at 22:20

OK Well I have temporarily fixed the problem by getting the static library to pass a pointer to the Root object to the DLL when it’s loaded. But for some reason even though I pass this poniter GetSingletonPtr() does not work but other get methods, GetLogger(), do. I don’t understand how the OGRE engine has done this?

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Feb 10, 2007 at 01:18

Dag239, freezo, a DLL can certainly access things from the application, as they are indeed in the same memory space. However, the memory addresses of application objects will not be known to the DLL unless you pass these addresses to the DLL upon load.

Dom, I don’t know why some of your methods work but others don’t. Could you post some of your code?

Eb3291f61c6a5e09cabefb4348f193d6
0
Dom_152 101 Feb 10, 2007 at 09:57

OK In the application which uses the static library:

DF::Root *dfRoot;
dfRoot  = new DF::Root();

Creating a new Root object. This is the object that’s used by the static library. E.g. The static library can do this:

Root::GetSingletonPtr()->GetLogger()->Log("Module " + name + " has been loaded successfully", EMT_NORMAL);

In the Roots constructor it creates a new Render Device. The constructor for the Render Device will then go ahead and load the external module and get some function pointers:

//Default constructor
Renderer::Renderer(ERENDERER_DRIVER driver)
{
    //Load the appropriate module
    switch(driver)
    {
    case ERD_DIRECT3D9:
        {               
#ifdef _WIN32       
#ifdef _DEBUG
            m_module.Load("DFGE_D3D9_d.dll");
#else
            m_module.Load("DFGE_D3D9.dll");
#endif
#else
            Root::GetSingletonPtr()->GetLogger()->Log("Direct3D 9 Renderer is not supported on this platform", EMT_ERROR);
#endif
        }
    }

    //Get pointers to the functions in the module
    m_createRenderDevice = (_CreateRenderDevice)m_module.GetProc("CreateRenderDevice");
    m_releaseRenderDevice = (_ReleaseRenderDevice)m_module.GetProc("ReleaseRenderDevice");

    //Create the render device      
    m_renderDevice = CreateRenderDevice(Root::GetSingletonPtr());
}

As you can see I call CreateRenderDevice, which in turn calls the equivalent function implemented in the DLL. I pass it a copy of my Singleton pointer for the Root (Root::GetSingletonPtr()).

This is the the CreateRenderDevice function definition in the DLL:

//In the module header file
DF::Root *Root = 0;

//In the source file
DF::IRenderDevice *CreateRenderDevice(DF::Root *root)
{
    Root = root;

    DF::D3D9RenderDevice *renderDevice;
    renderDevice = new DF::D3D9RenderDevice();

    Root->GetLogger()->Log("Direct3D 9 Render Device created succesfully", DF::EMT_NORMAL);

    if(renderDevice)
        return renderDevice;

    return 0;
}

As you can see in the previous function I do Root->GetLogger()… rather than Root::GetSingletonPtr()->GetLogger()… If I call the GetSingletonPtr() method inside the module it returns a NULL pointer. I think this may have something to do with the way I pass the Singleton pointer, and a Singleton can’t have a pointer to a singleton? :S

I hope this makes it easier for you to understand.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Feb 10, 2007 at 17:07

When you compile the DLL, do you compile in the module that contains the definition of Root and GetSingletonPtr, or do you just refer to the header file that contains the class interface?

You should be doing the latter. If you were to compile the module into the DLL, then the DLL would contain its own copy of the Root class and therefore a different singleton instance.

It looks to me like this may be what you are doing. If you put a call to Root::GetSingletonPtr from within the DLL, you ought to receive a linker error, because this function isn’t part of the DLL. If you don’t, you’ve probably got two copies of Root, one in the application, and one in the DLL, each with its own singleton object. The second one isn’t getting initialized which is why you’re getting NULL.

You can’t call a function inside an application from a DLL unless you’ve first passed its function pointer. So you could use Root::GetSingletonPtr in the DLL, if you declared that name in the DLL as a function pointer, and sometime during initialization set it to the address of the Root::GetSingletonPtr in the main application.

However, in my opinion singletons are more trouble than they’re worth. I would just stick with what you have now - passing a pointer to the Root object directly to the DLL. That’s more elegant and clear, IMHO.

Eb3291f61c6a5e09cabefb4348f193d6
0
Dom_152 101 Feb 10, 2007 at 17:14

Thanks that does make sense. And yeah I think I will stick to what I have at the moment. It works nicely. Thanks for all the help.

Eb3291f61c6a5e09cabefb4348f193d6
0
Dom_152 101 Feb 11, 2007 at 10:58

OK Unrelated to this topic but I’m just gonna use this thread anyway. There is a function in my DLL which is throwing uhnadled exceptions errors. I want to debug and find out whats causing it. (It seems changing a value from 16 to 32 destroys it :S) but whenever I debug it won’t load the symbols for the DLL so none of my breakpoints work. it only works for the static library. Any help? I’m using MSVC++ 2005.