Create a DLL in C and link it from a C++ project - c++

As per title, I'm trying to build a DLL using C and link it from a C++ project. I read and followed different tutorials on internet but everytime there is something missing and I don't understand what.
Here's what I did, step by step:
I created a new Win32 project, named testlib, then, from the wizard, I chose "DLL" and "Empty project".
Added a header:
//testlib.h
#include <stdio.h>
__declspec(dllexport) void hello();
Added a source; since I want it to be a C source I read I should simplly rename the .cpp file in .c, so
//testlib.c
#include "testlib.h"
void hello() {
printf("DLL hello() called\n");
}
Build succeded.
Now I would like to use my useful dll in another project.
Then: new project (testlibUse). This time I selected "Empty project".
No need to add an header, just created a cpp source
//main.cpp
#include <testlib.h>
int main() {
hello();
}
Then:
I added the path to the folder where is testlib.dll in Properties->VC++ directories->Executable directories
I added the path to the folder where is testlib.h in Properties->VC++ directories->Include directories
I added the path to testlib.lib (included extension) in Properties->Linker->Input->Additional dependencies
I tried to build but I got a linker error:
LINK : C:\path\testlibUse\Debug\testlibUse.exe not found or not built by the last incremental link; performing full link
main.obj : error LNK2019: unresolved external symbol "void __cdecl hello(void)" (?hello##YAXXZ) referenced in function _main
C:\path\testlibUse\Debug\testlibUse.exe : fatal error LNK1120: 1 unresolved externals
If I go back to testlib, rename back testlib.c in testlib.cpp and rebuild the dll, then I am able to build testlibUse but I get a "dll not found" error at runtime.
I tried also to change the configurations of both projects in "Release" (changing the path where needed), but nothing changed.
Sorry for the long post but I think it was necessary to write down exactly what I did.
Any suggestions?
Besides, are there any configuration parameters I need to change if I want to use my dll in a Qt project?

You have several problems:
The header file should mark the functions as exported when being compiled in the DLL but imported when being compiled by a library user.
The header file should wrap the function declarations in an extern "C" block when being compiled as C++ to ensure that the names do not get mangled
The DLL is not on your executable's library search path, so it can't be found at runtime.
To fix (1) and (2), rewrite your header like this:
#ifdef __cplusplus
extern "C" {
#endif
// Assume this symbol is only defined by your DLL project, so we can either
// export or import the symbols as appropriate
#if COMPILING_MY_TEST_DLL
#define TESTLIB_EXPORT __declspec(dllexport)
#else
#define TESTLIB_EXPORT __declspec(dllimport)
#endif
TESTLIB_EXPORT void hello();
// ... more function declarations, marked with TESTLIB_EXPORT
#ifdef __cplusplus
}
#endif
To fix (3), copy the DLL into the same folder as your executable file. The "executable directories" setting you're setting doesn't affect DLL searching -- see MSDN for a detailed description of how DLLs are searched for. The best solution for you is to copy your DLL into the directory where your executable file lives. You can either do this manually, or add a post-build step to your project that does this for you.

You should extern "C" the include:
extern "C" {
#include <testlib.h>
}

It looks as if you need to make sure the compiler not mangle the symbol name in the cpp build. You should be able to add an extern "C" to the definition in testlib.h:
#ifdef __cplusplus
extern "C"
#endif
__declspec(dllexport) void hello();

Here's a method for your C header file that could be included by C++. Make sure to set TESTLIB_EXPORTS only in your DLL preprocessor settings. In projects that include this header to use the DLL, the header will declare the functions as imports instead of exports.
The __cplusplus guard will tell the compiler to import your functions using C name decoration instead of C++ name decoration.
#include <stdio.h>
#ifdef TESTLIB_EXPORTS
#define TESTLIB_API __declspec(dllexport)
#else
#define TESTLIB_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
TESTLIB_API void hello();
/* other prototypes here */
#ifdef __cplusplus
}
#endif

Related

Linking to visual studio dynamic library

I am trying to create a dynamic library and use it in a console application. The library is Multisite.lib.
My problem is that when I add the project as a reference and add the header files directory it works well, however, when I try to use this library in an independent project I get the unresolved external symbol error.
What I did in the independent project is to add the library to the Linker > Input > Additional Dependencies and add the header directories
#pragma once
#ifndef MultiSite_IMPORTS
#define MATHLIBRARY_API extern "C" __declspec(dllexport)
#else
#define MATHLIBRARY_API extern "C" __declspec(dllimport)
#endif
#define STACKMODE __stdcall
#include <string>
struct interfaceManager;
MATHLIBRARY_API interfaceManager* STACKMODE createInstance();
MATHLIBRARY_API void STACKMODE bert_init(interfaceManager * inst , int bid);
MATHLIBRARY_API bool STACKMODE bert_connect(interfaceManager * inst, std::string IP);
These are the functions that I am trying to export and that are considered unresolved external symbols
EDIT
I tried to use the VS developer tools using dumpbin /EXPORTS MultiSite.lib and all my functions are there
The header doesn't contain the magic line needed to make Visual Studio link the right library. That's #pragma comment(lib, "MultiSite.lib"). It goes after #define MATHLIBRARY_API extern "C" __declspec(dllimport).
Alternatively, you can indeed tell the linker directly that MultiSite.lib is an additional input. See the Visual Studio linker property pages of your executable project.
"What I did in the independent project is to add the library to the Linker > Input > Additional Dependencies and add the header directories"
As far as I'm concerned, the project lacks MultiSite.lib. I suggest you should add the path to the .lib file to the Additional Library Directories (property -> linker -> General -> Additional Library Directories).
The problem was using a 64-bit library on a 32-bit application.
That's why it was working fine when I added it to the same solution but not in my independent project.
I used to think that visual studio can detect a wrong format but turns out that just the exported symbol's names change between two same libraries with different bit configuration.
Hence this explains the unresolved external symbol error that I encountered

