Exporting extern variables from dll visual C++ - c++

Basically I have a dll project in visual studio. I'm linking this dll project to a second project successfully but as soon as I try to use extern variables things go wrong. I've seperated my extern variables into a single header and source file from everything else so I can isolate the problem and potential solutions. I've scowered the internet for hours now and I feel like I've tried everything. I am beginning to think it might be a compile flag? Anyway, heres my code.
macros.h
#pragma once
// dll management
#ifdef TOAST_EXPORT
#ifdef _MSC_VER
#define TAPI __declspec(dllexport)
#else
#define TAPI __attribute__((visibility("default")))
#endif
#else
#ifdef _MSC_VER
#define TAPI __declspec(dllimport)
#else
#define TAPI
#endif
#endif
globals.h
#pragma once
#define TOAST_EXPORT
#include "macros.h"
namespace toast
{
TAPI extern const char c;
}
globals.c
Note that I tried this without const and made no assignment here
#pragma once
#include "globals.h"
namespace toast
{
const char c = 'a';
}
main.c (from the project that compiles to an exe)
#include <globals.h>
int main()
{
char c = toast::c;
return 0;
}
So far I've tried making a lot of subtle changes like reordering extern and const and such. I've also done it both with just extern and just const. Still produces the same unresolved external symbol "char const toast::c" error. Keep in mind that I can create instances of classes and call their methods from the dll successfully and thats with things like class TAPI logger... and such.

Related

Global initialized variable in a DLL

Is it possible to use a global variable from one DLL module to initialize global variable in other DLL module? If so, how?
I am using Microsoft Visual Studio 17.3.6 and use a C++/CLI wrapper class with some C files. I am in a bigger project but I have put together a smaller example that exhibits the behavior.
I would have thought that it would work like this. There are four files, file1.c, file1.h in one project and file2.c and file2.h in second project. They are built to two DLLs, file1.dll and file2.dll. First project has file1_EXPORTS preprocessor symbol defined and second has file2_EXPORTS defined. Include guards omitted for clarity.
file1.c:
#include <file1.h>
#include <file2.h>
structure1_t struct1 = {
&struct2
};
file1.h:
typedef struct
{
structure2_t* ptr;
} structure1_t;
#ifdef file1_EXPORTS
#define EXPORT_SYMBOL __declspec(dllexport)
#else
#define EXPORT_SYMBOL __declspec(dllimport)
#endif
EXPORT_SYMBOL structure1_t struct1;
file2.h:
typedef struct
{
int* i;
} structure2_t;
#if defined (file2_EXPORTS)
#define EXPORT_SYMBOL __declspec(dllexport)
#else
#define EXPORT_SYMBOL __declspec(dllimport)
#endif
EXPORT_SYMBOL structure2_t struct2;
file2.c:
#include <file2.h>
#include <file1.h>
int i;
structure2_t struct2 = {
&i
};
However, it cannot be compiled like this. There is an error C2099: initializer is not a constant. When I change the line (in file2.h) #define EXPORT_SYMBOL __declspec(dllimport) to #define EXPORT_SYMBOL extern, there are linker errors LNK2001: unresolved external symbol struct2 and LNK1120: 1 unresolved externals. Only combination that works for me is leaving the definition empty, e.g. #define EXPORT_SYMBOL. Other change that I must do is leave the definition in file1.h or the program fails in the next step.
Now those are built correctly and libraries file1.dll and file2.dll are created.
Assume that there is a third file file3.cpp which uses the DLLs:
#include <file1.h>
#include <file2.h>
#include <iostream>
int main(void)
{
std::cout << struct1.ptr << std::endl;
std::cout << struct2.i << std::endl;
return 0;
}
it prints:
0000000000000000
0000000000000000
So, my question is, is there some way this could work without the NULL pointers (e.g. struct1 has pointer to struct2 and struct2 has pointer to the integer)? Why is the program behaving like this, is it because file3.cpp sees only the declarations in the header and the variables are never initialized correctly? Other variant and solution would perhaps be to have an initialization function that puts the needed values to the structures. However, I am hesitant to doing this as I have a lot of structures that I would have to manually fill in. Or perhaps it could be filled in the DllMain as per here. Furthermore, I should mention that the C files have the extern "C" blocks in them.
I tried different combinations of __declspec(dllimport), __declspec(dllexport) and extern keywords but I cannot manage to make it work correctly. Also, putting EXPORT_SYMBOL to the C files as per Exporting global variables from DLL did not help either.
This answer would suggest that what I want to do is not possible but I do not know if it is relevant only to const variables or not.
What I was trying to do is not possible. Address of dllimported symbol cannot be used in an initializer of static data. I solved it by including the .c files with the structures' definition in each module that needed them. Structures themselves may stay extern when it is implemented this way. So with regards to my code examples, it would look like this:
file1.c:
#include <file1.h>
#include <file2.h>
#include <file2.c>
structure1_t struct1 = {
&struct2
};
file1.h:
typedef struct
{
structure2_t* ptr;
} structure1_t;
extern structure1_t struct1;
file2.h:
typedef struct
{
int* i;
} structure2_t;
extern structure2_t struct2;
file2.c:
#include <file2.h>
int i;
structure2_t struct2 = {
&i
};
(for illustration, have not tested it). This way, effectively no data are shared across DLLs as each one has its own copy. If data had to stay in the separate DLLs or if including the .c files was not possible, other solution would be not to have an initializer at all, use __declspec() instead of extern and initialize structures in a function call. However, I chose not to do that as I have hundreds of structures and it would not be feasible this way.

