Reputation: 457
I currently need to write a C++/CLI wrapper for a native C++ library (TetGen) for later use in a C# project. I have read quite a few articles on how to do this but am at a loss with my linker errors. A chap called "Sam Agten" tried to accomplish this too, as he states in his Blog which led me to a series on C++ Interop (Part 1, Part 2, Part 3, Part 4, Part 5), where Part 3 is supposed to explain how to do what I accomplish.
Because Sam wanted to integrate TetGen with Unity he at last had to resort to C-Style-Wrappers. Now, if I'm not entirely mistaken, I have tried using C-Style-Wrappers on a previous, related project.
Because my wrapped TetGen must run on a Windows Server (2008 I think) my first question is: Will a C++/CLI-Wrapper work in a Server-Environment?
I started writing a very simple wrapper according to aforementioned Part 3, which failed miserably. Anyway I tried to create a simple wrapper library along the line of thought, which I want to share with you. I began by creating a C#-project which ultimatly should use my wrapped library and added first a new project from the "Win32"-subsection of C++-projects "SimpleAdd".
//SimpleAdd.h
class _declspec(dllexport) SimpleAdd
{
public:
SimpleAdd();
~SimpleAdd();
int Add(int a,int b);
};
//SimpleAdd.cpp
#include "SimpleAdd.h"
int SimpleAdd::Add(int a, int b)
{
return a+b;
}
In the project settings I made sure, that it compiled to a static library (*.lib) and no CLR-Support was used. From the preprocessor definition I assume the lib is to target x86 systems: "WIN32". Everything is left pretty much on standard values. If I right-click => build it will successfully build a lib called "SimpleAdd.lib".
One thing I was pointed to through other posts: If I open the lib in DependencyWalker, I get an error saying: "No DOS or PE signature found. This file is not a valid 32-bit or 64-bit Windows module" which is kind of frustrating. What do I have to to to make DependencyWalker stop showing this error, since I think this 32/64-problem might hint to a solution.
Anyway, I have my lib, now I want to wrap it up. So I created a new project in my solution called "AddWrapper", using the CLR-ClassLibrary-template of the C++-branch.
// AddWrapper.h
#pragma once
#include "..\SimpleAdd\SimpleAdd.h"
using namespace System;
namespace AddWrapper {
public ref class ManagedSimpleAdd
{
private:
SimpleAdd *sa;
public:
ManagedSimpleAdd();
~ManagedSimpleAdd();
int Add(int a, int b);
};
}
//AddWrapper.cpp
#include "AddWrapper.h"
using namespace AddWrapper;
ManagedSimpleAdd::ManagedSimpleAdd() : sa(new SimpleAdd())
{
}
ManagedSimpleAdd::~ManagedSimpleAdd(){delete sa;}
int ManagedSimpleAdd::Add(int a, int b)
{
return sa->Add(a,b);
}
As both C++-projects are in seperate folders on the same hierarchical level, I specified the relative path to the headerfile. In the project settings I now have the configuration standard .dll and the /clr-switch. In my VC++ folders I added the path to the Debug-directory of my whole soultion, because this is where the referenced lib is compiled to. In my linker-settings under "additional dependencies" I added the name: "SimpleAdd.lib".
When I want to build my wrapper however, there is a problem, or rather 5 of them:
Fehler 3 error LNK2028: Nicht aufgel÷stes Token (0A00000B) ""public: __thiscall SimpleAdd::SimpleAdd(void)" (??0SimpleAdd@@$$FQAE@XZ)", auf das in Funktion ""public: __clrcall AddWrapper::ManagedSimpleAdd::ManagedSimpleAdd(void)" (??0ManagedSimpleAdd@AddWrapper@@$$FQ$AAM@XZ)" verwiesen wird. %path%\AddWrapper\AddWrapper.obj AddWrapper Fehler 4 error LNK2028: Nicht aufgel÷stes Token (0A00000C) ""public: __thiscall SimpleAdd::~SimpleAdd(void)" (??1SimpleAdd@@$$FQAE@XZ)", auf das in Funktion ""public: void * __thiscall SimpleAdd::
scalar deleting destructor'(unsigned int)" (??_GSimpleAdd@@$$FQAEPAXI@Z)" verwiesen wird. %path%\AddWrapper\AddWrapper.obj AddWrapper Fehler 5 error LNK2019: Verweis auf nicht aufgel÷stes externes Symbol ""public: __thiscall SimpleAdd::SimpleAdd(void)" (??0SimpleAdd@@$$FQAE@XZ)" in Funktion ""public: __clrcall AddWrapper::ManagedSimpleAdd::ManagedSimpleAdd(void)" (??0ManagedSimpleAdd@AddWrapper@@$$FQ$AAM@XZ)". %path%\AddWrapper\AddWrapper.obj AddWrapper Fehler 6 error LNK2019: Verweis auf nicht aufgel÷stes externes Symbol ""public: __thiscall SimpleAdd::~SimpleAdd(void)" (??1SimpleAdd@@$$FQAE@XZ)" in Funktion ""public: void * __thiscall SimpleAdd::
scalar deleting destructor'(unsigned int)" (??_GSimpleAdd@@$$FQAEPAXI@Z)". %path%\AddWrapper\AddWrapper.obj AddWrapper Fehler 7 error LNK1120: 4 nicht aufgel÷ste Externe %path%\Debug\AddWrapper.dll 1 1 AddWrapper
Now, what could be the cause of these errors? Is it the platform-befuddeledness of the lib? Did I miss to specify something else?
Upvotes: 0
Views: 2072
Reputation: 67080
What do I have to to to make DependencyWalker stop showing this error
Do not compile to a lib file! It's not an executable and it's not a dynamic link library so it has not PE signature. You can build a static library and link it inside your C++/CLI assembly (if you wish so) or you can simply put all that code inside your C++/CLI assembly. Up to you.
what could be the cause of these errors?
You directly included header file, let me highlight your code:
class _declspec(dllexport) SimpleAdd
As you can see you're actually compiling with _declspec(dllexport)
, you're not telling the compiler to import such class from a library but that you're exporting it (and linker will complain because you declared that class but there is not any implementation). When you include a class it has to be declared with _declspec(dllimport)
.
class _declspec(dllimport) SimpleAdd
Usually this trick is done with preprocessor macros. Let me make a simplified example. In your SimpleAdd.h
file you can declare:
#if defined(SIMPLEADD_LIB)
#define SIMPLEADD_EXPORTED _declspec(dllexport)
#else
#define SIMPLEADD_EXPORTED _declspec(dllimport)
#endif
Then change your code to
class SIMPLEADD_EXPORTED SimpleAdd
In your SimpleAdd
project you define a macro (from Project settings) named SIMPLEADD_LIB
. This will cause your library to be built with dllexport
(because from library you export that class) but in your C++/CLI wrapper to be declared as dllimport
(right because SIMPLEADD_LIB
isn't declared and there you're importing that class).
Upvotes: 2