Link a C++/CLI library in a CLR console project - c++

I see on a question that it wasn't possible to link a static C++/CLI library, so I generated a dynamic one and try to link it in a C++ CLR console project with no success
I get:
Error 1 error LNK2020: unresolved token (06000001) cBox::.ctor pTest9.obj
I put the dll (Project ->reference->add new reference) set the include files in the project
(include file with no code)
I don't know what to do (I am new with the C++/CLI)
thanks for suggestions/solution
Library Project declared as DLL
#include "stdafx.h"
using namespace System;
ref class cBox
{
public:
cBox() ;
cBox(double lv,double bv,double hv);
double Volume();
private:
double Length;
double Width;
double Height;
};
CODE OF THE LIBRARY :
#include "stdafx.h"
#include "cBox.h"
cBox::cBox()
{
Console::WriteLine(L"No arg constructor called");
Length = 1.0 ;
Width = 1.0 ;
Height = 1.0 ;
}
cBox::cBox(double lv,double bv,double hv)
{
Console::WriteLine(L"Constructor called");
Length = lv;
Width = bv;
Height = hv;
}
double cBox::Volume()
{
return Length*Width*Height;
}
Then in the Console CLR Project I try to link this library, I get its .h file
#include "stdafx.h"
#include "cBox.h"
using namespace System;
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Test Library:\n");
cBox^ oBox; // handle of type box
oBox = gcnew cBox;
Console::WriteLine(L"Default Box Volume {0}",oBox->Volume());
return 0;
}