C++ Visual Studio Windows: how to declare but not define extern function in dll

I have a project that is compiled into a library and declares a certain function to be implemented by the user of the library:
//To be defined by user
Application* CreateApplication();
When compiling the code into a shared library on Linux this works perfectly. Any user of the library can define an implementation for the declared function and it can be used inside the library. If the user of the library forgets to define an implementation, they will get an error pointing this out.
I'm now in the process of porting the library to Windows, where it is supposed to be compiled into a dll. However, I'm running into problems as the linker used by Visual Studio is complaining:
unresolved external symbol Application* __cdecl CreateApplication(void)
I tried adding the extern keyword to indicate that the definition of the function is somewhere else, but this didn't work.
Why can't I declare (but not define) a function in a dll like this? How should I fix my code so it works both on Linux and on Windows?
What you are attempting to do only works in a static library, it cannot work in a dynamic library like a DLL. For that, you will have to change the code to use a function pointer instead. The application that is using the DLL can pass in the address of the desired function from its own code, and the DLL can then assign that address to a variable that it uses as needed, eg:
HEADER:
#ifndef MYLIB_H
#ifndef MYLIB_H
#ifdef COMPILING_MY_LIB
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT __declspec(dllimport)
#endif
// declare Application as needed...
typedef Application (*lpCreateApplicationFunc)();
#ifdef __cplusplus
extern "C" {
#endif
MY_EXPORT void SetCreateApplicationFunc(lpCreateApplicationFunc func);
#ifdef __cplusplus
}
#endif
#endif
DLL:
#define COMPILING_MY_LIB
#include "MyLib.h"
//To be defined by user
lpCreateApplicationFunc CreateApplication = NULL;
void SetCreateApplicationFunc(lpCreateApplicationFunc func)
{
CreateApplication = func;
}
void doSomething()
{
Application *app = NULL;
if (CreateApplication)
app = (*CreateApplication)();
if (app)
{
...
}
}
EXE:
#include "MyLib.h"
Application MyCreateApplicationFunc()
{
...
}
// during startup, call this...
SetCreateApplicationFunc(&MyCreateApplicationFunc);

How to properly create a DLL from C code and use it in a C++ project

I have a set of functions written in C that I need to be able to call from another project written in C++. The C code is essentially some functions that do some calculations on a large data set. I didn't write them - all I want to do is allow my C++ project to be able to call those functions. My solution was to create a DLL for the C code and link it to my C++ project.
In order to make the DLL, I structured myCproj.h (the header in the C project, not C++ project) like so:
#ifdef __cplusplus
extern "C" {
#endif
struct __declspec(dllexport) neededStruct {
int a;
//I need to be able to initialize this struct in my C++ project.
}
__declspec(dllexport) void neededFunc( struct neededStruct *input ) {}
//I need to be able to call this function from my C++ project and feed
//it my local instance of neededStruct.
#ifdef __cplusplus
}
#endif
The src file, myCproj.c, was not changed at all. The function definitions do not have __declspec(dllexport)in front of them, nor is extern "C" inserted anywhere. The code compiles without error and produces myCproj.dll and myCproj.lib.
I then tell my C++ project in VS where to find myCproj.lib and myCproj.h accordingly and copy the DLL over to the directory where my C++ executable lives. To use the DLL, I gave myCPPproj.cpp the following addition:
#define DLLImport __declspec(dllimport)
struct DLLImport neededStruct input;
input.a = 0;
extern "C" DLLImport void neededFunc( &input );
However, I get error EO335 'linkage specification is not allowed' on that last line. What am I doing wrong?
It is preferable to use the same header for both the library and using code.
As mentioned, it is usually done by a conditional define, like the following:
MyLibrary.h:
#if defined(MYLIBRARY_API)
#define MYLIBRARY_EXPORTS __declspec(dllexport)
#else
#define MYLIBRARY_EXPORTS __declspec(dllimport)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
MYLIBRARY_API bool MyLibFunc();
#if defined(__cplusplus)
#endif
MyLibrary.c:
#include "MyLibrary.h"
void MyLibFunc()
{
....
}
App.cpp:
#include <MyLibrary.h>
int main()
{
MyLibFunc();
}
The symbol MYLIBRARY_API will be defined for the library project (usually as a /D on the compiler command line). And if you use visual studio that is pretty much exactly what you get when creating a dll project with exports.

