* Writing libraries is a big hassle in Windows because you have to explicitly define all exportable symbols.
* DLLs have all kinds of strange boundary rules. C++ exceptions cannot pass DLL boundaries. Heap memory allocated by one DLL cannot always be freed by another. Etc etc.
The second problem has got nothing to do with DLLs and everything to do with the fact that there is no C++ ABI.
As for memory allocation, it's not really a good idea to allocate memory in a library and free it in another, is it?
Ah, I guess I'll have to stop using strdup() then.
However, yes, for security reasons strdup should be avoided.
Just like in Aix, unless it is now changed (my experience goes back to 2001).
> C++ exceptions cannot pass DLL boundaries.
C++ restrictions have to do with lack of C++ ABI. You have in same issue in ELF systems, when mixing compilers.
> Heap memory allocated by one DLL cannot always be freed by another.
This is a good thing. Object handles belong to the module that created them, and it is a good way to ensure a clean way to use accessor functions to deal with data.
No, it doesn't prevent anything. There is nothing stopping you from calling free() on a buffer returned from a function in a DLL, it just might crash. There is nothing inherently superior about adding an additional source of crashes which are not diagnosed by the compiler.
Are you sure this isn't just a C++ problem? It's a well known fact that due to name mangling, C++ compiled by different compilers (even different versions of the same compiler!) can't always be called.
The same thing could happen if two people, for example, linked against different major versions of an XML parser: they would be unable to share state, as data returned from one library would have been generated with one XML library and then would be modified by another, even though the types matches for the purposes of the C compiler.
In practice, different major versions should simply be considered different libraries, and many argue it is an encapsulation mistake to allow your public interface to be bound up with details of the libraries you use; however, this kind of use case is much more likely to either work correctly or fail horribly on Linux, as opposed to ending up in some kind of weird uncanny valley of stability.
People then reference C++ with regards to this, because C++ happens to have a library that acts on tons of core data types, and yet by default (you can build setups where this doesn't happen, but it requires coordination over the DLLs you are mingling) compiles trivial parts of the algorithms inlined into your logic (so there isn't even a function boundary at all, much less code that could be shared easily).
The result is that if C++ touches your public interface, you are almost certainly, at bare minimum, wanting to share something "simple" like a string or a vector, or alternatively wanted to use exceptions somewhere. You now, however, run into the XML library issue.
Some people believe this is simply bad API design (as C++ should be treated as a library to encapsulate), while others believe it is a language deficiency. I argue that to the extent it is the latter you probably do control the DLLs that are acting as a set, and external APIs should operate under the former regime (as yes: you also have to worry about name mangling there, although compilers have gotten very good at that: we now tend to see them as part of the system ABI).
[1] http://msdn.microsoft.com/en-us/library/windows/desktop/aa37...
As an example:
/usr/lib/libreadline.dylib is actually /usr/lib/libedit.2.dylib
/System/Library/Frameworks/Python.framework/Python is actually /System/Library/Frameworks/Python.framework/Versions/2.6/Python
You can thereby have symbols linked from both /System/Library/Frameworks/Python.framework/Versions/2.5/Python and /System/Library/Frameworks/Python.framework/Versions/2.6/Python. "(Note that the module filenames are identical.)"
On Windows, all inter-module dependencies are (module, symbol) pairs (written "module!symbol"), not just bare symbol names as on ELF systems. That is, modA!fun1 calling modB!fun2 can exist in the same process as a modC!fun1 calling modD!fun2. The Windows model doesn't permit global interposition, but that's a good thing: the lack of interposition support permits the optimizations Macieira mentions, but "hooking" is still possible through a variety of mechanisms, which usually involve either overwriting import and export tables or the replacement of function preambles with jumps to trampolines.
Regardless of the performance considerations, I think the Windows DLL approach is the more robust and conceptually lighter one. That the Windows approach is also faster is simply a beneficial side effect.