Using a class inside a dll - c++

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.

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

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

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

How to write modules on Windows?

I'm currently writing a program that should be working on both Windows and Linux. The program uses dynamic modules (LoadLibrary/dlopen) to simplify deployment of different functions.
The Linux part works just fine: The main program exports functions and variables with -Wl,--export-dynamic so the modules can access them, and the modules can be compiled with gcc's -shared option without the requirement to resolve all symbol dependencies when linking.
With Windows (using MSVC 2010), this seems not to work. I'm exporting functions and variables from the main program using __declspec(dllimport), but I am not able to access functions and variables from the main program because linking fails (unresolved external, LNK1120).
How to deal with this? Thank you.
Edit (code sample):
core-file.cpp
#include "core-file.hpp"
Cls_A cls_instance;
void Cls_A::do_something() {
while(0);
}
core-file.hpp
#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif
class TEST_API Cls_A {
public:
void do_something();
};
extern Cls_A cls_instance;
module.cpp
#include "core-file.hpp"
TEST_API int my_init_function() {
cls_instance.do_something();
return 0;
}
__declspec(dllimport) is for when you're compiling the the program that uses the DLL. When you compiling the actual DLL, you want to use __declspec(dllexport).
Your use of these must be consistent. The typical idiom is to define a macro that will use dllimport and dllexport based on the presence of a macro. In the project the builds the DLL, you define the macro that means to export the functions, and in other projects you don't define it, which means to import them:
#ifdef PROJECT_NAME_BUILD_DLL
#define DLL_SYMBOL __declspec(dllexport)
#else //PROJECT_NAME_BUILD_DLL
#define DLL_SYMBOL __declspec(dllimport)
#endif //PROJECT_NAME_BUILD_DLL
DLL_SYMBOL void SomeFunction(Type value);
The project that builds the DLL will define PROJECT_NAME_BUILD_DLL; projects that use the DLL which include this header do not define this.
On Windows, when you want to link against exported symbols you have to remember to specify all the import libraries that were generated when you linked the modules whose symbols you want to import. (You can just leave the symbols unresolved on Linux because the executable format is different and it's possible to defer symbol resolution to load time.)

Export DLLs classes and functions and import them into Win32 Application

I have a dll with a class that define some methods and variables inside it. I marked it as
__declspec(dllexport)
and i imported the .h header inside a win32 application project in the same solution. I can use the functions but when I try to compile the project I have a lot of errors about external symbols not resolved. Why?
Please read about the standard way of using macros for this very common task here: http://wiki.tcl.tk/8721
The basic idea is that you define a macro, say MY_API like so:
#ifdef BUILD_MYAPI
# define MY_API __declspec(dllexport)
#else
# define MY_API __declspec(dllimport)
#endif
When you declare a function or a class in the header file you do this:
void MY_API myApiFunction(int x);
When you build your own dll which declares the body of the function, you add the definition of BUILD_MYAPI to the build. This makes all declerations to be dllexport
when you include the header from some other dll you don't add BUILD_MYAPI so the decelerations are dllimport
When compiling with visual studio, you can add a macro definition to the compilation without changing the source from project properties -> C/C++ -> Preprocesson -> Preprocessor definitions
For the application where you want to import that class, you will need to mark the class as
__declspec(dllimport)
Instead of dllexport.
You must also make sure to link with the import library of the DLL (a .lib file).

Forcing symbol export with MSVC

I have a application and several plugins in DLL files. The plugins use symbols from the
application via a export library. The application links in several static libraries and this is where most of the symbols come from. This works fine as long as the application uses a symbol. If the symbol is not used there, I get linker errors when compiling the DLL.
How can I force the export of the symbols only used in the plugins?
In order to trigger the export I've tried something like this:
class MyClassExporter
{
MyClass mInstance;
public:
MyClassExporter() {}
};
static MyClassExporter TheMyClassExporter;
in one of the static libs the application is made of to force the export, which didn't work.
In response to Greg (thanks for the answer) and to clarify: The class I want to force the export for is MyClass (which has __declspec(...) defined, depending on wether I want to export or import). MyClassExport was my attempt to force the inclusion of unused (in terms of the application) symbols into the app. I want to 'touch' the symbols so that the linker recognizes them as used and includes them into the application so that it can in turn export these to my plugins. Linking the static libs into the plugins is not an option, since they contain singletons which would be duplicated (app and DLLs each have their own copy of static variables).
The /INCLUDE directive can be used to force the MSVC linker to include a symbol. Alternatively, /OPT:NOREF can be used to disable removal of unused symbols in general.
A common approach is to create a single unused function that references all objects exported for your plugins. Then you only need a single /INCLUDE directive for that function.
You probably want to look at __declspec(export/import)
#ifdef DLL_EXPORTING
#define WHDLL __declspec(dllexport)
#else
#define WHDLL __declspec(dllimport)
#endif
When linking static module into a dll it will only bring in the code that is used. I've never imported stuff from a static lib to simply re export it.
Perhaps you just need to mark it as exportable in the dll when compiling the static lib.
But that reminds me of putting std containers into exported classes and using some trickery in msvc to export the 'instance' of the specialised container. the template code is similar to your static code (in my thinking)
for instance without the template you get warnings the template code is not exported to support the class - this is MSVC specific from my understanding
template class DLL_EXPORTING std::auto_ptr<wxCursor>;
class DLL_EXPORTING imageButton : public wxWindow
{
std::auto_ptr<wxCursor> m_Cursor;
};
What I tried out to solve this was this:
build a static library with function void afunction( int ).
build a dll, linked to static lib, exporting afunction.
build an exe, using the afunction symbol.
How? Since the linker can be told to export functions using the __declspec(dllexport) directive, a dll needs no more than declare a to-be-exported symbol thusly.
The lib has a header "afunction.h" and an accompanying cpp file containing the function body:
// stat/afunction.h
namespace static_lib { void afunction(int); }
// stat/afunction.cpp
#include "afunction.h"
namespace static_lib { void afunction(int){ } }
The dll has an include file "indirect.h", containing the declaration of the function to be exported. The dll has a link-time dependency to the static lib. (Linker options: Input/Additional Dependencies: "static_library.lib")
// dll/indirect.h
namespace static_lib {
__declspec( dllexport ) void afunction(int);
}
The executable has only the indirectly included file:
#include <dll/indirect.h>
int main() { static_lib::afunction(1); }
And guess what? It compiles, links and even runs!
The "Use Library Dependency Inputs" option does the trick in VS2005!
This option can be found under Configuration Properties -> Linker -> General -> Use Library Dependency Inputs. Set to "true" to force linking in ALL symbols & code declared in every LIB specified as input to the project.
You can do the following to get the symbol to export from the DLL: define LIB_EXPORTS in the library project and nothing in either the DLL project or the DLL client project.
#ifdef LIB_EXPORTS
#define DLLAPI __declspec(dllexport)
#else
#define DLLAPI __declspec(dllimport)
#endif
Turns out there is no need #include any headers from the LIB project when compiling the DLL project; just specify the LIB as a linker input. However, if you need to make use of the LIB code from within the DLL, you will need to #define DLLAPI as an empty macro; setting the symbol(s) to either dllexport or dllimport will generate an error or a warning, respectively.
There is some discussion of this problem on MSDN which was pretty useful. As it turns out, /OPT:NOREF is not particularly helpful in this case. /INCLUDE can work but it can be hard to automatically figure out what needs to be /INCLUDEd. There's unfortunately no silver bullet.
http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/2aa2e1b7-6677-4986-99cc-62f463c94ef3