How to control #define directive in different projects ...?

My question is quite straight forward. I just intended to know that is the #define directive in C++ controllable over the different project files? Elaborately, I have a header file and a cpp file for one project. The codes of the files are as follows:
MyHeader.h
#ifndef __MY_HEADER_H__
#include <cstring>
using namespace std;
#ifdef _HEADER_EXPORT_
#define HEADER_API __declspec(dllexport)
#else
#define HEADER_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
class HEADER_API MyHeader
{
public:
MyHeader();
~MyHeader();
#ifdef _HEADER_DISPLAY_
void __cdecl ParseHeader();
#elif defined (_HEADER_RETURN_)
string __cdecl ParseHeader();
#endif
};
#ifdef __cplusplus
}
#endif
#define __MY_HEADER_H__
#endif
MyHeader.cpp
#ifndef __MY_HEADER_H__
#include "MyHeader.h"
#endif
MyHeader::MyHeader() { }
MyHeader::~MyHeader() { }
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _HEADER_DISPLAY_
HEADER_API void __cdecl MyHeader::ParseHeader()
{
fputs(string("Displaying...").c_str(), stdout);
}
#elif defined (_HEADER_RETURN_)
HEADER_API string __cdecl MyHeader::ParseHeader()
{
string retVal("Returning...");
return retVal;
}
#endif
#ifdef __cplusplus
}
#endif
In another project HeaderImpl.cpp file has been implemented with the following code.
HeaderImpl.cpp
#include "stdafx.h"
#define _HEADER_DISPLAY_ // To display the message
// #define _HEADER_RETURN_ // To return the message as string
#include "MyHeader.h"
int main(int argc, char* argv[])
{
MyHeader header;
MyHeader.ParseHeader(); // To display the message or to return the string
return 0;
}
Now, I wanted to know that how can I use the #define directive in my HeaderImpl.cpp file to control the ParseHeader method for MyHeader.cpp file? As it has been noted that MyHeader.h file doing exactly what I need for; i.e. controlling the ParseHeader method upon declaring the #define directive, accordingly.
You can't. Each C++ source file is compiled independently, and settings in one cannot affect another. You'll have to do this on project level.
One way to do that would be to set up different project (and solution) configurations for different values of this macro. Instead of just the usual Debug and Release, you could add Debug-Display, Debug-Return etc. You can then define the macros in the project settings for each configuration. This will make sure you link the correctly built version of your library.
As a side note, you're using illegal names in your code. A name which contains double underscores, or starts with an underscore followed by an uppercase letter, is reserved for the compiler & standard library. User code is not allowed to use such names for its own purposes.
You usually can provide #defines for all of your compilation units on the command line of the compiler. IIRC for Visual studio that would be something like /D_HEADER_DISPLAY_ or /D_HEADER_RETURN_
Your project must be using something like this already for the _HEADER_EXPORT_ define.
There is no way for a preprocessor definition in one translation unit to remotely affect a different translation unit.
Most, if not all, compilers accept them as parameters for the compilation, though (and the flag is usually -D, or /D for VC++).
In Visual Studio, you can set project-wide preprocessor definitions in the project settings, under
Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions

Why does linker fail when accessing static member in inline constructor

