Passing classes across DLL boundaries is a bad idea due to undefined vtable layout in c++, but what if I explicitly set the calling convention, and avoid virtual functions and inheritance?
In other words, could i safely pass pointers to the following struct across a DLL?
struct MyStruct {
int a;
int b;
WINAPI MyStruct(int a, int b)
: a(a), b(b)
{}
void WINAPI SetA(int a) {
this->a = a;
}
};
Would it be safe to use link to such a DLL with a differetnt compiler version etc?
Your code is really equivalent to the following C code:
struct MyStruct {
int a;
int b;
};
void WINAPI InitMyStruct(struct MyStruct* p, int a, int b)
{
p->a = a; p->b = b;
}
void WINAPI MyStruct_SetA(struct MyStruct* p, int a)
{
p->a = a;
}
Avoiding virtual functions has basically bought you nothing; it is still compiler-dependent what these "equivalent" C functions will be called ("name mangling") so you need to use compatible compilers. All versions of MSVC from this millennium are compatible with each other in this respect. All versions of GCC from this millennium are compatible with each other. Just don't mix the two (link-time errors will happen).
There are other sources of problems:
Make sure your packing/alignment settings match up (but they need to do that for plain C interfaces, as well).
If you use "new" in one DLL and "delete" in another, you might be in trouble unless you use the exact same compiler version and use the DLL runtime library. So don't new
or delete
your MyStruct object from client code; instead, provide functions inside the DLL to do that for you.
Stay away from standard library containers in your interface. They won't work if the DLL and the client aren't linked to the same standard library.
Don't be afraid of virtual functions.
Note: all these problems exist in theory on other platforms as well, but appear to be a little less relevant in practice for Linux and Mac OS X.