I'm having problems in implementing a class in a DLL in the same way it is explained here
. I have my interface with all the methods declared as virtual, I have my class that implements the interface and I have the method that should create the object of the class. The problem is here, when I try to use it I get a "unreferenced external symbol" error. Why?
class IXYZ
{
virtual void XXX() = 0;
};
class XYZ : public IXYZ
{
void XXX();
}
#ifdef __cplusplus
extern "C" __declspec(dllexport) IXYZ* __stdcall GetIXYZ();
#endif
and I use it inside my win32 program with:
IXYZ *myvar = GetIXYZ();
In my exe program I've included the .h file of the dll
If you've correctly defined the function in the DLL, and it is exported properly, then the only plausible explanation is that there is something wrong with your use of the .lib file in the application that uses the DLL.
Related
I am developping a C++ DLL with a C wrapper in order to use it in Python and C#. So I create on Visual Studio a project (DLL) to develop and compile it. No problem here. I even can use my DLL on Python without trouble.
But, on Visual, I want to create another project in the same solution as the DLL to test the DLL too.
So I created the second project (Win32 Windows Application), added the .h to the header files, added the link to the .lib file I added in the folder of the test project, but when I try to compile it, I have errors about LNK2019, beginning with the constructor:
error LNK2019: unresolved external symbol "public: __cdecl Projet::Projet(void)" (??Projet##QEAA#XZ) referenced in function main
DLL = Projet / Test = Projet_Test
Projet.h
#pragma once
#include "Projet_inc.h"
class Projet
{
public:
Projet();
~Projet();
int multiply(int arg1, int arg2);
int result;
};
Projet_inc.h
#ifdef PROJET_EXPORTS
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __declspec(dllimport)
#endif
#define CALLCONV_API __stdcall
#ifdef __cplusplus
extern "C" // C wrapper
{
#endif
typedef struct Projet Projet; // make the class opaque to the wrapper
EXPORT Projet* CALLCONV_API cCreateObject(void);
EXPORT int CALLCONV_API cMultiply(Projet* pDLLobject, int arg1, int arg2);
#ifdef __cplusplus
}
#endif
Projet.cpp
#include "stdafx.h"
#include "Projet.h"
Projet::Projet() {}
Projet::~Projet() {}
int Projet::multiply(int arg1, int arg2) {
result = arg1 * arg2;
return result;
}
Projet* EXPORT CALLCONV_API cCreateObject(void)
{
return new Projet();
}
int EXPORT CALLCONV_API cMultiply(Projet* pDLLtest, int arg1, int arg2)
{
if (!pDLLtest)
return 0;
return pDLLtest->multiply(arg1, arg2);
}
Projet_Test.cpp
// Projet_Test.cpp : définit le point d'entrée pour l'application console.
//
#include "stdafx.h"
#include "Projet.h"
int main()
{
Projet object;
return 0;
}
On Visual, I select the test project as startup project for information. And I look a lot of posts on SO but I didn't find the solution for now. Thank you in advance.
You need to __declspec(dllexport) all functions that you want to call directly, not just the C ones.
In your example, you should be able to correctly call the C wrapper functions cCreateObject and cMultiply, as those were exported correctly, but you will not be able to call the underlying C++ functions like Projet::Projet() and Projet::~Projet().
You have two ways of solving this: You can change these functions to inline functions and move their implementation to the header. That way, the client project will no longer invoke the code from the DLL for those functions, but instead just compile the inline definitions directly itself. This is obviously not a sensible approach in general. Alternatively, mark your C++ member functions with __declspec(dllexport), just as you did with the C functions.
Note that Visual Studio has a tendency of breaking the C++ ABI between versions, so you need to make sure that the compiler version you used for compiling the dll is compatible with the one you used for compiling the client application. This is not an issue if both parts are compiled with the same Visual Studio version or if you stick with a plain C interface.
First, the error about the missing symbol EpsCndCoreDll seems to be out of context here and you should rather be getting a compile error about redefining struct as a class (class Projet).
Probably you need to use something like:
class Projet;
typedef Projet* PProjet;
and use PProject as the opaque handle further on.
You also need to export the Projet class like:
class EXPORT Projet
to be able to instantiate that class by a client or add a factory function that returns a reference.
Make sure that you have added the DLL reference to your DLL.
My problem is remarkably similar to this one: A class in a DLL has a static member. In this case, the static member is of Type QString (a QT type) and provides a name for the class. I provide the normal export on class level: __declspec(dllexport).
When I link the DLL with my class to another project and try to compile it, I get an "unresolved external symbol" error for the static data. I verified two things:
Dumpbin definitely reports the static data member to be exported by compiled DLL.
Actually, the static data member seems not to be used in the application which reports the error.
HEADER file (.h) in DLL is:
class __declspec(dllexport) MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
IMPLEMENTATION file (.cpp) in DLL is:
#include "MyClass.h"
MyClass::~MyClass() { }
const QString MyClass::JUST_A_NAME("call_me_al");
In contrast to already mentioned post, I avoided methods to be inline, e.g. implementation is obviously not in the header. The type, QString (see line 83 ff.), contains several inlines itself. May that cause the error?
EDIT: I added an import statement in the header of my application. It is located before any includes.
HEADER file (.h) in APPLICATION is:
class __declspec(dllimport) MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
The error remains the same:
error LNK2001: non resolved external symbol ""public: static class QString const MyClass::JUST_A_NAME" (?JUST_A_NAME#MyClass##2VQString##B)". <name of .obj file from application>
In your application header file you need to do two things.
When exporting, declare the definition __declspec(dllexport)
When importing, declare the definition __declspec(dllimport)
You obviously cannot do them both at the same time.
What you have to do is define a macro like this:
#ifdef __COMPILING_MYLIB
#define MYLIBAPI __declspec(dllimport)
#else
#define MYLIBAPI __declspec(dllexport)
#endif
Then declare your exports like this:
// mylib.h
class MYLIBAPI MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
Then, when compiling MYLIB, you pass -D__COMPLING_MYLIB to the compiler, which triggers the #if above.
That way, when compiling the library itself, the header file declares things as exports, but when compiling things which will use the library, they are declared as imports.
I'm trying to use a C++ class from a native .dll project in a C++/CLI .dll project. Visual Studio 2010, .NET Framework 3.5. So far this is what I have:
// This is a common macro:
#ifdef ISDLL
#define DLL __declspec(dllexport)
#else
#define DLL __declspec(dllimport)
#endif
NativeProject:
//INativeType.h:
class DLL INativeType {
public:
virtual void Foo() = 0;
};
//NativeType.h:
class DLL NativeType : public INativeType {
public:
virtual void Foo();
};
extern "C" DLL INativeType CreateNativeType();
//NativeType.cpp:
void NativeType::Foo() {}
extern "C" DLL INativeType* CreateNativeType() {
return new NativeType();
}
C++/CLI Project:
// Wrapper.h:
#include "INativeType.h"
ref class Wrapper {
INativeType* m_nativeType;
};
// Wrapper.cpp:
#include "Wrapper.h"
#include "NativeType.h"
// in some method:
m_nativeType = CreateNativeType();
This gives me the following linker error:
error LNK2028: unresolved token (...) "extern "C" class INativeType * __stdcall CreateNativeType(void)"" ... in Wrapper.obj
Also, although the functions are correctly exported in NativeProject.dll, as I verified it with DependencyWalker, the linker also gives this warning:
warning LNK4199: /DELAYLOAD:NativeProject.dll ignored; no imports found from NativeProject.dll
The C++/CLI project is configured to delay load NativeProject.dll and also includes NativeProject.lib in its linker options. At this point I don't know how to diagnose this linker error. What am I doing wrong?
Why don't you just let the C++/CLI project instantiate the class directly instead of with a factory method?
Besides that, it just looks like you are re-inventing COM (using objects through interfaces). I would just instantiate full-blown C++ classes or, if you really need it, use full-blown COM.
EDIT: Make sure the factory method's calling convention is the same in both the client and the DLL.
First of all I use VS 2008 and dynamic build of Qt 4.7.0.
interface.h:
class PluginInterface
{
public:
virtual void foo() = 0;
};
Q_DECLARE_INTERFACE(PluginInterface, MY_PLUGIN_VERSION)
And I have and class which implements this interface:
myplugin.h
class MyPlugin: public QObject, public PluginInterface
{
public:
Q_OBJECT
Q_INTERFACES(PluginInterface)
virtual void foo(); // this functions is implemented in cpp file.
static QString goo(); // this function is also implemented in cpp file.
};
So when I use this plugin in other project(MySpecialPlugin) which will be compiled as dynamic-link library(actually also a plugin interface implementation) I can't call
MyPlugin::goo();
The header of "MyPlugin.h" is visible for MySpecialPlugin. And Ms VS2008 successfully compile the project. But I have error on link step LNK2001, undefined reference. But when change static void goo(); to virtual void goo(); it works.
I'm using Q_EXPORT_PLUGIN2 macro for creating plugins.
What I'm doing wrong? Does Qt set additional requirements on implementation of plugin interfaces?
First of all you need to export your class (on windows it's magic like __declspec(dllexport) after class keyword when compiling your "myplugin" and __declspec(dllimport) when compiling code using it (in this case MySpecialPlugin). You can achieve it with simple define. read more
#ifdef _WIN32
#ifdef MYPLUGIN_COMPILE
#define MYPLUGIN_EXPORT __declspec(dllexport)
#else
#define MYPLUGIN_EXPORT __declspec(dllimport)
#endif
#else
#define MYPLUGIN_EXPORT
#endif
class MYPLUGIN_EXPORT MyPlugin
{
// implementation
};
And add MYPLUGIN_COMPILE to preprocessor section of MyPlugin
You need to link against exporting library
Calling static and "normal" methods differs from calling virtual methods... static and "normal" methods are always at certain address and your code needs to know where is it... virtual call "checks" class vtable at what address your method has implementation and get that address "dynamicly" from that table. Additionaly win32 VC platform requires to define that something is "exported" (exposed) to access from outside of dll. So basicly if you want to call anything from MyPlugin directly (every member that is not virtual is called directly), you have to export it on win32 VC platform. Note that calling directly virtual method with MyPlugin::foo() will cause same error
I'm working on a C++ project built with Visual Studio 2008.
I'm defining (in a project producing a dll) a template class and a derived, not-template, one:
template <class T>
struct DLL_EXPORT Base {
int base() { return 1; }
};
struct DLL_EXPORT Deriv: public Base<Deriv> {
int deriv() { return 1; }
};
the DLL_EXPORT is the usual stuff:
#ifdef COMPILING_MY_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
Now, when I'm trying to use my Deriv class in another project, the trouble is starting. If I use only the function from Deriv, it works well:
Deriv d;
d.deriv();
But if I try to call d.base(), I get the following linker error:
error LNK2019: unresolved external symbol "__declspec(dllimport) public: int __thiscall Base<struct Deriv>::base(void)" (__imp_?base#?$Base#UDeriv####QAEHXZ)
If, elsewhere in my dll code, I'm using the d.base() function, it works well, and the linker error disappear in the "user" project. And if I remove the template part (it's not really useful in my example, but in the real-life situation it is), everything is fine.
It looks like the function don't get compiled if it's not used, or something equivalent. Any idea ?
Thanks in advance.
don't use __declspec(dllexport) on template definitions since they are not exported (they are not real code until instantiated).
They are only in the header file for usage by sources. You can use __declspec(dllexport) on specializations of templates ,but you must instatiated those at least once in your DLL.
If that is your problem, you might be able to fix it by explicitly instantiating the template.
In one of the .cc files in your DLL (not header file), include your template definition and write:
template int Base<Deriv>::base();
This should force the compiler to put the code for Base<Deriv>::base() into that compilation unit so your linker can find it.
I don't know much about this, but I think you might be able to fix it by writing
template struct Base<Derive>;
somewhere in your source file. (or perhaps template DLL_EXPORT struct Base<Derive>;)