VS2019: Linking Static Library Functions to DLL - c++

I have three projects in my visual studio solution: project A, project, B, and project C. Projects A and B compile to A.lib and B.lib, respectively, and project C compiles to C.dll. I'd like to take the functions in A.lib and B.lib and put them in C.dll - what can I do to make this happen? I have a feeling that I'm using __declspec(dllexport) at the wrong time, or that I'm forgetting to link something.
=== PROJECT A ===
foo.h
#include <iostream>
__declspec(dllexport) void foo();
foo.cpp
#include "foo.h"
void foo()
{
std::cout << "Foo!\n";
}
=== PROJECT B ===
goo.h
#include <iostream>
__declspec(dllexport) void goo();
goo.cpp
#include "goo.h"
void goo()
{
std::cout << "Goo!\n";
}
=== PROJECT C ===
// What goes here?

There is no need to use __declspec(dllexport) in static libraries.
foo.h can be modified as:
#include <iostream>
void foo();
Do not forget to add lib file in Dll's properties. For your reference: Create and use a static library and Create and use your own Dynamic Link Library (C++)
MyDLL:
Header.h
#pragma once
#include"foo.h"
#include"goo.h"
#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif
extern "C" MATHLIBRARY_API void Myfun();
Cpp file
#include"Header.h"
void Myfun()
{
foo();
goo();
}
The test project:
#include <iostream>
#include"Header.h"//from MyDll
int main()
{
Myfun();
}
In test project, I only input Mydll.lib. And I also include directories of foo.h and goo.h.
Output:
Foo!
Goo!

Related

Error LNK2028 when calling exported C function from C++ wrapper

I have C project from which I export function f() and call it from other C++ project and it works fine. However, when I call some other function g() inside f I get LNK2028 error.
The minimal example of Cproject looks like:
Test.h
#ifndef TEST_H
#define TEST_H
#include "myfunc.h"
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
EXTERN_DLL_EXPORT void f()
{
g(); // this will provide LNK2028 if f() is called from other project
}
#endif
myfunc.h
void g();
myfunc.c
#include "myfunc.h"
void g(){}
The project itself is being built. However, when I call this function from other C++/CLIproject
#include "Test.h"
public ref class CppWrapper
{
public:
CppWrapper(){ f(); } // call external function
};
I get error:
error LNK2028: unresolved token (0A00007C) "void __cdecl g(void)" (?g##$$FYAXXZ) referenced in function "extern "C" void __cdecl f(void)" (?f##$$J0YAXXZ) main.obj CppWrapper
error LNK2019: unresolved external symbol "void __cdecl g(void)" (?g##$$FYAXXZ) referenced in function "extern "C" void __cdecl f(void)" (?f##$$J0YAXXZ) main.obj CppWrapper
Additional details:
I set x64 platform for whole solution
In CppWrapper I include .lib file from C project
Test.h
#ifndef TEST_H
#define TEST_H
#ifdef BUILDING_MY_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
DLL_EXPORT void f();
#ifdef __cplusplus
}
#endif
#endif
Test.c
#include "Test.h"
#include "myfunc.h"
void f()
{
g();
}
In your C project you have to add BUILDING_MY_DLL to
Configuration Properties > C/C++ > Preprocessor > Preprocessor Definitions
The only real change is that I added the toggle between __declspec(dllexport) and __declspec(dllimport). Changes required:
Moved f's body to Test.c because functions imported with __declspec(dllimport) cannot have a definition already.
Other changes:
Do never write extern "C" without an #ifdef __cplusplus guard, or many C compilers will not compile your code.
I just spent 2 days fighting this exact same problem. Thank you for the solution. I'd like to extend it.
In my case, I am calling a c function from an exported c++ dll function and I was getting the same error. I was able to fix it so (using your example)
#ifndef TEST_H
#define TEST_H
#ifdef BUILDING_MY_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include "myfunc.h"
#ifdef __cplusplus
}
#endif
#endif

Why will I have a runtime check failure error?