You need to make a couple of changes to get this to work. First, you need to make the class public so your application can use it:
public ref class cBox
{
...
And you need to remove the #include "cBox.h" from your console application project; the inclusion is implicit when using managed libraries.

Related

EntryPointNotFoundException With Unity Plugin

I'm very new to writing c++ plugins for unity but must do so now. I have been loosely following this tutorial and created the following in a visual studio dll project uncreatively called UnityPluginTest:
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#define DLLExport __declspec (dllexport)
extern "C"
{
DLLExport int RandomNumber(int min, int max)
{
srand((unsigned int)time(0));
return (rand() % (max - min) + min);
}
}
I created a completely new unity project to test it (Unity 2020.2.f1 if it matters), and copied the compiled .dll file into a new folder Assets/Plugins. I then made a new script called (equally uncreatively) TestFirstUnityPluginTest.cs which contains the following:
using System.Runtime.InteropServices;
using UnityEngine;
public class TestFirstUnityPluginTest : MonoBehaviour
{
const string dll = "__Internal";
[DllImport(dll)]
private static extern int RandomNumber(int min, int max);
void Start()
{
Debug.Log(RandomNumber(0, 10));
}
}
When I put the script on a gameobject and hit play, I get an error stating "EntryPointNotFoundException: RandomNumber" with a stack trace pointing to the Debug.Log() call. Any ideas what I might be doing wrong? Thank you in advance.
You should specify entry point and use DECORATED name:
replace [DllImport(dll)] by [DllImport("YOUR_DLL_NAME.dll", EntryPoint = "DecoratedFunctionName")]
My C++ code:
__declspec(dllexport) int Double(int number)
{
return number * 2;
}
My Unity3d C# code:
[DllImport("Dll4_CPP.dll", EntryPoint = "?Double##YAHH#Z")]
public static extern int Double(int number);
void Start()
{
Debug.Log(Double(10));
}
Decorated name - name of the function inside DLL (compiler renames it).
Dumpbin.exe helps to find it:
VisualStudion2019 -> Tools -> CommandLine -> DeveloperComandPrompt
cd <your PathToDLL>
dumpbin /exports Dll4_CPP.dll
it will print:
...
1 0 00011217 ?Double##YAHH#Z = #ILT+530(?Double##YAHH#Z)
...
Source

MFC C++ static library linked with non MFC console app

I'm trying to compile a console program that uses a static library implementing CString.The console app has been created with the VS wizard with :
Win32 console application with precompiled headers, SDL verification but without ATL or MFC.
The static library is a MFC static library (wizard construction).
Where is (are) my mistake(s) ?
This is what I so long have tried:
I've created a new console app using MFC controls - this compile fine with the static library.
Then I've controlled and modified when necessary every link options, comparing the 2 console projects.
But the 1st console application does not compile.
I'm stucked !
I'm working with Visual Studio 2012 on Windows 10.
Here is the code :
File TestLib.h
#pragma once
#include <atlstr.h>
class TestLib
{
public:
TestLib(){};
TestLib(const CString &tst);
virtual ~TestLib(void);
private:
CString _tst;
};
Fichier TestLib.cpp
#include "stdafx.h"
#include "TestLib.h"
TestLib::TestLib(const CString &tst)
: _tst(tst)
{
}
TestLib::~TestLib(void)
{
}
Fichier ConsoleTest2.cpp
// ConsoleTest2.cpp : définit le point d'entrée pour l'application console.
#include "stdafx.h"
#include "TestLib.h"
int _tmain(int argc, _TCHAR* argv[])
{
TestLib *tst = new TestLib(); // This compile fine !
//TestLib *tst = new TestLib(_T("Test")); // This generates LNK2019 link error
return 0;
}
Here is the solution, thanks to Jochen Arndt
Just have to change the TestLib declaration to
TestLib::TestLib(LPCTSTR str)
: _tst(str)
{
}

Use C++/CLI Library in C++ native code and how to link

I want to use some code that executes a http-post, and because I'm not too familiar with c++ and what libraries you can use, and I am probably too dumb to get libcurl and curlpp to work, I found a link explaining how to use the .net version.
Alright so I created a class. Header File:
public ref class Element
{
public:
Element();
virtual ~Element();
void ExecuteCommand();
};
Class file:
#include "Element.h"
Element::Element()
{
}
Element::~Element()
{
Console::WriteLine("deletion");
}
void Element::ExecuteCommand(){
HttpWebRequest^ request = dynamic_cast<HttpWebRequest^>(WebRequest::Create("http://www.google.com"));
request->MaximumAutomaticRedirections = 4;
request->MaximumResponseHeadersLength = 4;
request->Credentials = gcnew NetworkCredential("username", "password", "domain");
HttpWebResponse^ response = dynamic_cast<HttpWebResponse^>(request->GetResponse());
Console::WriteLine("Content length is {0}", response->ContentLength);
Console::WriteLine("Content type is {0}", response->ContentType);
// Get the stream associated with the response.
Stream^ receiveStream = response->GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader^ readStream = gcnew StreamReader(receiveStream, Encoding::UTF8);
Console::WriteLine("Response stream received.");
Console::WriteLine(readStream->ReadToEnd());
response->Close();
readStream->Close();
}
If I set the configuration type of this project to Application (exe), and create a new .cpp file where I create an Instance of this Element it works fine.
But my question is: Is it possible to create a .dll/.lib Library from this project and use it in a C++ project without CLI? (I don't want to use ^ for pointers :( )
Even if it's not possible, I have another problem.
When I link the library in a C++/CLI project. I get
unresolved token (06000001) Element::.ctor
unresolved token (06000002) Element::~Element
unresolved token (06000003) Element::ExecuteCommand
3 unresolved externals
the code for main.cpp in the second project is just the following:
#include <Element.h>
int main(){
return 0;
}
Thank you
As Hans Passant already stated: you must compile your C++/CLI code as Dynamic Library in order to be able to consume it from an unmanaged application. CLI/Managed code cannot run from/cannot reside in static libraries.
If you change the C++/CLI library target from Static library to Dynamic library you'll be able to compile successfully your unmanaged C++ application.
One thought from my side:
I think you'll be better if you use mixed mode C++/CLI DLLs to consume the managed functionality - you'll be able to free your consumer application completely from referencing the CLR.
The Header of such mixed mode Wrapper for your Element class would look like this:
#pragma once
#pragma unmanaged
#if defined(LIB_EXPORT)
#define DECLSPEC_CLASS __declspec(dllexport)
#else
#define DECLSPEC_CLASS __declspec(dllimport)
#endif
class ElementWrapperPrivate;
class __declspec(dllexport) ElementWrapper
{
private:
ElementWrapperPrivate* helper;
public:
ElementWrapper();
~ElementWrapper();
public:
void ExecuteCommand();
};
And the implementation would look like this:
#include "ElementWrapper.h"
#pragma managed
#include "Element.h"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class ElementWrapperPrivate
{
public:
msclr::auto_gcroot<Element^> elementInst; // For Managed-to-Unmanaged marshalling
};
ElementWrapper::ElementWrapper()
{
helper = new ElementWrapperPrivate();
helper->elementInst = gcnew Element();
}
ElementWrapper::~ElementWrapper()
{
delete helper;
}
void ElementWrapper::ExecuteCommand()
{
helper->elementInst->ExecuteCommand();
}
Then just compile your Element.cpp + ElementWrapper.cpp to a DLL and use the ElementWrapper.h in your unmanaged applications.

managed c to call an unmanaged c dll , unresolved token

I have 1 native c++ dll, CppApp, another project is managed c++, GatWayLibrary, with /clr
In GatewayLibrary, I called functions from native CppApp dll.
but I got unresolve token errors.
Here are my code snips:
CppApp.h
=========
#ifdef CPPAPP_EXPORTS
#define CPPAPP_API __declspec(dllexport)
#else
#define CPPAPP_API __declspec(dllimport)
#endif
class CPPAPP_API CppApp
{
public:
CppApp();
~CppApp();
ContextManager & contextMgr() { return m_rplContextMng; }
INativeListener* m_listener;
void registerListener(INativeListener* listener)
{
m_listener = listener;
}
...........
}
In separate project, GateWaylibrary, wrap the native dll as
#include "../CppApp/CppApp.h"
#include <vcclr.h>
using namespace System;
using namespace System::Runtime::InteropServices;
#pragma comment(lib, "CppApp.lib")
namespace GatewayLibrary{
//.net equvelant of the argument class
public ref class DotNetEventArg{
internal:
//contructor takes native version of argument to transform
DotNetEventArg(const NativeCPPArgs& args) {
....
...
}
the managed c++ has the linking errors as unresolved tokens for all the function calls from the native c++.
I did include the CppApp.lib as Additional Dependencies
and the directory.
Can anyone please help? many thanks ahead.
Edit:
here is of the place I called the native c++
`GatewayLibrary::EventGateway::EventGateway()
{
nativeCode_ = new CppApp();
//note; using 'this' in ctor is not a good practice
nativeListener_ = new NativeListenerImp(this);
//register native listener
nativeCode_->registerListener(nativeListener_);
}`

Multiple definition of the same symbol in C++ (visual studio)

I'm having an issue with a pretty simple code
I am following the tutorial of chrono::engine http://www.chronoengine.info/mediawiki/index.php/Demo_fourbar
I do not have much experience in C++ programming (I have some experience in Java), therefore I tried to define MyEventReceiver (a class from the tutorial) in a different file (MyEventReceiver.h and MyEventReceiver.cpp) to get my head around classic structure of a C++ code
Here is the version of the code
MyEventReceiver.h
#ifndef RECEIVER_H
#define RECEIVER_H
#include "physics/CHapidll.h"
#include "physics/CHsystem.h"
#include "irrlicht_interface/CHbodySceneNode.h"
#include "irrlicht_interface/CHbodySceneNodeTools.h"
#include "irrlicht_interface/CHdisplayTools.h"
#include "irrlicht_interface/CHirrWizard.h"
#include "core/CHrealtimeStep.h"
#include <irrlicht.h>
// Use the namespace of Chrono
using namespace chrono;
// Use the main namespaces of Irrlicht
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(ChSystem* asystem, IrrlichtDevice* adevice, ChSharedPtr<ChLinkEngine> aengine);
bool OnEvent(const SEvent& event);
void setText_enginespeed(IGUIStaticText* _text_enginespeed);
IGUIStaticText* getText_enginespeed();
private:
IGUIStaticText* text_enginespeed;
ChSystem* msystem;
IrrlichtDevice* mdevice;
ChSharedPtr<ChLinkEngine> mengine;
};
#endif
with the implementation as follows in MyEventReceiver.cpp
#include "MyEventReceiver.h"
// Constructor
MyEventReceiver::MyEventReceiver(ChSystem *asystem, IrrlichtDevice *adevice, ChSharedPtr<ChLinkEngine> aengine)
{
// store pointer to physical system & other stuff
// so we can tweak them by user keyboard
msystem = asystem;
mdevice = adevice;
mengine = aengine;
}
bool MyEventReceiver::OnEvent(const SEvent& event)
{
// check if user moved the sliders with mouse..
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
IGUIEnvironment* env = mdevice->getGUIEnvironment();
switch(event.GUIEvent.EventType)
{
case EGET_SCROLL_BAR_CHANGED:
if (id == 101) // id of 'engine speed' gui
{
s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
double newspeed = 10*(double)pos/100.0;
// set the speed into engine object
ChFunction_Const *spe_funct = dynamic_cast <ChFunction_Const*> (mengine->Get_spe_funct());
spe_funct->Set_yconst(newspeed);
// show speed as formatted text in interface screen
char message[50]; sprintf(message,"Engine speed: %g [rad/s]",newspeed);
text_enginespeed->setText(core::stringw(message).c_str());
}
break;
}
}
return false;
}
void MyEventReceiver::setText_enginespeed(IGUIStaticText* _text_enginespeed)
{
text_enginespeed = _text_enginespeed;
}
IGUIStaticText* MyEventReceiver::getText_enginespeed()
{
return text_enginespeed;
}
and the main file in Main_2.cpp (which I emptied, it gives me the same error with or without the code inside - which is basically only setting up the 3D engine Irrlicht and some mechanics features from the collision model of chrono::engine)
#include "MyEventReceiver.h"
int main()
{
return 0;
}
Basically the code defines an event receiver, so that the user after running the program can interact with the 3D environment built from the chrono::engine and Irrlicht engine through GUI manipulation
I define all the required libraries in the MyEventReceiver.h file and the required namespaces
The problem is that it does not compile (please note that I already tested the engines - with the same #include and using namespaces in just one file and it was working in a different project - ), i think the problem is coming from the structure of the header files
I got those lines of error
1>MyEventReceiver.obj : error LNK2005: "public: virtual bool __thiscall irr::scene::RTSCamera::OnEvent(struct irr::SEvent const &)" (?OnEvent#RTSCamera#scene#irr##UAE_NABUSEvent#3##Z) already defined in Main_2.obj
1>MyEventReceiver.obj : error LNK2005: "public: virtual void __thiscall irr::scene::RTSCamera::OnRegisterSceneNode(void)" (?OnRegisterSceneNode#RTSCamera#scene#irr##UAEXXZ) already defined in Main_2.obj
etc... (it goes on like this)
and the final mistake
1>C:\Users\****\Documents\Visual Studio 2010\Projects\TutorialChronoEngine\Debug\TutorialChronoEngine_2.exe : fatal error LNK1169: one or more multiply defined symbols found
I am using Visual Studio 2010 C++. I defined one global solution, and several projects in this very solution (the program I wrote above is one project among others)
I am sure it must be pretty easy to solve, but can't really find the solution. Let me know if you need further details
Thanks a lot
Best regards
Vincent
Edit : If I put all the codes in one single file as follows
#include "physics/CHapidll.h"
#include "physics/CHsystem.h"
#include "irrlicht_interface/CHbodySceneNode.h"
#include "irrlicht_interface/CHbodySceneNodeTools.h"
#include "irrlicht_interface/CHdisplayTools.h"
#include "irrlicht_interface/CHirrWizard.h"
#include <irrlicht.h>
// Use the namespace of Chrono
using namespace chrono;
// Use the main namespaces of Irrlicht
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
// Get rid of the command windows that pops up when compiling and running
#ifdef _IRR_WINDOWS_
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
IGUIStaticText* text_enginespeed = 0;
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(ChSystem* asystem,
IrrlichtDevice *adevice,
ChSharedPtr<ChLinkEngine> aengine)
{
// store pointer to physical system & other stuff
// so we can tweak them by user keyboard
msystem = asystem;
mdevice = adevice;
mengine = aengine;
}
bool OnEvent(const SEvent& event)
{
// check if user moved the sliders with mouse..
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
IGUIEnvironment* env = mdevice->getGUIEnvironment();
switch(event.GUIEvent.EventType)
{
case EGET_SCROLL_BAR_CHANGED:
if (id == 101) // id of 'engine speed' gui
{
s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
double newspeed = 10*(double)pos/100.0;
// set the speed into engine object
ChFunction_Const *spe_funct = dynamic_cast <ChFunction_Const*> (mengine->Get_spe_funct());
spe_funct->Set_yconst(newspeed);
// show speed as formatted text in interface screen
char message[50]; sprintf(message,"Engine speed: %g [rad/s]",newspeed);
text_enginespeed->setText(core::stringw(message).c_str());
}
break;
}
}
return false;
}
private:
ChSystem* msystem;
IrrlichtDevice* mdevice;
ChSharedPtr<ChLinkEngine> mengine;
};
int main(int argc, char* argv[])
{
return 0;
}
In that way, I avoid defining several times functions from the Irrlicht 3D engine that are not defined as inline. Unfortunately, this way of coding can become really cumbersome if a project becomes big (having to define all classes that rely on the 3D engine in one unique .cpp file), is there a design pattern to follow so that it is possible to avoid multiple defined objects with each class defined in a separate file ?
Thanks a lot
Best
Vincent
The linker is complaining about two of your functions being defined multiple times. As you could probably figure out from the errors, these functions are:
irr::scene::RTSCamera::OnEvent(struct irr::SEvent const &)
irr::scene::RTSCamera::OnRegisterSceneNode(void)
What's most likely happening here is that these two functions are defined in a header file, but:
Their definition does not appear directly in the class definition (so they are not implicitly declared to be inline);
Their out-of-class definition in the header file is not explicitly marked as inline.
As a result, if the header is included multiple times in different translation units (i.e. in different .cpp files), multiple definitions of the same functions will end up being present in the object code of those translation units.
When merging them, the linker will complain that you are breaking the ODR (One Definition Rule).