Compile dll in Qt with VS compiler to use it in Borland

I have a package of C functions and I need to create DLL library from it, that can be used in C++ program. I haven't done any library before, so I am total beginner in that. I am working in Qt Creator.
My first try was to create it according to the manual Creating shared libraries, so I added these two lines to my project file:
TEMPLATE = lib
DEFINES += MYLIB_LIBRARY
Then I created mylib.h file
#ifndef MYLIB_H
#define MYLIB_H
#include "mylib_global.h"
#include "functions1.h"
#include "functions2.h"
#include "functions3.h"
class MYLIBSHARED_EXPORT Mylib
{
public:
Mylib(){};
};
#endif // MYLIB_H
Finally I added mylib_global.h:
#ifndef MYLIB_GLOBAL_H
#define MYLIB_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(MYLIB_LIBRARY)
# define MYLIBSHARED_EXPORT Q_DECL_EXPORT
#else
# define MYLIBSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // MYLIB_GLOBAL_H
To make functions usable in C++ I used these lines for each function in library
#ifdef __cplusplus
extern "C"{
#endif
void foo();
#ifdef __cplusplus
}
#endif
When compiling with MSVC2012 everything seems ok and I got some .dll file. But then I sent library to someone, who wanted to use it in Borland C++. He told me that I have to compile it with some DEF file to tell to VS compiler right names and with __stdcall instead of __cdecl. But I have no idea how to do it in Qt. Any explanation and help would be really appreciated. Thanks
P.S. I looked at posts Using VS dll in old Borland and Import VS dll in C Builder, but they
did not help me to understand the problem.
If you want to export the foo function, you need to tell the linker somehow.
What you were suggested is to use a .def file, which is quite easy.
Just create a file like exports.def in your project directory, and write in it something like:
EXPORTS
foo
Then go to your library project settings -> Linker -> Input -> Module Definition File
and fill in your .def file name

Visual Studio: Creating C++ dll and use it in VB Code

Using Visual Studio 2013, I am currently trying to generate a .dll with C++ Code, which i want to include into a VB.NET project. To create the .dll i tried to follow these tutorials:
http://www.codeguru.com/cpp/cpp/cpp_mfc/tutorials/article.php/c9855/DLL-Tutorial-For-Beginners.htm
http://msdn.microsoft.com/de-de/library/ms235636.aspx
For now my .dll Project contains only the following files:
External Dependencies (auto generated by VS2013)
Header Files: stdafx.h, targetver.h (auto generated)
dllmain.cpp with default entry point Method DllMain and stdafx.cpp (auto generated)
MyDLL.cpp and containing the implementation of my methods which should be exported (for now one void method without parameters)
Headerfile MyDLL.h
Source.def (i only added the .def file after i tried using the __declspec(dllexport) statement)
MyDll.h contains:
#ifndef _DLL_MYDLL_H_
#define _DLL_MYDLL_H_
#include <iostream>
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
extern "C"
{
DECLDIR void MyMethod();
}
#endif
MyDLL.cpp contains:
#include "stdafx.h"
#include "MyDLL.h"
#define DLL_EXPORT
extern "C"
{
void MyMethod(){
//my code
}
When i create the .dll (by using "build > build solution" in VS2013) it compiles without errors and warnings. However, when i try to set a reference in my VB-Project by using "project > add reference" and selecting the .dll that was created in the DEBUG-Folder of my DLL-Project, i get an error stating that the reference could not be added and that i should make sure that the file is accessible and that it is a valid assembly or COM component.
Am i missing some vital settings in my dll/vb project here? Thanks in advance for your advice.

Using a class inside a dll

I have a class inside a dll which I want to use in another project. I read this tutorial about how to do this and my pseudo code looks like this
interface.h
#ifdef EXPORT
#define SOMEAPI __declspec(dllexport)
#else
#define SOMEAPI __declspec(dllimport)
#endif
struct ISomeInterface
{
virtual void SomeMethod()=0;
};
typedef ISomeInterface* SOMEHANDLE;
#define EXTERN_C extern "C"
EXTERN_C SOMEAPI SOMEHANDLE WINAPI CreateSomething(VOID);
And then I have SomeDLL.dll which implements ISomeInterface and CreateSomething.
When I try to use this in my client I get linker error. The client looks like this:
Client.cpp
#include "interface.h"
SOMEHANDLE h = ::CreateSomething(); // Linker error here: Unresolved external
I can solve this by adding the dll project as a dependency of Client project in VC++. Then everything is good.
The problem is what if I want to use this a standalong dll(which is the case right now)? How do I get rid of the linker error then?
I can solve this by adding the dll project as a dependency of Client project
Yes, that automatically does the one thing you have to do in a stand-alone project by hand. Project + Properties, Linker, Input, Additional Dependencies setting. Add the .lib file that was generated by the DLL project. The import library, it tells the linker about the functions exported by the DLL.

Can't access variable in C++ DLL from a C app

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.