Just started doing some coding for a very simple automated test framework for internal use. (I know there are hundreds of them out there - really good ones too, but at the moment that's not interesting, so don't point me to any of those, please ;)) I then came across the following problem which I can't explain, thus asking for your help.
I have the following code as part of a DLL:
(The code is barely an embryo and took me <2 minutes to write, so it's logic, structure - nothing - is refined, in any way yet.)
h-file:
#pragma once
#ifdef __DLL__ // Defined in DLL-project
#define DLLEXPORT __declspec( dllexport )
#else
#define DLLEXPORT
#endif
class DLLEXPORT AutoTest
{
public:
enum eTestID {TESTID_SomeFunction};
AutoTest(eTestID id, LPVOID lpData)
{
if(sm_bTestsActive)
ExecTest(id, lpData);
}
void ActivateTests();
private:
static void ExecTest(eTestID id, LPVOID lpData)
{
}
static BOOL sm_bTestsActive;
};
cpp-file:
#include "StdAfx.h"
#include "AutoTest.hpp"
BOOL AutoTest::sm_bTestsActive = FALSE;
void AutoTest::ActivateTests()
{
sm_bTestsActive=TRUE;
}
This compiles just fine and the DLL gets generated.
Here's my problem though - when instantiating the class with:
AutoTest(AutoTest::TESTID_SomeFunction, &SomeData);
from the main application, the linker fails with
error LNK2001: unresolved external symbol "private: static int AutoTest::sm_bTestsActive" (?sm_bTestsActive#AutoTest##0HA)
<2 minutes to write - now going on 5 hours to understand why it fails!!! :O
Here's what interesting - if I move the constructor to the cpp-file (not inlined) it works just fine!?!?
Here's that code:
h-file:
#pragma once
#ifdef __DLL__ // Defined in DLL-project
#define DLLEXPORT __declspec( dllexport )
#else
#define DLLEXPORT
#endif
class DLLEXPORT AutoTest
{
public:
enum eTestID {FK3059};
AutoTest(eTestID id, LPVOID lpData);
void ActivateTests();
private:
static void ExecTest(eTestID id, LPVOID lpData)
{
}
static BOOL sm_bTestsActive;
};
cpp-file:
#include "StdAfx.h"
#include "AutoTest.hpp"
BOOL AutoTest::sm_bTestsActive = FALSE;
AutoTest::AutoTest(eTestID id, LPVOID lpData)
{
if(sm_bTestsActive)
ExecTest(id, lpData);
}
void AutoTest::ActivateTests()
{
sm_bTestsActive=TRUE;
}
(I've made some minor edits in the code after pasting, so there may or may not be simple syntax errors.)
Also, if I remove the reference to the static member from the inline versions constructor, it works fine.
Any ideas as to why the inline version won't work?
Pay attention to your definition of DLLEXPORT.
Make sure that it is properly expanded to __declspec(dllexport) when building the DLL, or __declspec(dllimport) when building the client.
I'd suggest using a macro with a more specific name than the generic DLLEXPORT (to avoid conflicts with other macros with the same name).
Having static data members accessed from inline member functions works fine for me (tested with VS2013).
Minimal repro:
Create a Visual Studio solution with an empty DLL project and an empty console application project.
Inside the DLL project add two files:
DllClass.h:
#pragma once
#ifndef TEST_DLL_CLASS
#define TEST_DLL_CLASS __declspec(dllimport)
#endif
class TEST_DLL_CLASS DllClass
{
public:
DllClass();
int GetMember() const
{
return m_data1;
}
static int GetStaticMember()
{
return sm_data2;
}
private:
int m_data1;
static int sm_data2;
};
DllClass.cpp:
#define TEST_DLL_CLASS __declspec(dllexport)
#include "DllClass.h"
int DllClass::sm_data2 = 2;
DllClass::DllClass()
: m_data1(1)
{
}
Inside the console app project, add one file:
Test.cpp:
#include "..\DllTestClass\DllClass.h"
#include <iostream>
using namespace std;
#pragma comment(lib, "DllTestClass")
int main()
{
DllClass dllClass;
cout << dllClass.GetMember() << endl;
cout << DllClass::GetStaticMember() << endl;
}
Make sure that when building the console test app, the linker can find the DLL .lib (DllTestClass.lib) file.
For that purpose, you can navigate the console app's project properties, going to:
Project Properties | Linker | Additional Library Directories
and add $(OutDir) to the additional library directories, making it:
$(OutDir);%(AdditionalLibraryDirectories)
Builds and works correctly for me.
Should be:
#ifdef __DLL__ // Defined in DLL-project
#define DLLEXPORT __declspec( dllexport )
#else
#define DLLEXPORT __declspec( dllimport )
#endif
You can declare C++ classes with the dllimport or dllexport attribute. These forms imply that the entire class is imported or exported. Classes exported this way are called exportable classes.
More information in the documentation.