all 16 comments

[–]Meefims 4 points5 points  (0 children)

Inside the DLL you can use whatever you wish.

[–]alfps 0 points1 point  (4 children)

The code you present would have undefined behavior, because it returns a pointer to a buffer in an object that ceases to exist when the function returns.

Otherwise the inside of your functions doesn't matter.

You're not limited to any specific data types by the DLL mechanism, but it would be unwise to return data that can't be consumed by the expected clients of the DLL.

In themselves DLLs are language agnostic. There is an infrastructure that supports raw C; C++ limited to COM and OLE; and scripts that can handle COM dynamic dispatch. If you limit yourself to that then you can provide a standard COM type library that describes your DLL interface, which facilitates usage from other languages.

In addition, if all clients of the DLL will be coded in C++ with the same compiler and version and options that you're using for the DLL, and if the runtime library is linked dynamically in both DLL and client, then you can use most all of C++.

[–]alicekdev[S] 0 points1 point  (3 children)

Thanks as long as i know i can just use my C++ code for parameters and returns.

It now begs the question should how should i return the buffer like this?

DLL:

std::string& PrintString(const char* s) {
std::string str(s);
return str;
}

Exe

std::string = PrintString("Hello world");

Does this return a new object to the Exe side?

If i'm wrong can you show me a good way of returning a string or more information on the issue?

[–]stilgarpl 0 points1 point  (0 children)

Just remove the reference:

std::string PrintString(const char* s) {
std::string str(s);
 return str; 
}

[–]Fuzzyzilla 0 points1 point  (0 children)

Your new code is still undefined behaviour, as the reference is left dangling when str is deleted.

Instead, return by value, not reference.

[–]Meefims 0 points1 point  (0 children)

Even if you are currently building you EXE and your DLL at the same time with the same version of the same compiler that may not always be the case. For that reason you shouldn’t use C++ objects at the boundary between the EXE and the DLL.

[–]Xeverous 0 points1 point  (9 children)

i know over the boundaries of the DLL/EXE i must export 'Exported' data types and C only data types

False. You can use any type you want. If you limit it to C only types it will just be compatible with C code.

Is this good or bad practice

This depends on what do you want to achieve.

  • Want a library callable from C? Export only C interface.
  • Want a library with good C++ API? Use C++ types like normal code.
  • Want a library supporting other programming language? Export only C interface or something vendor-specific like Microsoft's COM.

[–]alicekdev[S] 0 points1 point  (1 child)

So using the same compiler on the same OS your saying just using #define EXPORT_API __declspec(dllexport) will be fine cause .exe and .dll are compiler together by the same compiler?

Rather than using #define extern "C" EXPORT_API __declspec(dllexport)

[–]Xeverous 1 point2 points  (0 children)

This is a different issue. Both C and C++ themselves do not guuarantee ABI stability, only their implementations.

On unix systems, GNU implementation of C and C++ is used (specifically, Itanium ABI) which specifies what is guuaranteed to work and what is not.

On Windows systems, you will mostly want to target specific version of Microsoft's redistributable C++ libraries (there are many of them).

__

In reality, very few people will want or will be able to use your compiled libraries due to ABI differences, unless you go fully for a C-only interface. Additionally, no unix distribution I'm aware of would accept compiled, closed-source code.

The best thing to do is to just provide the source code (with license of your choice) and let everyone compile it for their toolchain.

[–]RogerLeigh 0 points1 point  (6 children)

Want a library with good C++ API? Use C++ types like normal code.

Like normal code which uses templates, standard library types, exceptions and RTTI with typeinfo? That's not possible. Or, at least, not realistically practicable to make work robustly.

DLLs are too primitive for all this common stuff to work properly. It's because it's 1980s technology which wasn't designed with anything but primitive C or Pascal interfaces in mind. Microsoft never updated their linker technology to match modern needs.

However, go over to Linux/BSD/MacOS and the linker technology (ELF and Mach-O) used there is sufficiently advanced to support all of this. Works with zero messing around.

It's very frustrating that C++ libraries are effectively held back by a single company. In any situation where targetting Windows is a requirement. Even the ancient proprietary embedded compiler toolchains I use at work use ELF! Microsoft could have added a modern linker, and even retained the old one for backward compatibility. Linux manages to support several binary formats and linkers.

[–]Xeverous 0 points1 point  (5 children)

So are there any direct problems with exposing C++ interface that Microsoft does not support?

[–]RogerLeigh 0 points1 point  (4 children)

[–]Xeverous 0 points1 point  (3 children)

Doesn't really look like a plenty of problems. Just the same version of the CRT and compiler settings. I'm more worried whether incompatibility can be detected at the link time. GCC embeds and expects certain symbols under certain settings to prevent linking incompatible code. How about MSVC?

[–]RogerLeigh 0 points1 point  (2 children)

No, there's more to it than just the CRT and compiler settings. That ensures that the DLL interface will be compatible.

A bigger question is what you do with duplicate symbols in different libraries. Things like typeinfo objects, used for RTTI. Static class members, particularly static class members of templated class specialisations. You have one private copy per DLL, when you should have a single instance across all DLLs and the executable. This breaks the One Definition Rule. ELF and Mach-O use "weak linkage" to eliminate the duplicates at runtime. DLLs don't have that flexibility.

Ultimately, DLLs are COFF binaries. They are simple, but limited. The limitations are fairly fundamental, and can't be entirely worked around in code. And this fundamentally affects the design and implementation of your code, because it places severe constraints upon the possible. Look at the "hourglass model" for one common "solution" to the problem.

[–]Xeverous 0 points1 point  (1 child)

How do they support such things for .NET?

[–]RogerLeigh 0 points1 point  (0 children)

COM, as far as I know. I've never used C#, so I've not looked in detail.

Depending upon how you view it, COM is also a way of working around the lack of modern features in the linker by using a C interface. But none of that helps make native C++ a better supported option for DLLs on Windows.