I did not realize in a .dll library object types that depends on things that happen at compile time can case problems until I read the question Could I ignore C4251 warning in this case? In deed, if the library compilation settings for the library and the program that uses the library are different, some errors can occur. Here is an example:
dll.h
#include <iostream>
#include <string>
using namespace std;
class __declspec(dllexport) HelloWorld
{
public:
#ifdef DTEST
int test;
#endif
HelloWorld();
};
dll.cpp
#include "dll.h"
HelloWorld::HelloWorld()
{
#ifdef DTEST
test=0;
#endif
}
exe.cpp
#include "dll.h"
#include <iostream>
using namespace std;
int main(void)
{
HelloWorld myworld;
return 0;
}
If I compile dll.h and dll.cpp to create dll.lib and dll.dll with the definition of DTEST but compile exe.cpp without the definition of DTEST. I will have a runtime check failure #2 error. Could some explain why I have this error. Thanks!
You have this error because DTEST is a preprocessor macro and you are not defining it consistently for all pieces of your program. It is completely removed by the time your code reaches the actual compiler, so the compiler won't catch the problem. If you define DTEST for dll.cpp but not for exe.cpp, then exe.cpp will look like this to the compiler:
(...contents of <iostream>...)
(...contents of <string>...)
using namespace std;
class __declspec(dllexport) HelloWorld
{
public:
HelloWorld();
};
(...contents of <iostream> again...)
using namespace std;
int main(void)
{
HelloWorld myworld;
return 0;
}
However, dll.cpp will look like this:
(...contents of <iostream>...)
(...contents of <string>...)
using namespace std;
class __declspec(dllexport) HelloWorld
{
public:
int test;
HelloWorld();
};
HelloWorld::HelloWorld()
{
test=0;
}
The problem here is dll.cpp and exe.cpp have two different ideas of what HelloWorld is: dll.cpp thinks it contains test, but exe.cpp thinks it doesn't. There is a runtime check that catches this mismatch, which is what you're seeing.
What the compiler sees is the results of preprocessor expansion.
In your example, the compiler sees:
class HelloWorld
{
public:
int test;
HelloWorld();
};
in dll.cpp, and
class HelloWorld
{
public:
HelloWorld();
};
in exe.cpp. Same class, two different definitions. That's
a violation of the one definition rule, which results in
undefined behavior.
This has nothing to do with the C4251 warning (which if
I understand correctly, only concerns linking between different
DLLs).

Is it possible to create a thread of a static member function that is defined in a DLL?

Say I have the following .h and .cpp files for a DLL:
.h
#ifdef BLAH_EXPORTS
#define BLAH_API __declspec(dllexport)
#else
#define BLAH_API __declspec(dllimport)
#endif
class BLAH_API MyClass
{
public:
static void SomeFunction();
};
.cpp
#include ".h" //you get the picture
void MyClass::SomeFunction()
{
//blah blah blah
}
Now you import the .dll and .lib for this DLL into another program.
Is it possible to create a thread of MyClass::SomeFunction() since it's hidden in a DLL?

build(compile.link) application code with only DLL *.h header file and load DLL implementation in run-time (explicit linking)

I have an application code which invokes a DLL lib with explicit linkage (or run time linking) for accessing an exported class.
DLL.h
#ifdef DLL_EXPORT
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
FooDLL.h
#include "DLL.h"
class DLL_API Foo
{
public:
void doSomeThing();
};
extern "C" DLL_API Foo* _getInstance() {
return new Foo();
}
typedef Foo* (*getInstanceFactory)();
Foo* getInstance() {
HINSTANCE dllHandle = LoadLibraryA("Foo.dll");
getInstanceFactory factory_func = (getInstanceFactory)GetProcAddress(dllHandle, "_getInstance");
return factory_func();
}
FooDLL.cpp
#include "FooDLL.h"
Foo::doSomething() {
// .......
}
Application.cpp (which invokes DLL)
#include "FooDLL.h"
Foo* obj = getInstance();
obj->doSomething(); // XXX this line can be compiled and linked only when DLL is already in path
The above code can be built (e.g. compiled&linked) only when the DLL file is included in lib path. Otherwise I got unresolved external symbol error.
error LNK2001: unresolved external symbol "__declspec(dllimport) public: void __thiscall Foo::doSomething()" .....
Is it possible to build the application code with only DLL header file (i.e. FooDLL.h) and without DLL/LIB files during the build time? (p.s. The class implementation must be in cpp file.)
thanks!
with virtual function.
class Foo
{
public:
void virtual doSomeThing();
};
Yes it is possible. If you did not export a class you would not need a header file at all.
I am not sure why you placed call to LoadLibrary in the header file.
Since you are exporting class, you have to let the compiler know the type. Besides, you do not have to export entire class, you can export only specific member functions of the class you want to expose
Your dll header to be used in a dll and exe projects, should include following (I used my own names):
#ifdef WIN32DLL_EXPORTS
#define WIN32DLL_API __declspec(dllexport)
#else
#define WIN32DLL_API __declspec(dllimport)
#endif
class CWin32DLL
{
public:
CWin32DLL();
int WIN32DLL_API GetInt();
};
Implementation:
#include "stdafx.h"
#include "Win32DLL.h"
extern "C" WIN32DLL_API CWin32DLL* _getInstance()
{
return new CWin32DLL();
}
// This is the constructor of a class that has been exported.
// see Win32DLL.h for the class definition
CWin32DLL::CWin32DLL()
{
}
int CWin32DLL::GetInt()
{
return 42;
}
Your DLL consumer:
#include "Win32DLL.h"
#include "SomeOther.h"
typedef CWin32DLL* (*getInstanceFactory)();
HINSTANCE dllHandle = LoadLibrary(_T("Win32DLL.dll"));
getInstanceFactory factory_func = (getInstanceFactory)GetProcAddress(dllHandle, "_getInstance");
CWin32DLL* pWin32 = factory_func();
int iRet = pWin32->GetInt();
Do not forget to define WIN32DLL_EXPORTS (or equivalent) in project properties, C++, Preprocessor, Preprocessor Definitions for the dll.

