boost::bind and boost::function across DLL boundaries?

Started by
10 comments, last by jdhardy 18 years, 4 months ago
I understand that when using DLLs, we have certain restrictions such as: 1) Memory should be new-ed and deleted in the same memory space. ie new in dll, delete in dll 2) templates used in dll's have to be instantiated(or whatever is the spelling) at compile time 3) Classes whose implementation is in the DLL(exported classes) should not be newed outside the DLL.(Im not really sure about this point or why it should be this way, perhaps someone can explain, but that is what i understand from what ive read. This explains the need for Factory classes which news an object and return a pointer to it.) Now i want to design a GUI. I have successfully made one in the past without boost but it was not in a DLL and it used a Event class i made without the use of boost. But now, i want to start using more of boost and my code is in a dll. In DLL

class DLLEXPORT Button
{
boost::function<void> onClick;
boost::function<void> onMouseOver;
boost::function<void> onMouseRelease;
//etc;
}

It should work fine here. But i want the events to be declared in the exe where the user will declare the required response. In EXE


class player
{
public:

    void play();
    void stop();
};

player thePlayer;
//use a factory because of restriction in point 3.
Button* myButton = Factory::createButton();
myButton->onClick = boost::bind(&player::play, &thePlayer);



Now i believe boost::bind will create a boost::function and myButton->onClick will be assigned the value through a copy which i believe might cause problems. I have not implemented this code yet, but i would like to clarify potential problems before i get started on it.
Advertisement
I don't see any glaring problems.

You just have to make sure you destroy everything that you need to before unloading the DLL.

Ok, so it should work. But now im in a dilemma, if i implement my events using Boost, users of my DLL will also need to download boost to use it. Because my headers contain

boost::function<void> onClick;

And they will probably need boost::bind to bind events.
This not only increases dependancies for the user but could also introduce problems because of binary incompatibilities because of different compiler settings/boost versions.

Any advice if i should still use boost?
Quote:Original post by GamerSg
Ok, so it should work. But now im in a dilemma, if i implement my events using Boost, users of my DLL will also need to download boost to use it. Because my headers contain

boost::function<void> onClick;

And they will probably need boost::bind to bind events.
This not only increases dependancies for the user but could also introduce problems because of binary incompatibilities because of different compiler settings/boost versions.

Any advice if i should still use boost?

You're going to have compiler compatibility issues with DLLs anyway, and there isn't much you can do about it (and if there is, let me know!). You'll probably have to ship a DLL per compiler anyway, so compatibility shouldn't be an issue.

Boost.Bind and Boost.Function are both header-only libraries anyway, so installing Boost (for them) is as simple as downloading/unzipping/changing the compiler include paths. Also, both are basically part of the SC++L, so it shouldn't be long before you can use std::(tr1::)function and std::(tr1::)bind.

If you're really concerned you can use Boost's bcp tool to create a version of boost that only contains what you need, and ship that with your library.
I was recently (today) pointed to the following article regarding implementing
Delegates, in C++ which might provide another alternative to using boost::function & boost::bind.

Is quite long, an initially starts with a potted history BUT it makes for interesting reading and looks like it might be of use to you.

Good luck.
Gary.Goodbye, and thanks for all the fish.
On the Memory issues:

You have to make sure your DLLs and EXE use the Multithreaded DLL or Multithreaded Debug DLL runtime libs.. Without those every module will get its own private heap ( managed by the CRT of VC ) and thus allocating in a DLL and freeing the pointer in another one ( or the Exe ) would cause an exception ( since it can't find the pointer in its own heap ) ..
If you use the Multithreaded DLL family you will get a single heap for all your in process modules and thus you can safely pass around pointer new/delete them whereever you want without problems..

On the design side.. Have you considered using boost::signal ? Its exactly what you would need for events in a GUI library in my opinion... Very similiar to .NET delegates.

You can register multiple handlers to a single signal and call the signal like a function.... Very easy to use and very powerful.
Quote:Original post by Gluber
On the Memory issues:

You have to make sure your DLLs and EXE use the Multithreaded DLL or Multithreaded Debug DLL runtime libs.. Without those every module will get its own private heap ( managed by the CRT of VC ) and thus allocating in a DLL and freeing the pointer in another one ( or the Exe ) would cause an exception ( since it can't find the pointer in its own heap ) ..
If you use the Multithreaded DLL family you will get a single heap for all your in process modules and thus you can safely pass around pointer new/delete them whereever you want without problems..

On the design side.. Have you considered using boost::signal ? Its exactly what you would need for events in a GUI library in my opinion... Very similiar to .NET delegates.

You can register multiple handlers to a single signal and call the signal like a function.... Very easy to use and very powerful.


Ok so that means that i need not follow the rule 1 on memory issues. But if a different compiler is used for the exe, it will link with a different runtime which will cause the same problems?

Quote:
You're going to have compiler compatibility issues with DLLs anyway, and there isn't much you can do about it (and if there is, let me know!). You'll probably have to ship a DLL per compiler anyway, so compatibility shouldn't be an issue.


Ill have to disagree with this, because i see programmers using the same DLL with many different VC versions/MingW with no problems.

Example
1) OpenGL (The one provided by MS/drivers from ATI/nVidia)
2) OpenAL
3) FMod
4) DirectX
etc..

I don't believe the drivers link to different dll's when you run a 3d game which was compiled in VC6/VC7/VC7.1/MingW/Intel C++. What i need to know is how they design their DLLs so that these compatibility issues dont occur.

One of the main issues i feel is to not new/delete memory in different places which makes both the DLL/EXE independant from seperate heap issues.

Ill take a look at the article and also at boost::signal.
Quote:Original post by GamerSg
Ill have to disagree with this, because i see programmers using the same DLL with many different VC versions/MingW with no problems.

Example
1) OpenGL (The one provided by MS/drivers from ATI/nVidia)
2) OpenAL
3) FMod
4) DirectX
etc..


While I cant speak for the others both OpenGL and OpenAL use C name mangling, which is standised, C++'s name mangling scheme and vTable layout ISNT, as such a native C++ library is going to probably explode if you try to use one compiled on one compiler with another.

Also, on the OpenGL front, you only link to OpenGL32.dll, it does the work to setup your commincation to the hardware.
What phantom posted is true, but it isn't the whole truth. vTable layout is not specified by the C++ standard (the standard doesn't even mandate vtables be used), but is specified by the COM standard. Because of this vTable layout has become a defacto C++ standard and any COM compliant compilers will be cross-compatible with each other, even when not using COM. To avoid the name-mangling issue you simply provide a C-based interface to create classes. Names of member functions don't matter since they are matched based on vTable layout, not name. In fact you can even have different member function names in the executable and dll. This old thread demonstrates the technique.

Enigma
Quote:Original post by phantom
Quote:Original post by GamerSg
Ill have to disagree with this, because i see programmers using the same DLL with many different VC versions/MingW with no problems.

Example
1) OpenGL (The one provided by MS/drivers from ATI/nVidia)
2) OpenAL
3) FMod
4) DirectX
etc..


While I cant speak for the others both OpenGL and OpenAL use C name mangling, which is standised, C++'s name mangling scheme and vTable layout ISNT, as such a native C++ library is going to probably explode if you try to use one compiled on one compiler with another.
OpenGL, OpenAL and FMod are pure C interfaces.
And so is DirectX really, it uses COM which is a hack for emulating C++ interfaces from C interfaces. Like this:
class com_class { struct {  void (*virtual_function)(com_class *p); } *vtable;public: inline void virtual_function() { vtable->virtual_function(this); }};
Of course the whole process is wrapped up in a bunch of utility macros that makes things somewhat easier.

In general exporting C++ interfaces in a portable manner is painful, requires a lot of work, and limits the use of many basic language features. Exceptions and dynamic memory allocation can't be used reliably across DLL boundaries for instance. If the OP truly needs to ship a single portable DLL then I suggest either using a pure C interface or looking into how COM handles these issues.

This topic is closed to new replies.

Advertisement