[dev-cpp trimmed because I don't read their list]
Carlos García del Monte wrote:
> But some days ago here (mingw-users) was a thread of messages about dll,
> in which I read speaking about the problems of C++ code inside dlls,
> just due to the function's mangling for support overloading in c++.
The way a class (and especially its virtual function
table) is laid out in memory is implementation defined.
When the layout differs between two compilers, the
object files they produce must not be linked together.
That might appear to work in some cases, but fail
mysteriously in others. Therefore, in that case, it
has been considered wise for each compiler to mangle
names differently--in order to make it impossible to
link incompatible object files. Mangling differences
aren't the problem; they protect against the problem.
I think Stroustrup said this in D&E, but I can't find
my copy right now.
Different implementations may however agree to use
the same binary interface. I know gcc-3.x was designed
to conform to some such standard, but I don't know
much about it.
> Searching for some things I found at
I tried this URL but got 'Error 404 Not found'.
> , a work about memory management
> and dlls by Steve Riggal where the author proposes a way for working
> with objects inside dlls.
> Since the title of the subsection (it is treated in chapter 4) is
> portable class exports, I understands he claims with that you can make a
> dll for use with any compiler/system.
> In short, his way consists on making two classes, one private to the dll
> and one public.
Apparently this is the 'envelope-letter' idiom.
> First the public: it's a header file you'll have to include in your
> source file (it is done for implicit loading, through a lib file which
> has an export table, but I guess it should work in explicit loading), it
> defines a pure virtual class and a function for creating a instance of
> the object which returns a pointer to it and is declared as extern "C".
So far, this sounds clever enough: the 'letter'
contains everything that would cause linker
problems, and the 'envelope' is extern "C".
But I don't see how he's going to call virtual
functions on the object.
> Nothing more. All its functions are pure virtual, and only define the
> functions (at least in the example he gives, but I assume it will be
> done this way always).
> Then a def file which exports only the function for creating an object.
So far so good, I guess. The virtual functions
> And a private one.
[snip] OK, that's the 'letter' (implementation)
inside the 'envelope' (interface).
> In the cpp of the program (linked to the lib file) he creates instances
> of the class by:
> public_header_class *object = object_creator_function();
> and then he uses all the functions as usual
I don't understand how this could work.
An application built with compiler A that calls a
virtual function in a dll built with compiler B
needs to know the layout of B's vtable, doesn't it?
> I see the idea, but it works? I didn't see it very clear.
> My thought was that it avoids the problem when calling the creating
> function of the dll, but at the end you will have to use the member
> functions, and those will have to be compiled there by the compiler
> which built the dll, haven't them the mangling which generates the
I think we share the same concern. I emphasize
the vtable, and you emphasize mangling, but I
think both would prevent this from working.
> Don't you have your source file being mangled with your
> compiled ways and the dll with its builder way of mangling? Or it
> happens only for the function that will be exported, and the others lose
> the decoration?
The only function in the .def file is an
extern "C" function that creates an object.
Here's what I suppose happens for the virtual
functions. The application that uses the dll
has a header that specifies the abstract base
class's virtual functions, so calling them is
not a *compiler* error. But how would the
linker resolve the call? Consider that in two
aspects: mangling, and the vtable.
Mangling should not be an issue. Only *names*
can be mangled. But the dll exports only one
name, which is not mangled because it's
declared extern "C". The application that
uses the dll doesn't know what names the
dll uses for virtual functions.
But I think the vtable is an issue. The
application that uses the dll will look up
the virtual functions in a manner determined
by the compiler used to build the application.
If the compiler used to build the dll lays
out objects differently, then the address of
the virtual function it calls is likely to
be incorrect. As they say, it may format
your hard disk, and then demons will fly out
> Wouldn't be better use structs besides all their
> limitations (I mean if portability is a matter)?
Using a struct does not guarantee portability
across compilers. There are certain layout
compatibility guarantees for POD-structs
(which cannot have virtual functions), but
they don't guarantee compatibility between
> So I decided try it building the executable with mingw and Borland5.5,
> using the dll produced by mingw and the one provided by the author.
> Then I built both the dll and the executable with MinGW and ran without
> I've tried to build the user project linking to the lib file he provides
> with the examples, surely it was compiled with visual C++, I compile it
> succesfully, but when I run it generated an access violation.
You're lucky that demons did not fly out your
nose. But that may happen the next time you
run the program.
> And I
> haven't done anything wrong during compiling, since I did it twice: one
> with the dll from the example, compiled by the author (surely with
> Visual C++), in which case it generated the access violations, and
> another time with the dll generated by mingw, in this case it ran
> without problems even using the lib provided by the author.
The universe of undefined behavior includes
the possibility that the program will appear
to run correctly sometimes.
> I tried then with Borland, and it worked!. It works linking to the dll
> produced by mingw, so it is true.
I would conjecture that their vtable layouts
are the same for this example. Maybe they
differ in some other way that a different
example would reveal.
> So my supposition about code mangling
> of the class functions are erroneous,
Differences in mangling are a desirable safety
feature. Negating that safety feature elicits
the unsafe behavior it was intended to prevent.
> what happens is that code mangling
> matters only for exported functions, not for the other which are yet
> inside the dll. And that's the reason why it works.
> However linking to the dll provided with the zip file you find in the
> tutorial, which has all the sources, produces memory access violations.
> Now I noticed that the dll provided by him is 200Kb, and the one
> produced by mingw is 29Kb, that makes me think as something almost
> evident he is providing a debug version of the dll, and that's the
> reason it doesn't work with executables produced by mingw and borland.
I don't think the inclusion of debug
information should make a difference.
> The only point with Borland is since I didn't build the dll with
> Borland, I had to use coff2omf (an app with borland which translates
> coff format libs to omf) over the import library, and link to it, in
> that process the effect is that the executable doesn't ask for
> mydll2.dll, it asks for DS00000.o, so I had to rename it, but I guess it
> is a problem that can be solved in some way.
> And if I use the lib provided by the author it says "undefined reference
> to %s", where %s is the create_public_object_function() preceded by an
> The only I left now to do, and I'll see later is what happens about
> inheritance from it, but I suppose there would be an easy way of work
> around it if it doesn't work directly.
If this approach were viable, wouldn't
someone else have discovered it many
years ago? I think the only way to get
binary compatibility between different
compilers is a standard application
binary interface. Perhaps some of your
other compilers use the same ABI as
the latest g++.