c++ exporting and using dll function

I can't quite figure out where there is a mistake. I am creating a DLL and then using it in a C++ console program (Windows 7, VS2008). But I get LNK2019 unresolved external symbol when trying to use the DLL functions.
First the export:
#ifndef __MyFuncWin32Header_h
#define __MyFuncWin32Header_h
#ifdef MyFuncLib_EXPORTS
# define MyFuncLib_EXPORT __declspec(dllexport)
# else
# define MyFuncLib_EXPORT __declspec(dllimport)
# endif
#endif
This is one header file I then use in:
#ifndef __cfd_MyFuncLibInterface_h__
#define __cfd_MyFuncLibInterface_h__
#include "MyFuncWin32Header.h"
#include ... //some other imports here
class MyFuncLib_EXPORT MyFuncLibInterface {
public:
MyFuncLibInterface();
~MyFuncLibInterface();
void myFunc(std::string param);
};
#endif
Then there is the dllimport in the console program, which has the DLL included in the Linker->General->Additional Library Directories:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
__declspec( dllimport ) void myFunc(std::string param);
int main(int argc, const char* argv[])
{
std::string inputPar = "bla";
myFunc(inputPar); //this line produces the linker error
}
I can't figure out what's going wrong here; it must be something really simple and fundamental.
You're exporting a class member function void MyFuncLibInterface::myFunc(std::string param); but trying to import a free function void myFunc(std::string param);
Make sure you #define MyFuncLib_EXPORTS in the DLL project. Make sure you #include "MyFuncLibInterface.h" in the console app without defining MyFuncLib_EXPORTS.
The DLL project will see:
class __declspec(dllexport) MyFuncLibInterface {
...
}:
And the console project will see:
class __declspec(dllimport) MyFuncLibInterface {
...
}:
This allows your console project to use the class from the dll.
EDIT: In response to comment
#ifndef FooH
#define FooH
#ifdef BUILDING_THE_DLL
#define EXPORTED __declspec(dllexport)
#else
#define EXPORTED __declspec(dllimport)
#endif
class EXPORTED Foo {
public:
void bar();
};
#endif
In the project which actually implements Foo::bar() BUILDING_THE_DLL must be defined. In the project which tries to use Foo, BUILDING_THE_DLL should not be defined. Both projects must #include "Foo.h", but only the DLL project should contain "Foo.cpp"
When you then build the DLL, the class Foo and all its members are marked as "exported from this DLL". When you build any other project, the class Foo and all its members are marked as "imported from a DLL"
You need to import the class not a function. After that, you can call the class member.
class __declspec( dllimport ) MyFuncLibInterface {
public:
MyFuncLibInterface();
~MyFuncLibInterface();
void myFunc(std::string param);
};
int main(int argc, const char* argv[])
{
std::string inputPar = "bla";
MyFuncLibInterface intf;
intf.myFunc(inputPar); //this line produces the linker error
}