tags:

views:

1139

answers:

4

I've been reading many a tutorial/article on unmanaged DLLs in C++. For the life of me, however, I cannot seem to grasp the concept. I'm easily confused by the seeming disagreement about whether it needs a header file, how to export it, whether I need a .lib file and what have you.

So, let's assume I have just a function like so:

public int calculateSquare(int num)
{
    return num*num;
}

Ignoring the actual code, what do I require to make this simple function, by itself, into a DLL which I can then call? Do I just add __dllexport or whatever it is to the first line or do I require a header? I am perplexed by all of this.

+12  A: 

I cannot stress this enough, the C++ compiler does not see header files, after the preprocessor is done, there's just one big source file ( also called the compilation unit ). So strictly you don't need a header to export this function from a dll. What you do need is some form of conditional compilation to export the function in the dll that you are compiling and to import it in the client code.

Typically this is done with a combination of macros and header files. You create a macro called MYIMPORTEXPORT and through the use of macro conditional statements you make it work like __declspec ( dllexport ) in the dll, and __declspec( dllimport ) in the client code.

in file MYIMPORTEXPORT.h

#ifdef SOME_CONDITION
#define MYIMPORTEXPORT __declspec( dllexport )
#else
#define MYIMPORTEXPORT __declspec( dllimport )
#endif

in file MyHeader.h

#include <MyImportExport.h>

MYIMPORTEXPORT public int calculateSquare(int num)
{
    return num*num;
}

in dll .cpp file

#define SOME_CONDITION

#include <MyHeader.h>

in client code .cpp file

#include <MyHeader.h.

Of course you also need to signal to the linker that you are building a dll with the /DLL option.

The build process will also make a .lib file, this is a static lib - called the stub in this case - which the client code needs to link to as if it were linking to a real static lib. Automagically, the dll will be loaded when the client code is run. Of course the dll needs to be found by the OS through its lookup mechanism, which means you cannot put the dll just anywhere, but in a specific location. Here is more on that.

A very handy tool to see whether you exported the correct function from the dll, and whether the client code is correctly importing is dumpbin. Run it with /EXPORTS and /IMPORTS respectively.

QBziZ
A: 

You need to export the function using either__declspec( dllexport ) or adding the function to a module definition file (.def). Then compile tho project as a DLL.

On the client side, you have two options. Either use an import library (.lib) which is generated when compiling the DLL. Simply linking with your client project with this library will give you access to the functions exported from the DLL. And you need a header file, because the compiler needs to know the signature of your function - that it returns int and takes an int. To recap, you need to link with an import library (.lib) and a header file which contains the header of your function.

Another way is to load the DLL dynamically using WinAPI call LoadLibrary and then GetProcAddress to obtain a pointer to the function. The pointer to function must have the correct type, so that the compiler can give it it the correct parameters and the correct calling convention is used.

Roman Plášil
+6  A: 

QBziZ' answer is right enough. See http://stackoverflow.com/questions/236035/unmanaged-dlls-in-c#236052

To complete it: In C++, if you need to use a symbol, you must tell the compiler it exists, and often, its prototype.

In other languages, the compiler will just explore the library on its own, and find the symbol, et voilà.

In C++, you must tell the compiler.

See a C/C++ header as a book table of contents

The best way is to put in some common place the needed code. The "interface", if you want. This is usually done in an header file, called header because this is usually not an independent source file. The header is only a file whose aim is to be included (i.e. copy/pasted by the preprocessor) into true source files.

In substance, it seems you have to declare twice a symbol (function, class, whatever). Which is almost an heresy when compared to other languages.

You should see it as a book, with a summary table, or an index. In the table, you have all the chapters. In the text, you have the chapters and their content.

And sometimes, you're just happy you have the chapter list.

In C++, this is the header.

What about the DLL?

So, back to the DLL problem: The aim of a DLL is to export symbols that your code will use.

So, in a C++ way, you must both export the code at compilation (i.e., in Windows, use the __declspec, for example) and "publish" a table of what is exported (i.e. have "public" headers containing the exported declarations).

paercebal
+1  A: 

Checklist for exporting functions:

  • Is the calling convention suitable for the caller? (this determines how parameters and results are passed, and who is responsible for cleaning up the stack). You should state your calling convention explicitely.
  • Under which name the symbol will be exported? C++ usually needs to decorate ("mangle") the names of symbols, e.g. to distinguish between different overloads.
  • Tell the linker to make the function visible as DLL Export

On MSVC:

  • __stdcall (which is pascal calling convention) is the typical calling convention for exported symbols - supported by most clients I guess.
  • extern "C" allows you to export the symbol C-style without name mangling
  • use __declspec(dllexport) to mark a symbol to be exported, or link a separate .def file where the symbols to be exported are listed. With a .def fiel you can also export by ordinal only (not by name), and change the name of the symbol that is exported.
peterchen