Sign in to follow this  

DLL Problem....

This topic is 4664 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

I have a dll problem. I have developed a plugin system that loads dlls from a certain folder. I have an interface layer which has certain function the dll can call, but this gets passed in when I call init in the dll. I have a main application that I don't want the dlls to interact with, thats the reason for the interface layer. But the interface layer references the main application in it. So what happens is that I create the main application and then the dll is creating a second main application because it is referenced in the interface layer. The main application and application interface are both singletons. What I would like to do is have the dll not create a second main application and use the current one that was created already and is referenced in the application interface that is passed to the dll. Sorry if so confusing. Just ask any questions if you don't understand. Thanks in advance. -Jay

Share this post


Link to post
Share on other sites
I have a habbit of putting stuff in DLLs all the time. What I *always* do is have to abstract classes. One which the DLL implements, and one which the EXE implements, and passes to the DLL.

For example, my bomberman clone has the AI in a DLL. The AI interface has functions like OnTick() and OnNewMap(), and the EXE interface has functions like GetPlayerPos(), MoveLeft(), DropBomb(), etc etc.

My main application class derives from this virtual class, and provides functionality for the functions (GetPlayerPos(), MoveLeft(), DropBomb(), etc).
When I load the DLL, I use GetProcAddress() to get the address of the Create() function. I then call it, passing this to it, as the abstract class.

That's a really bad explanation [smile]. I export the function from the DLL as:

extern "C" {
AI_API IAI* CreateAI(IGameInterface* pInterface);
}



In your case, if you really want to use a singleton, you'd just pass the singleton through as the interface. For example m_pAP = pfnCreate(&CGame::Get());.

Hope this helps,
Steve

Share this post


Link to post
Share on other sites
This is pretty much what I do, I pass the application interface instance to the dll, but when the main application is referenced in the application interface via MainApplication::GetInstance()->SomeFunc(), it creates a second main application instance, so is there a way for it not to create a second when it tries to access the main application.

-Jay

Share this post


Link to post
Share on other sites
I'm not entirely sure I understand...

If you pass a pointer to the singleton to the DLL, then the DLL shouldn't care if the passes pointer is a singleton or not. So it shouldn't need to call the Get() method, which would cause another instance to be created.

Example code:

//
// Your interfaces
//
class IDll
{
public:
IDll() {}
virtual ~IDll() {}

virtual void Release() = 0;
virtual void Tick() = 0;
};

class IGameInterface
{
public:
IGameInterface() {}
virtual ~IGameInterface() {}

virtual HWND GetWindow() = 0;
virtual void DoSomething() = 0;
};

// Exported function:
IDll* CreatePlugin(IGameInterface* pInterface);

//
// In the DLL:
//
class CDll : public IDll
{
public:
CDll(IGameInterface* pInterface) : m_pInterface(pInterface) {}
virtual ~CDll() {}

virtual void Release() {delete this;}
virtual void Tick() {m_pInterface->DoSomething();}

protected:
IGameInterface* m_pInterface;
};

// Exported function implementation:
IDll* CreatePlugin(IGameInterface* pInterface)
{
return new CDll(pInterface);
}


//
// In the exe:
//
class CGame : public IGameInterface
{
public:
CGame() {}
virtual ~CGame() {}

virtual HWND GetWindow() {return m_hWnd;}
virtual void DoSomething() {/* Blah */}

static CGame& Get()
{
static CGame theInstance;
return theInstance;
}

protected:
HWND m_hWnd;
IDll* m_pPlugin;
// Etc
};


//
// When you load the plugin:
// - Assume pfnCreate is the CreatePlugin() function from GetProcAddress()
//
m_pPlugin = pfnCreate(&CGame::Get());


This way, the DLL doesn't care that the game class is a singleton - in fact it has no way to refer to it as such, so there'll only be one copy created in the EXE.

Share this post


Link to post
Share on other sites
I have two singletons MainApplication and ApplicationInterface.
ApplicationInterface uses MainApplication. I pass the ApplicationInterface singleton pointer, but because that references MainApplication. That creates a second MainApplication pointer from within the ApplicationInterface, when one was created earlier before from the main game.

Hope that helps.

-Jay

Share this post


