Returning C ++ objects from a Windows DLL

Due to the way Microsoft implements a bunch in its non-DLL runtime versions, returning a C ++ object from a DLL can cause problems:

// dll.h DLL_EXPORT std::string somefunc(); 

and

 // app.c - not part of DLL but in the main executable void doit() { std::string str(somefunc()); } 

The above code works fine, and the DLLs and EXEs are built using a multi-threaded DLL runtime library.

But if the DLLs and EXEs are built without a DLL runtime library (or with single-user or multi-threaded versions), the above code does not work (with the debug version, the code is interrupted immediately due to a _CrtIsValidHeapPointer(pUserData) approval error; with a non-debug runtime the heap gets corrupted, and the program ends up not working elsewhere).

Two questions:

  • Is there a way to solve this problem and then require all the code to use the DLL runtime?
  • For people who distribute their libraries to third parties, how do you deal with this? Are you using C ++ objects in your API? Do you need your library users to use DLL runtime? Something else?
+4
source share
5 answers

There is a way to handle this, but it is somewhat nontrivial. As with most other libraries, std::string does not allocate memory directly with new - instead, it uses a allocator ( std::allocator<char> , by default).

You can provide your own allocator that uses your own heap allocation routines that are common to the DLL and the executable, for example, using HeapAlloc to get memory and lock between them.

0
source

Is there a way to solve this problem and then require all the code to use the DLL runtime?

Not that I knew.

For people who distribute their libraries to third parties, how do you deal with this? Are you using C ++ objects in your API? Do you need your library users to use DLL runtime? Something else?

In the past, I distributed the w / dll SDK, but was based on COM. With COM, all parameter marshalling and IPC is done automatically for you. Users can also integrate with any language in this way.

+1
source

There are two potential problems in your code: you turned to the first - CRT. You have one more problem: std :: string may change in VC ++ versions. In fact, this has really changed in the past.

A safe way to deal is to export only the base types of C. And it exports both the creation and release functions from the DLL. Instead of exporting std :: string, export the pointer.

 __declspec(export) void* createObject() { std::string* p = __impl_createObject(); return (void*)p; } __declspec(export) void releasePSTRING(void* pObj) { delete ((std::string*)(pObj)); } 
+1
source

If you have a DLL that you want to distribute, and you do not want to associate your subscribers with a specific version with C-Runtime, do one of the following:

I. Link the DLL to the static version of the C-Runtime library. On the Visual Studio project properties page, select the tab Configuration Properties → C / C ++ → Code Generation. This is an option to select "Runtime Library". Select Multithreading or Multithreaded Debugging instead of DLL versions. (Conditional command line value is / MT or / MTd)

There are several different disadvantages to this approach:

a. If Microsoft ever releases a CRT security patch, your submitted components may be vulnerable until you recompile and reinstall your binary.

b. The heap pointers allocated by "malloc" or "new" in the DLL cannot be "free" or "delete" d EXE or other binary code. Otherwise you will collapse. The same is true for FILE descriptors created by fopen. You cannot invoke fopen in a DLL and expect the exe to depend on it. Again, if you do. You will need to create an interface for your DLL to be resistant to all these problems. For starters, a function that returns an instance in std :: string is likely to be a problem. Provide the functions exported by your DLL to handle the release of resources as needed.

Other parameters:

II. Ship without c-runtime depedency. This is a little trickier. First you need to remove all calls from the CRT from your code, provide some stub functions to link the DLL, and provide a link to the "no by default" link. It can be done.

III. C ++ classes can be exported from DLLs using COM interface pointers. You still have to solve the problems described in 1a above, but ATL classes are a great way to get rid of COM overhead.

0
source

The simple fact is that the Microsoft implementation aside, C ++ is not an ABI. You cannot export C ++ objects on any platform from a dynamic module and expect them to work with another compiler or language.

Exporting C ++ classes from Dlls is pretty much pointless exercise - due to name changes and lack of support in C ++ for dynamically loaded classes - DLL files must be loaded statically, so you lose the biggest advantage of splitting a project into dlls - the ability Download only functionality.

0
source

Source: https://habr.com/ru/post/1306531/


All Articles