I am working on a C++ (VS2017) project that uses a protobuf type I created.
However, this project requires a .dll of said protobuf type. The __declspec( dllexport ) in each class declaration are not there by default, and I read online that they can be added by generating the protobuf object with this command line:
--cpp_out=dllexport_decl=MY_EXPORT_MACRO:output/directory
No one has explained what MY_EXPORT_MACRO is or how to define it. When I first generated my protobuf objects I used the most basic line and it worked:
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/my_file.proto
What and where is MY_EXPORT_MACRO and/or is there another way to make my protobuf files .dll compatible?
You know about __declspec( dllimport ) also, correct? What's the easiest way to use the same type definition while building the DLL (with dllexport annotations) and in DLL clients (with dllimport annotations)?
Having a macro to switch the annotation is an extremely common practice in Win32 DLL development of all sorts, not just for protobuf DLLs.
Usually the definition runs like this:
#if BUILD_DLLX
# define DLLX_API __declspec(dllexport)
#else
# pragma comment('lib', 'dllx.lib')
# define DLLX_API __declspec(dllimport)
#endif
And then you would use --cpp_out=dllexport_decl=DLLX_API:$DST_DIR so that the generated header files have DLLX_API inserted in the right places. Then build the DLL with /DBUILD_DLLX so it exports the types and functions.
Consumers of the DLL can #include the exact same header file, and with no /DBUILD_DLLX in their project configuration, they'll end up with imports.
Related
I’m currently having some problems trying to implement an integration with a Verifone PoS.
The bank we are working with provided us with one .dll file, one .h file and one .hpp file.
I’m usually a Java or PHP developer, so for the last days I consumed everything I found on the web about DLL files and how to use them, but none seemed to work so far. I got a lot of errors, many of them being something like “invalid dll”.
I found on the web that alongside a dll file there should have been a .lib file. I asked the third party about this, but apparently
There is no .lib file. The .dll file contains all the required info for an integration
From their documentation of library I found this:
The form of the supplied binary is a dynamic library. By its nature, a dynamic library allows for easier updates and corrections, not requiring recompilation or relinking of the client (calling) code, as long as the procedures prototypes (function parameters and return types) remain the same.
The language used for the library implementation is C++.
To access the functionalities implemented in the library binary, a C-style header interface is provided. This is comprised of the function prototypes available to be called as well as the types of the result-structures through which the returned data needs to be interpreted to make sense for the previously accessed functionality (the specific requested transaction).
So yeah, the .h file includes only the data types, and the .hpp file contains some declarations that looks like this:
extern "C" __declspec(dllexport) bool doSomething(int param);
Also in their documentation there is an example of how an implemetation should look (and it is fairly simple):
bool someVar = doSomething(1);
It looks like those functions can be called as simple as that, but they cannot. If I try to do that I get an “undefined function” (or similar) error.
At this point the only thing that seemed to have somehow worked (maybe) is loading the DLL with the LoadLibrary function. But besides the fact that whatever function I try to call, with whatever parameters, it returns false, it seems kind of wrong that I do not use the .hpp file at all.
So here we are. How I should aproach this? Is there a way to load the DLL and use the provided HPP file as function definitions? If not, is there another way beside LoadLibrary + GetProcAddress combo to do this?
Thank you!
I'm assuming the dll is a native dll, not a managed assembly (.net dll).
Usually, the dll author adds a preprocessor definition to the build system, like DLL_EXPORT. So if the author compiles the dll, the import library (a small .lib file) will contain all functions that used the DLL_API macro. Then the author can ship the very same header to a user. Because that user won't have the DLL_EXPORT macro defined, DLL_API will resolve to a dllimport, which basically says that the annotated function is defined in the import library.
Such a header might look like this (the whole #if condition is usually in its own header file which is then included in all headers that export functions):
#ifdef DLL_EXPORT
# define DLL_API __declspec(dllexport)
#else
# define DLL_API __declspec(dllimport)
#endif
extern "C"
{
void DLL_API SomeFunction(int x);
void DLL_API AnotherFunction(int x);
}
If the author builds the project (in msvc) the compiler will generate the dll file and a small .lib file, which is the import library. This lib will essentially do what you have to do now: calling LoadLibrary and GetProcAddress to resolve all the functions that have been annotated with __declspec(dllexport).
The following part is a bit speculative and I'm guessing a bit here.
All __declspec(dllimport) does, is tell consumers that this dll contains those functions. But the linker has to link a declaration to its definition (implementation) so the function must be defined somewhere at compiletime. And that place is the import library (.lib). If you don't link with the import library, you will get a linker error when you build your project.
This means simply changing the dllexport to a dllimport won't solve your problems. Without an import library your only option is to load the dll manually with LoadLibrary and search for each function.
If I were you, I'd ask the author for an example project that uses the dll. AFAIK, the only ways to use a native dll is either by linking to an import library or by loading everything manually.
Manually generating the import library from the dll
I've tested this to make sure it works.
First of all, fix the header file to either use the macros like I did in the example above, or just use dllimport directly.
Second, open the developer command prompt for VS and follow the steps from this answer. Make sure to use the correct file names and target architecture (x64 or x86). Now you should have a .lib file.
Thrid, add the lib to your project.
Add the directory of the lib (place it somewhere close to the project so you can use relative paths). Open the project properties and follow the steps in this image:
Make sure that Configuration and Platform are correct (you probably want it like in the image). You can also use relative paths. Click on the Macros button to see all predefined paths available to you.
Add the lib to the linker dependencies:
Put the header somewhere in your project where you can access it.
Now you can simply include the header anywhere in your project and use the functions declared inside it. But note that the dll file has to be placed somewhere where LoadLibrary can find it. Preferably this is the same directory where your project's executable is located.
Bonus facts
The definition file (.def) is actually very simple. The def file for my sample code above is:
LIBRARY MyLibrary
EXPORTS
AnotherFunction
SomeFunction
If I remove the extern "C" block around my declarations, my function names will be mangled and the def file looks like this:
LIBRARY MyLibrary
EXPORTS
?AnotherFunction##YAXH#Z
?SomeFunction##YAXH#Z
If you put those functions inside a namespace (for example FooSpace), that namespace name will also be part of the function name:
LIBRARY MyLibrary
EXPORTS
?AnotherFunction#FooSpace##YAXH#Z
?SomeFunction#FooSpace##YAXH#Z
Note that all extern "C" entities will ignore namespaces, meaning all extern "C" functions, variables, types, ... will be put into the global namespace, no matter if you define them inside a namespace or not.
These are also the names that you'd have to pass to GetProcAddress if you did it manually.
Im in the process of converting a visual studio c++ framework over into a linux build, and in the process of eliminating windows dependencies I ran into a whole bunch of __declspec(dllimport) calls in some header files. These header files define a bunch of functions and classes that are used in the source files, so theyre needed for the build.
Heres the exact lines that use the __declspec() call.
#ifndef UeiDaqAPI
#define UeiDaqAPI __declspec(dllimport)
#endif
UeiDaqAPI is the collection of classes and functions that all the source files use. The declspec call, from what I understand, links the functions/classes defined in the current .h file to the dynamic library "UeiDaqAPI"
__declspec(dllimport) is not supported by linux, so ive tried a "workaround" using dlopen(). For some more background information, about 40 header files use the above __declspec() call, so testing any workaround is very tedious. I was given a dynamic library for linux, in the .so format that I'm supposed to use.
I found an example of using dlopen(path-to-library) that should allow me to get around the __declspec() call but I am unsure how to get it working correctly. So far I have tried following the example, and changed all 40 or so header files and replaced the __declspec() call with the following:
#ifndef UeiDaqAPI
string nameOfLibToLoad("path/to/lib/lib.so");
UeiDaqAPI = dlopen(nameOfLibToLoad.c_str(), RTLD_LAZY);
if (!lib_handle) {
cerr << "Cannot load library: " << dlerror() << endl;
}
#endif
This however, I get errors stating that function calls that ARE defined in the header files were not defined, I suspect this is because they dont get added to the .so library, but Im not sure.
Id like some help either with implementing the above workaround, or, if there is a better way to get around the __declspec() call, then id like some pointers on where to start.
You shouldn't need to use dlopen, that is for dynamic loading (LoadLibrary/dlopen, GetProcAddress/dlsym, FreeLibrary/dlclose).
Instead as with Windows in the basic case it should be automatic, but the syntax is a little different.
Windows/MSVC generally only exports things from DLL's that it was specifically told to by __declspec(dllexport) and then when using the DLL only tries to link things explicitly told to by __declspec(dllimport).
GCC/Linux however by default (you can opt-in to an explicit export style) just exports everything in a .so, and when linking considers any object or library, so just declaring the function is enough, like for a static library or multiple C/C++ files.
void my_uei_daq_api_function(int a, int b);
Often in portable libraries there might be something along the lines of:
#if defined(_WIN32) && defined(MYLIB_DLL)
# ifdef MYLIB_BUILD
// Compiling a Windows DLL
# define MYLIB_EXPORT __declspec(dllexport)
# else
// Using a Windows DLL
# define MYLIB_EXPORT __declspec(dllimport)
# endif
// Windows or Linux static library, or Linux so
#else
# define MYLIB_EXPORT
#endif
Which is then used in the libraries headers:
MYLIB_EXPORT void my_uei_daq_api_function(int a, int b);
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
{
...
};
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 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.