Windows & C++: extern & __declspec(dllimport) - c++

What is the difference/relationship between "extern" and "__declspec(dllimport")? I found that sometimes it is necessary to use both of them, sometimes one is enough.
Am I right that:
"extern" is for statically linked libraries,
"__declspec(dllimport)" is for DLL (dynamically linked libraries),
both do actually the same job for their respective type of linking,
you need to use both when you use import libraries (small .lib files that help linking with dll)?

extern means that the entity has external linkage, i.e. is visible outside its translation unit (C or CPP file). The implication of this is that a corresponding symbol will be placed in the object file, and it will hence also be visible if this object file is made part of a static library. However, extern does not by itself imply that the symbol will also be visible once the object file is made part of a DLL.
__declspec(dllexport) means that the symbol should be exported from a DLL (if it is indeed made part of a DLL). It is used when compiling the code that goes into the DLL.
__declspec(dllimport) means that the symbol will be imported from a DLL. It is used when compiling the code that uses the DLL.
Because the same header file is usually used both when compiling the DLL itself as well as the client code that will use the DLL, it is customary to define a macro that resolves to __declspec(dllexport) when compiling the DLL and __declspec(dllimport) when compiling its client, like so:
#if COMPILING_THE_DLL
#define DLLEXTERN __declspec(dllexport)
#else
#define DLLEXTERN __declspec(dllimport)
#endif
To answer your specific questions:
Yes, extern alone is sufficient for static libraries.
Yes -- and the declaration also needs an extern (see explanation here).
Not quite -- see above.
You don't strictly need the extern with a __declspec(dllimport) (see explanation linked to above), but since you'll usually be using the same header file, you'll already have the extern in there because it's needed when compiling the DLL.

Related

How does __declspec exactly work? [duplicate]

I had a question about DLL building / linking in Visual Studio 2005 and later. Basically my understanding and experience is this:
To build a DLL, I specify the project properties to build a DLL, and then I but __declspec(dllexport) in front of any functions or members that I want to publically expose from the DLL. Building the project will result in a DLL, a Lib, and a header file that can be deployed as say an API or something.
On the other end, to have your other compiled executable application dynamically link to the DLL and use its functions, you simply need to have your executable project include the header files and link with the small lib file that was created when the DLL was built. As long and the compiled application can find the DLL, everything will work.
That has been my experience and that is also how the Microsoft DLL building tutorial described everything on MSDN. I am wondering: is this standard practice? When would you ever need to use __declspec(dllimport) anywhere? Am I missing something?
Thanks!
Yes you would use __declspec(dllimport) and you generally have a macro that controls whether a source file either exports (if it's part of your DLL) or imports (if it's part of the using-executable) symbols.
In your DLL you can set a manifest constant to the build settings of some sort, say 'BUILDING_MY_DLL' and then create the macro like this within your header file:
#ifdef BUILDING_MY_DLL
#define MY_DLL_EXPORT __declspec(dllexport)
#else
#define MY_DLL_EXPORT __declspec(dllimport)
#endif
and then decorate your exported functions like this:
MY_DLL_EXPORT int func(int y);
You can also export entire classes this way too:
class MY_DLL_EXPORT InterestingClass
{
...
};

When is __declspec(dllimport) used? [duplicate]

I had a question about DLL building / linking in Visual Studio 2005 and later. Basically my understanding and experience is this:
To build a DLL, I specify the project properties to build a DLL, and then I but __declspec(dllexport) in front of any functions or members that I want to publically expose from the DLL. Building the project will result in a DLL, a Lib, and a header file that can be deployed as say an API or something.
On the other end, to have your other compiled executable application dynamically link to the DLL and use its functions, you simply need to have your executable project include the header files and link with the small lib file that was created when the DLL was built. As long and the compiled application can find the DLL, everything will work.
That has been my experience and that is also how the Microsoft DLL building tutorial described everything on MSDN. I am wondering: is this standard practice? When would you ever need to use __declspec(dllimport) anywhere? Am I missing something?
Thanks!
Yes you would use __declspec(dllimport) and you generally have a macro that controls whether a source file either exports (if it's part of your DLL) or imports (if it's part of the using-executable) symbols.
In your DLL you can set a manifest constant to the build settings of some sort, say 'BUILDING_MY_DLL' and then create the macro like this within your header file:
#ifdef BUILDING_MY_DLL
#define MY_DLL_EXPORT __declspec(dllexport)
#else
#define MY_DLL_EXPORT __declspec(dllimport)
#endif
and then decorate your exported functions like this:
MY_DLL_EXPORT int func(int y);
You can also export entire classes this way too:
class MY_DLL_EXPORT InterestingClass
{
...
};

