C Execution Objects, dll boundaries

What is the best way to develop a C API for a dll that deals with the problem of passing "C-dependent" objects "(FILE *, pointer returned by malloc, etc.). For example, if two DLLs are associated with a different version of the runtime, I understand that you cannot safely transfer FILE * from one dll to another.

Is the only solution to use a Windows-dependent API (which is guaranteed to work through a DLL)? The C API already exists and is mature, but was developed using unix POV, basically (and still needs to work on unix, of course).

+6
windows unix dll abi
source share
4 answers

You asked for C, not C ++ - a solution.

The usual method for doing this kind of operation in C is:

  • Create a module API to simply not require CRT objects. Get the material that went through the raw types of C - for example, ask the consumer to download the file and just give you a pointer. Or, ask the consumer to pass the full file name, open, read, and closed inside.

  • The approach used by other c modules, the SD MS cabinet and parts of the OpenOSL iirc library comes to mind so that the consumer application passes pointers to the functions of the initialization function. Thus, any API that you pass FILE * at some point during initialization takes a pointer to a structure with function pointers corresponding to the signatures fread, fopen, etc. When working with external FILE * s, the dll always uses the function passed, not the CRT function.

With some simple tricks, you can make your C-DLL interface completely independent of CRT hosts - or actually require the host to be written in C or C ++ in general.

+2
source share

None of the existing answers are correct: given the following on Windows: you have two DLLs, each of them is statically linked to two different versions of the standard C / C ++ libraries.

In this case, you should not pass pointers to structures created by the standard C / C ++ library in one DLL, in another. The reason is that these structures may be different between the two standard implementations of the C / C ++ library.

Another thing you do not need to do is a free pointer allocated by the new or malloc from one DLL that has been allocated to another. A different heap implementation may also be implemented.

Note. You can use pointers between DLLs - they just point to memory. This is freedom in this.

Now you may find that it works, but if so, then you are just lucky. This is likely to cause problems in the future.

One possible solution to your problem is dynamic linking with CRT . For example, you can dynamically bind to MSVCRT.DLL. Thus, your DLL will always use the same CRT.

Note. I recommend that you fail to transfer CRT data structures between DLLs. You might want to know if you can improve the situation.

Please note that I am not an expert on Linux / Unix, but you will have the same problems for these OSs.

+1
source share

The problem with different runtimes is not resolvable because the FILE * structure belongs to the same runtime on Windows.

But if you write a small wrapper interface made by you, and in fact it will not hurt.

stdcall IFile* IFileFactory(const char* filename, const char* mode); class IFile { virtual fwrite(...) = 0; virtual fread(...) = 0; virtual delete() = 0; } 

This is a save that will be passed along dll borders everywhere and is not really painful.

PS: Be careful if you start throwing exceptions across dll boundaries. This will work well if you run some design scripts on Windows, but do not work on some others.

0
source share

If the C API exists and is mature, bypassing the CRT internally using the pure Win32 API component, you get half the way. The other half ensures that the DLL user uses the appropriate Win32 API functions. This will make your API less portable, both for use and for documentation. Also, even if you go this way with memory allocation, where CRT and Win32 functions deal with void *, you still have problems with the files - the Win32 API uses descriptors and knows nothing about the FILE structure.

I'm not quite sure what the limitations of FILE * are, but I assume the problem is the same as when distributing CRT between modules. MSVCRT uses Win32 to handle file operations, and the main file descriptor can be used from each module within the same process. What may not work is to close the file that was opened by another module, which involves releasing the FILE structure on a possibly different CRT.

What would I do if the API change is still an option, these are export cleanup functions for any possible "object" created in the DLL. These cleanup functions will handle the deletion of this object in a way that matches the way it was created in this DLL. It will also make the DLL completely portable in terms of use. The only concern you are having is that the DLL user actually uses your cleanup functions, not regular CRTs. This can be done with a few tricks that deserve another question ...

0
source share

All Articles