Link to post
Share on other sites
Ohhh, I see (Sorry, I'm slow [smile]).
I think that your best bet is to combine MainApplication and ApplicationInterface into one class. I can't really see any reason for seperating them.
Alternatively, you could have a pointer to MainApplication inside ApplicationInterface that you could set at startup, and use that instead of MainApplication::Get(). It's pretty ugly, but that's all I can think of.

Share this post


Link to post
Share on other sites
It is my understanding of dlls is that dlls copy their data for the different proccesses. Is that correct? If so is there a way to make the dll use existing data and not let it make a copy of data? Example: If I make a class outide the dll and then want to use that class in the dll, it creates a second one, I don't want it to do this, I want it to use the one I created first. Is there a way to do this?

-Jay

Share this post


Link to post
Share on other sites
As far as I know, you can only do this if the one instance of the data is in the DLL. You can declare a section of the DLL shared, and put the variable in there.
All prigrams that link to the DLL access the same variable, instead of getting their own copies of it.
Here's the source from a keyboard hooking program I wrote a while ago (The pragmas are for MSVC 6.0, but they'll probably work in VC 2003 or 2005):

// Declare these as system-wide globals (shared) //
#pragma data_seg(".Dll")
HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:.Dll,rws")


That means that all exe's that link to the DLL access the same g_hHook varible. Without this, if two exe's load the DLL, they'll each get their own instance of the variable. So if program 1 sets it, it'll still be NULL in program 2. If the segment is shared, then when program 1 changes the variable, program 2 will see the change.

Share this post


Link to post
Share on other sites
Ok now based on this is there any way to flip this, and have the program make the classes and the dll just uses them without creating its own? Example I have a class called EventSystem that has a static map member and a static function called SendMessage, now EventSystem is the base class for each System, and it adds itself to the static map member and if it needs to send a message to another system it uses SendMessage which looks into the map for the System it wants to send to and if its there then it sends it. I have all this created already before the dll loads, but when I use SendMessage in the dll, it has created a second base EventSystem with no systems in it, when there should be some in there if it was the same system to begin with. So SendMEssage fails all the time because it can't find any systems in it.

Share this post


Link to post
Share on other sites
You can't use the shared data method if the data in in the exe. If it's static, then there should only be one instance of the variable, where it's declared. I assume you have the source file that declares the static variable in both the dll and exe, so you have one copy in the dll and one in the exe.
As far as I'm aware there's no way around this except to provide some kind of pointer to the static member to the dll, and not declare it at all in the dll. So, you'd have the map declared as static in the exe, and pass a pointer to the map (or a pointer to the class) to the dll.
If you pass a pointer to the class to the dll, it'll have to be through an interface, using a virtual function, otherwise the dll won't compile (it'll say that the static member was never defined).
You can't use static variables directly between dlls and exes, since you get these sorts of problems.

Share this post


Link to post
Share on other sites
Well this kinda sucks then. I am making an editor and with the editor I am makign a plugin system using dlls. I have made the base gui stuff in the library, ie a messagebox, and I wanted the plugins to be able to use this but through the event system setup already. Know of any good articles for developing a good/nice plugin system? I have looked on google/codeproject/gamedev but haven't found any good ones. The only ones I found just show me only how to write a dll and load it. Cause I thought I had a pretty good system, but now everything is getting created a second time which is no good. Thanks Evil Steve for all your help.

-Jay

Share this post


Link to post
Share on other sites
If it's just a couple of functions that you need, then you can use a function pointer, and pass it to the dll.
E.g.

//
// In the dll:
//
typedef void* (*LPGetSomething)(int nKey);
IPlugin* Create(LPGetSomething pfnAccessor);

//
// In the exe
//
class MyClass
{
public:
static void* GetSomething(int nKey);

protected:
static std::map<int,void*> s_theMap;
};

// In the source:
std::map<int,void*> MyClass::s_theMap;

int main()
{
// Load the dll and get a pointer to the plugins Create() function
pfnCreate(MyClass::GetSomething);
}


This way, the DLL calls the function pointer instead of the static function. The function pointer points to a function in the exe, so the static map in the exe is used.
As for the tutorials, I seem to recall that there's one here on GameDev.Net in the articles section, but I can't be sure.

Share this post


Link to post
Share on other sites

This topic is 4664 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this