I've got a DLL that I've created as a C++ Win32 application. To prevent name mangling in my DLL, I have used the EXPORT definition defined below:
#ifndef EXPORT
#define EXPORT extern "C" __declspec(dllexport)
#endif
EXPORT int _stdcall SteadyFor(double Par[], double Inlet[], double Outlet[]);
To get this code to compile, I had to go into the project's Properties and set the C/C++ Calling Convention to __stdcall (/Gz) and set Compile As to Compile as C++ Code (/TP).
This worked in Debug mode, but Release mode is throwing error C2059: syntax error: 'string' on all of my EXPORT functions - even though I have configured the Release mode settings to be the same as the Debug settings.
How do I get Release Mode to compile?
Regards,
~Joe
(Developing under Visual Studio 2008 Professional)
EDIT:
A lot of comments about my #define, which does not appear to be causing any problems.
To eliminate the confusion, my header file has been rewritten as follows:
#ifndef coilmodel_h
#define coilmodel_h
extern "C" __declspec(dllexport) int _stdcall steadyFor(double Par[], double Inlet[], double Outlet[], char* FileIn, char* FileOut);
#endif
That is all of it.
The error is:
Description error C2059: syntax error: 'string'
File coilmodel.h
Line 4
Again, this error only appears in Release mode, not Debug mode.
Project is a C++ Win32 DLL application.
If your source file has a .c extension, the compiler you are using will compile it as C (not C++) and produce that error on the extern "C". If that is the case, then you need to use the /TP switch as you already noted or rename the file to .cpp. The other solution is to put #ifdefs around the extern:
#ifdef __cplusplus
extern "C"
#endif
I would guess EXPORT is defined as something else in Release builds. Since you've got an #ifndef around your definition, that won't do anything if it is already defined, then you get something else (maybe a string?) pasted at the beginning of your function declarations.
So maybe try something like this:
#ifdef EXPORT
#error EXPORT already defined!
#else
#define EXPORT extern "C" __declspec(dllexport)
#endif
Forcing Compile As to Compile as C++ Code (/TP) - did you set this on all build configurations - debug/release x 32/x64 etc. I avoid using this option, much easier to name the file appropriately for the compiler to choose automatically.
You only need the "C" part of extern "C" if the file is C++ to turn off the name mangling.
I prefer to arrange the shared public header using this format, so you can include in C/C++ internally or externally.
#ifdef __cplusplus
# define NOMANGLE extern "C"
#else
# define NOMANGLE
#endif
#ifdef EXPORT_BUILD
# define EXPORT NOMANGLE __declspec(dllexport)
#else
# define EXPORT NOMANGLE __declspec(dllimport)
#endif
Unprobable, but make sure dllexport or _stdcall is not #defined...
Related
I am trying to understand some code that I have inherited, but am having some trouble googling my way out of it, and have some questions I hope some of you can help me with. The code can be seen just below, and is a .hpp (c++ header file) which declares a function.
#ifdef _MSC_VER
#define EXPORT_SYMBOL __declspec(dllexport)
#else
#define EXPORT_SYMBOL
#endif
#ifdef __cplusplus
extern "C" {
#endif
EXPORT_SYMBOL float func(int int_param, float float_param);
#ifdef __cplusplus
}
#endif
My first point of confusion is
#ifdef _MSC_VER
#define EXPORT_SYMBOL __declspec(dllexport)
#else
#define EXPORT_SYMBOL
#endif
I understand this as "if we are compiling from a windows machine, do something special".
What does __declspec(dllexport) do exactly?
Why do I need EXPORT_SYMBOL at all?
Secondly I am confused about the necessity of wrapping the header in the extern "C" statement. As far as I can tell the header is checking to see if __cplusplus is defined, that is, if we are compiling with g++. The extern block is here to make sure I don't have issues with the g++ compiler if func() was found in say, a file called func.c instead of a .cpp file, and then compiled with gcc. I understand mangling, and how g++ changes function names to enable overloading.
As i have it contained in a .cpp file and hence intend to exclusively compile it with g++, do I need the extern "C" block, and #ifdef statements? Is there a case where this is crucial?
What does __declspec(dllexport) do exactly?
When DLL is created, it does not export any symbols by default (unlike static library). In Visual C++, __declspec(dllexport) is the easiest way to export symbols. There are other ways to export.
As i have it contained in a .cpp file and hence intend to exclusively
compile it with g++, do I need the extern "C" block, and #ifdef
statements? Is there a case where this is crucial?
This allows using the function if you load the DLL from a C program, from a C++ program built by any compiler, or even from other languages with C bindings. If you work exclusively with C++ and g++ compiler, there is still a case when this is important: loading the DLL dynamically - in which case you need to supply your function name as a string (mangled unless you use extern "C").
#if COMPILING_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
How / where do I define COMPILING_DLL ?
Seen here:
what does __declspec(dllimport) really mean?
Sounds like I can't use load-time dynamic linking at all if I can't use the same header?
One another option:
Use the default defined macro local to the project.
You can see the default defined macros local to the project in the below location:
Properties -> C/C++ -> Preprocessor -> Preprocessor Definition.
Example:
Suppose your Project Name is: MyDLL
Default Macro Local to that project: MYDLL_EXPORTS
#ifdef MYDLL_EXPORTS
/*Enabled as "export" while compiling the dll project*/
#define DLLEXPORT __declspec(dllexport)
#else
/*Enabled as "import" in the Client side for using already created dll file*/
#define DLLEXPORT __declspec(dllimport)
#endif
Best place to define COMPILING_DLL=1 is command line of compiler. If you use Visual Studio IDE then it is in Project properties ... C/C++ ... Preprocessor ... Preprocessor Definitions.
__declspec(dllimport) is Microsoft specific extension to C++. Microsoft has excellent online documentation.
In the DLL project, you add a #define (either in a header file or in the project properties) for COMPILING_DLL. As this will not be set for any other project (especially if you name it something better than COMPILING_DLL) then the #if directive will work properly.
You (actually Visual Studio in ideal cases) defines the COMPILING_DLL as an argument to the compiler when you build the DLL. So, it will default to __declspec(dllexport). On the other end, when you USE the DLL's header file, you don't define this, so DLLEXPORT will be evaluated by default to __declspec(dllimport).
If you use CMake to generate your build configuration, you should be able to use
the macro <projectname>_EXPORTS the way you want to use COMPILING_DLL, where projectname was defined with the CMake command project(projectname):
A preprocessor macro, <target_name>_EXPORTS is defined when a shared library compilation is detected.
source
I tested and it works on Windows using the Ninja generator with compiler MSVC from Visual Studio 2015 Express.
Related: CMake adds -Dlibname_EXPORTS compile definition
You can't define function body that way in the header file. It is prohibited by __declspec(dllimport). This specifier can only be specified on function declaration, not definition.
You have to move the function body to a source file.
in header file:
extern DLLEXPORT void test2();
In .cpp file:
void test2()
{
// ...
}
As folks said, don't forget to add COMPILING_DLL to the project preprocessor definitions.
Actually, the real problem is the preprocessor directive.
You should use #ifdef and not #if to test if the variable is really defined (and we don't care about the defined value or if there is any).
NOTE: I know this thread is 1-year old but it still may be useful for somebody who have this problem in the future.
I am creating a c++ dll to be imported in vb.net.
I have found that the best way to organize the imports and exports in the header file of the dll, is something of the following type:
#ifndef MY_DLL_EXPORTS
#define MY_DLL_EXPORT __declspec(dllexport)
#else
#define MY_DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
MY_DLL_EXPORT BOOL my_function(uint32_t x);
#ifdef __cplusplus
}
#endif
My question is, where are the __cplusplus and MY_DLL_EXPORTS supposed to be defined ?
I have not done this before and I can't seem to find a place in the code for it. I read something about putting these definitions in the
Project Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions
Do I put them in the DLL's project properties ? and if i do, on using this DLL, will they always be defined so the if statement will always go to the dllimport ?
Also, is __cplusplus already defined or must I define it ?
__cplusplus is defined for you by a C++ compiler, but NOT by a C compiler. This is how you can determine if your code is being compiled by a C or C++ compiler. That's why this is used to guard the extern "C" construct. A C compiler would just omit it (since it emits C linkage already).
The other constants can be either defined on the compiler's command line (eg. in the menu you listed), or in the code somewhere:
#define MY_DLL_EXPORTS
Best place to define COMPILING_DLL is command line of compiler. If you use Visual Studio IDE then it is in Project properties ... C/C++ ... Preprocessor ... Preprocessor Definitions.
__declspec(dllimport) is Microsoft specific extension to C++. Microsoft has excellent online documentation.
#if COMPILING_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
How / where do I define COMPILING_DLL ?
Seen here:
what does __declspec(dllimport) really mean?
Sounds like I can't use load-time dynamic linking at all if I can't use the same header?
One another option:
Use the default defined macro local to the project.
You can see the default defined macros local to the project in the below location:
Properties -> C/C++ -> Preprocessor -> Preprocessor Definition.
Example:
Suppose your Project Name is: MyDLL
Default Macro Local to that project: MYDLL_EXPORTS
#ifdef MYDLL_EXPORTS
/*Enabled as "export" while compiling the dll project*/
#define DLLEXPORT __declspec(dllexport)
#else
/*Enabled as "import" in the Client side for using already created dll file*/
#define DLLEXPORT __declspec(dllimport)
#endif
Best place to define COMPILING_DLL=1 is command line of compiler. If you use Visual Studio IDE then it is in Project properties ... C/C++ ... Preprocessor ... Preprocessor Definitions.
__declspec(dllimport) is Microsoft specific extension to C++. Microsoft has excellent online documentation.
In the DLL project, you add a #define (either in a header file or in the project properties) for COMPILING_DLL. As this will not be set for any other project (especially if you name it something better than COMPILING_DLL) then the #if directive will work properly.
You (actually Visual Studio in ideal cases) defines the COMPILING_DLL as an argument to the compiler when you build the DLL. So, it will default to __declspec(dllexport). On the other end, when you USE the DLL's header file, you don't define this, so DLLEXPORT will be evaluated by default to __declspec(dllimport).
If you use CMake to generate your build configuration, you should be able to use
the macro <projectname>_EXPORTS the way you want to use COMPILING_DLL, where projectname was defined with the CMake command project(projectname):
A preprocessor macro, <target_name>_EXPORTS is defined when a shared library compilation is detected.
source
I tested and it works on Windows using the Ninja generator with compiler MSVC from Visual Studio 2015 Express.
Related: CMake adds -Dlibname_EXPORTS compile definition
You can't define function body that way in the header file. It is prohibited by __declspec(dllimport). This specifier can only be specified on function declaration, not definition.
You have to move the function body to a source file.
in header file:
extern DLLEXPORT void test2();
In .cpp file:
void test2()
{
// ...
}
As folks said, don't forget to add COMPILING_DLL to the project preprocessor definitions.
Actually, the real problem is the preprocessor directive.
You should use #ifdef and not #if to test if the variable is really defined (and we don't care about the defined value or if there is any).
NOTE: I know this thread is 1-year old but it still may be useful for somebody who have this problem in the future.
I'm stuck on a fix to a legacy Visual C++ 6 app. In the C++ DLL source I have put
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
which results in MyNewVariable showing up (nicely undecorated) in the export table (as shown by dumpbin /exports blah.dll). However, I can't figure out how to declare the variable so that I can access it in a C source file. I have tried various things, including
_declspec(dllimport) char* MyNewVariable;
but that just gives me a linker error:
unresolved external symbol "__declspec(dllimport) char * MyNewVariable" (__imp_?MyNewVariable##3PADA)
extern "C" _declspec(dllimport) char* MyNewVariable;
as suggested by Tony (and as I tried before) results in a different expected decoration, but still hasn't removed it:
unresolved external symbol __imp__MyNewVariable
How do I write the declaration so that the C++ DLL variable is accessible from the C app?
The Answer
As identified by botismarius and others (many thanks to all), I needed to link with the DLL's .lib. To prevent the name being mangled I needed to declare it (in the C source) with no decorators, which means I needed to use the .lib file.
you must link against the lib generated after compiling the DLL. In the linker options of the project, you must add the .lib file. And yes, you should also declare the variable as:
extern "C" { declspec(dllimport) char MyNewVariable; }
extern "C" is how you remove decoration - it should work to use:
extern "C" declspec(dllimport) char MyNewVariable;
or if you want a header that can be used by C++ or C (with /TC switch)
#ifdef __cplusplus
extern "C" {
#endif
declspec(dllimport) char MyNewVariable;
#ifdef __cplusplus
}
#endif
And of course, link with the import library generated by the dll doing the export.
I'm not sure who downmodded botismarius, because he's right. The reason is the .lib generated is the import library that makes it easy to simply declare the external variable/function with __declspec(dllimport) and just use it. The import library simply automates the necessary LoadLibrary() and GetProcAddress() calls. Without it, you need to call these manually.
They're both right. The fact that the error message describes __imp_?MyNewVariable##3PADA means that it's looking for the decorated name, so the extern "C" is necessary. However, linking with the import library is also necessary or you'll just get a different link error.
#Graeme: You're right on that, too. I think the "C" compiler that the OP is using is not enforcing C99 standard, but compiling as C++, thus mangling the names. A true C compiler wouldn't understand the "C" part of the extern "C" keyword.
In the dll source code you should have this implementation so that the .lib file exports the symbol:
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
The c client should use a header with this declaration so that the client code will import the symbol:
extern "C" _declspec(dllimport) char* MyNewVariable;
This header will cause a compile error if #include-ed in the dll source code, so it is usually put in an export header that is used only for exported functions and only by clients.
If you need to, you can also create a "universal" header that can be included anywhere that looks like this:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef dll_source_file
#define EXPORTED declspec(dllexport)
#else
#define EXPORTED declspec(dllimport)
#endif dll_source_file
#ifdef __cplusplus
}
#endif
EXPORTED char* MyNewVariable;
Then the dll source code looks like this:
#define dll_source_code
#include "universal_header.h"
EXPORTED char* MyNewVariable = 0;
And the client looks like this:
#include "universal_header.h"
...
MyNewVariable = "Hello, world";
If you do this a lot, the monster #ifdef at the top can go in export_magic.h and universal_header.h becomes:
#include "export_magic.h"
EXPORTED char *MyNewVariable;
I've never used _declspec(dllimport) when I was programming in Windows. You should be able to simply declare
extern "C" char* MyNewVariable;
and link to the .libb created when DLL was compiled.