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.
Related
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);
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.
I created a DLL project and successfully built it. I then tried to use the DLL in another Project, TEST, and I am getting the following error.
Error 1 error LNK2001: unresolved external symbol "public: void __thiscall SnoMessage::setRawMessageName(class ATL::CStringT<wchar_t,class StrTraitMFC_DLL<wchar_t,class ATL::ChTraitsCRT<wchar_t> > >)" (?setRawMessageName#SnoMessage##QAEXV?$CStringT#_WV?$StrTraitMFC_DLL#_WV?$ChTraitsCRT#_W#ATL#####ATL###Z)
I added the required lib in the linker properties, and I also added the header files in the TEST include directory. So the function is being recognized, but it keeps giving those errors. The DLL is comprised of the following files
SnoMessage.h
#pragma once
#include "StdAfx.h"
class SnoMessage
{
public:
__declspec(dllexport) SnoMessage(void);
__declspec(dllexport) ~SnoMessage(void);
__declspec(dllexport) void setRawMessageName(CString messageName);
__declspec(dllexport) void setRawMessageType(CString messageType);
__declspec(dllexport) void setRawMessageAttributes(std::map<CString,CString> attributes);
__declspec(dllexport) CString getRawMessageName();
__declspec(dllexport) CString getRawMessageType();
__declspec(dllexport) std::map<CString,CString> getRawMessageAttributes();
private:
CString messageName;
CString messageType;
std::map<CString,CString> attributes;
};
SnoMessage.cpp
#include "stdafx.h"
#include "SnoMessage.h"
SnoMessage::SnoMessage(void)
{
}
SnoMessage::~SnoMessage(void)
{
}
void SnoMessage::setRawMessageName(CString messageName){
this->messageName = messageName;
}
void SnoMessage::setRawMessageType(CString messageType){
this->messageType = messageType;
}
void SnoMessage::setRawMessageAttributes(std::map<CString,CString> attributes){
this->attributes = attributes;
}
CString SnoMessage::getRawMessageName(){
return messageName;
}
CString SnoMessage::getRawMessageType(){
return messageType;
}
std::map<CString,CString> SnoMessage::getRawMessageAttributes(){
return attributes;
}
And in test I am doing the following:
test.cpp
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "SnoMessage.h"
int _tmain(int argc, _TCHAR* argv[])
{
SnoMessage *msg = new SnoMessage();
msg->setRawMessageName("TEST");
return 0;
}
Let me know if you need more info, thanks.
In your dll define this in some header you want to use for your export defs...
MyExports.h
#ifdef SNOMESSAGE_EXPORTS
#define SNOMESSAGE_API __declspec(dllexport)
#else
#define SNOMESSAGE_API __declspec(dllimport)
#endif
Now in your dll you just define SNOMESSAGE_EXPORTS, then when your dll is compiled your class and methods will be visible to the exe. But when you include those same headers in the exe the Macro will import them instead of export.
//In the DLL this is == to export, in the executable this is import. Problem solved.
class SNOMESSAGE_API SnoMessage
{
public:
//...
};
You no longer need to export each member, just the class.
I would mark the whole class as exported, not just its member functions. Also, following the advice of this conversation, you need to specify __declspec(dllecport) or __declspec(dllimport) based on whether you are including the header in the DLL or the code that uses the DLL; and define the guarding macro in the DLL project.
When you compile the DLL you should have __declspec(dllexport), but when you compile exe you should have __declspec(dllimport). The easiest way to do this is to have a #define somewhere that has different value when "in DLL" and "out of DLL". Also do export the whole class instead of individual methods.
There is a case when dll compile use C call but exe use standard call, the link in x64 has no problem, but when using win32 will show this link error 2001. For that situation just use C call for both dll and exe for win32 platform (https://learn.microsoft.com/en-us/cpp/error-messages/tool-errors/name-decoration?view=msvc-160).
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 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.