views:

1250

answers:

5

This question is related to "How to make consistent dll binaries across VS versions ?"

  • We have applications and DLLs built with VC6 and a new application built with VC9. The VC9-app has to use DLLs compiled with VC6, most of which are written in C and one in C++.
  • The C++ lib is problematic due to name decoration/mangling issues.
  • Compiling everything with VC9 is currently not an option as there appear to be some side effects. Resolving these would be quite time consuming.
  • I can modify the C++ library, however it must be compiled with VC6.
  • The C++ lib is essentially an OO-wrapper for another C library. The VC9-app uses some static functions as well as some non-static.

While the static functions can be handled with something like

// Header file
class DLL_API Foo
{
    int init();
}

extern "C"
{
    int DLL_API Foo_init();
}

// Implementation file
int Foo_init()
{
    return Foo::init();
}

it's not that easy with the non-static methods.

As I understand it, Chris Becke's suggestion of using a COM-like interface won't help me because the interface member names will still be decorated and thus inaccessible from a binary created with a different compiler. Am I right there?

Would the only solution be to write a C-style DLL interface using handlers to the objects or am I missing something? In that case, I guess, I would probably have less effort with directly using the wrapped C-library.

+1  A: 
MadKeithV
+1  A: 

Interface member names will not be decorated -- they're just offsets in a vtable. You can define an interface (using a C struct, rather than a COM "interface") in a header file, thusly:

struct IFoo {
    int Init() = 0;
};

Then, you can export a function from the DLL, with no mangling:

class CFoo : public IFoo { /* ... */ };
extern "C" IFoo * __stdcall GetFoo() { return new CFoo(); }

This will work fine, provided that you're using a compiler that generates compatible vtables. Microsoft C++ has generated the same format vtable since (at least, I think) MSVC6.1 for DOS, where the vtable is a simple list of pointers to functions (with thunking in the multiple-inheritance case). GNU C++ (if I recall correctly) generates vtables with function pointers and relative offsets. These are not compatible with each other.

Roger Lipscombe
+3  A: 

The biggest problem to consider when using a DLL compiled with a different C++ compiler than the calling EXE is memory allocation and object lifetime.

I'm assuming that you can get past the name mangling (and calling convention), which isn't difficult if you use a compiler with compatible mangling (I think VC6 is broadly compatible with VS2008), or if you use extern "C".

Where you'll run into problems is when you allocate something using new (or malloc) from the DLL, and then you return this to the caller. The caller's delete (or free) will attempt to free the object from a different heap. This will go horribly wrong.

You can either do a COM-style IFoo::Release thing, or a MyDllFree() thing. Both of these, because they call back into the DLL, will use the correct implementation of delete (or free()), so they'll delete the correct object.

Or, you can make sure that you use LocalAlloc (for example), so that the EXE and the DLL are using the same heap.

Roger Lipscombe
Problems with dynamic memory allocations in different heaps are a huge issue that many people don't get.
John Dibling
A: 

not fun, man. you are in for a lot of frustration, you should probably give this:

Would the only solution be to write a C-style DLL interface using handlers to the objects or am I missing something? In that case, I guess, I would probably have less effort with directly using the wrapped C-library.

a really close look. good luck.

Dustin Getz
+1  A: 
orcmid