How do I fix an Unresolved External Symbol error in my C++ DLL?

I have a dll, which accesses some classes outside of its project (I'm using Visual Studio, so I have two projects). The thing is, in the header that the dll includes, which is outside of the dll's project, there are only bodies of functions, like this:
x.h
class x
{
void myFunc();
}
And in another cpp file, outside of the dll file:
#include "x.h"
x::myFunc()
{
//.....
}
The dll is only getting the bodies of the functions, so when I compile, I get lots of unresolved external symbols (I'm quite sure that this is the issue, because I tested with another class fully built in a .h file, in another project, and no errors). So how can I solve this mystery?
It is normal for the import headers to only have function signatures; the actual function bodies are already compiled into the DLL binary and are resolved at link time by linking into the actual DLL.
The first thing to try is to make sure you are actually linking to the said DLL. It isn't enough to just include the header, you also need to link to the binary. So in your project configuration, you need to add a link to (for example) the .lib file that gets created along-side the DLL when the DLL is compiled (if in MSVC). This lib file lets the linker know how to connect the function signatures you included via the import header to the actual implementations contained in the DLL. If you're on a different platform, the mechanics might be a little different, but the concepts will be similar.
Edits:
The next step is to make sure the binary is actually exporting the symbols you're trying to link against. Make sure that all interface signatures are being exported via __declspec(dll_export) prefixes. Normally this is wrapped up in an IFDEF so that the header is declared export while the DLL is being compiled, but not when that header is included in a client project. Next, you could use dumpbin to check the mangled export names, and see if there is anything unexpected.
Here's a modified version of your example that illustrates this style of export (note, I haven't tested if this compiles, apologies for any typos):
#ifdef BUILDING_MYDLL
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class MYDLL_API x
{
void myFunc();
}
You would then set your configuration to define BUILDING_MYDLL when compiling the dll, but not when compiling the executable. This way the functions are only marked export when compiling the library dll. Now you can mark your public API functions with MYDLL_API and they should get exported during build.
Please note that dll_export, dll_import, and declspec are all very MSVC-specific constructs. Other compilers/runtimes handle symbol export in different ways.
There's multiple ways to link DLL into your app on Windows, check out this existing question/answer:
https://stackoverflow.com/a/2060508/1701823

What is dllspec(dllimport) and dllspec(dllexport) means

After googling, i came to know that Dllimport makes the function available for other modules,
is it mandatory to declare function with extern "c" identifier?
Also, Dllexport means, Dll itself uses the function while compiling it says. so by default all
functions present in DLL are dllexport?
__declspec(dllexport) exports a symbol. It makes it available from outside a DLL.
__declspec(dllimport) imports a symbol. It practically says "this symbol is not defined in this application, it needs to be imported from a DLL file".
You don't have to declare it with extern "C". If you don't use extern "C", then the symbol will be exported as a C++ symbol, and you will only be able to call it from C++ (and languages that support calling C++ DLLs). If you use extern "C", then the symbol will be exported as a C symbol, and you will be able to call it from languages that support caling C DLLs.
If you want to use your DLL in C#, you will need to use extern "C".
Here is an excellent tutorial that shows you how to use a C++ DLL in C#: How to marshal a C++ class. I have used solution A in many projects at work.
Also, here is a short tutorial on how you can use a C++ DLL in another C++ application: How to create and use DLL in C++.
No -- dllexport means you're exporting it from the DLL (or from an executable) so that other modules (DLLs or executables) can use that function.
dllimport is used to declare a function that's implemented in a DLL (or, again, executable).
So, in a typical case, you'll have something like:
#ifdef BUILDDLL
#define DLL declspec(dllexport)
#else
#define DLL declspec(dllimport)
#endif
Then each public function the DLL will be marked as DLL:
DLL int dosomething(int);
Then, when you're building the DLL, you'll define BUILDDLL, to have all those functions marked as dllexport. Otherwise, you'll include the same header in client code that needs to use the function(s). It won't define BUILDDLL, so they'll all be marked as dllimport instead, so when it comes to link time, it'll create a link to that DLL instead of trying to satisfy those functions from someplace like the standard library.
It also means that entries (in the form of static import and export tables) are created (by the linker) in the exe, dll..files, which document the dependencies between a provider and a consumer.

About inconsistent dll linkage

How can I remove this link warning? You can see code segment that causes this warning.
static AFX_EXTENSION_MODULE GuiCtrlsDLL = { NULL, NULL };
//bla bla
// Exported DLL initialization is run in context of running application
extern "C" void WINAPI InitGuiCtrlsDLL()
{
// create a new CDynLinkLibrary for this app
new CDynLinkLibrary(GuiCtrlsDLL);
// nothing more to do
}
warning C4273: 'InitGuiCtrlsDLL' : inconsistent dll linkage
I have also export and import definitions, like:
#ifdef _GUICTRLS
#define GUI_CTRLS_EXPORT __declspec(dllexport)
#else
#define GUI_CTRLS_EXPORT __declspec(dllimport)
#endif
The purpose of the preprocessor statements:
#ifdef _GUICTRLS
#define GUI_CTRLS_EXPORT __declspec(dllexport)
#else
#define GUI_CTRLS_EXPORT __declspec(dllimport)
#endif
is to make sure that the header file declares the class or function as __declspec(dllexport) in the .dll where it is defined, and as __declspec(dllimport) for any other .dll that might want to use it.
For this to work, _GUICTRLS must be defined when compiling the exporting .dll, and not defined for any other .dll. Generally you would expect _GUICTRLS to be defined in the project properties, under C/C++ -> Preprocessor -> Preprocessor Definitions.
The compiler error you are seeing usually happens because either _GUICTRLS is not defined for the project that is doing the export, or it is defined for multiple projects, usually resulting from cutting an pasting from one project to another. You will also see this if _GUICTRLS is defined in a header file that is included in multiple projects.
There are multiple possibilities:
1) static AFX_EXTENSION_MODULE GuiCtrlsDLL = { NULL, NULL };
You use AFX_EXTENSION_MODULE. This means that you are implementing an MFC extension DLL. For such extension dlls you have to define the preprocessor _AFXEXT. Set this in the C++ compiler settings of your Visual C++ project
see:
How To Use _declspec(dllexport) in an MFC Extension DLL: http://support.microsoft.com/kb/128199
AFX_EXTENSION_MODULE Structure: http://msdn.microsoft.com/en-us/library/sxfyk0zk.aspx
TN033: DLL Version of MFC: http://msdn.microsoft.com/en-us/library/hw85e4bb.aspx
2) It is likely that you have a duplicated definiton/declaration.
In addition to reading the warning message, pay attention to where it occurs if you have multiple projects as part of a workspace.
I wasted time looking for a problem in my DLL which was compiling and linking correctly. The workspace was also building the main application and my error was that I had inadvertently included a new (DLL) source file into the build file list of the application itself.
The main program requires the DLL header mynewdll.h to import things but does not require the source file mynewdll.cpp. (The code is brought in at run time with a DLL.) I have a habit of including header and code files into projects as a pair, and this is where I had gone wrong.
I would have detected the error much sooner if I had been alert and noticed that the DLL project linked with no errors and it was the main program that complained!
My DLL source code and project was error free and it was only the way I tried to build my executable that was faulty.
That warning is usually caused by a duplicate definition of a function with different use of dllimport. Are you sure you didn't do this?
[ CMake inconsistent dll linkage ]
I encountered the following issue + solution with the __declspec(dllexport) + __declspec(dllimport) :
# # #CMakeLists.txt
add_defintions(-DMYLIB=1)
# The above was the solution...
# (MYLIB is used in the standard ifdef + define MYLIB_EXPORT syntax)
# Below: seems to get overruled by other directory's headers:
set_source_files_properties( file1.h file2.h COMPILE_FLAGS "-DMYLIB=1")
This was annoying because a number of sources say to use the 'set source file properties' command to get better granularity but the doc is not clear on what happens to file1.h's declares when included from a different directory... better stick with add_definitions( -DMYLIB=1 ) for now!
To catch this problem: in your Foo.cpp file:
#include "export.h"
#if defined(MYLIB)
#if defined(OTHERLIB)
static_assert(0,"error, check your definitions!");
// OTHER depends on MY; can't have both of these flags being set!
#endif
#endif
struct OTHER_EXPORT foo
{
};
See that you are not defining the exported symbols in a different project. Also clean all the intermediate files by hand and recompile.
To elaborate the answer of damian with an example. I read it but didn't understand at first glance.
You have a shared library with a source file compiled in that contains the function. In a new project you use the library and in addition you compile also the source file to use the function (I forgot that it is already in the library). Within the library the functions label is exported, within the additional compiled source file the functions label is marked to be imported. That's the conflict.
In my case, error C4273 was caused by trying linking to .lib file from a DLL dynamic load tester app in Qt5 by msvc2017_64 toolchain. Removing the reference to .lib file by changing LIBS setting in .pro file have the problem solved.