How to use a struct defined in C++ CLR in unmanaged C++? - c++

I have a struct defined in Managed.h and I would like to be able to use it inside a different project, which is unmanaged C++ (let's call it Unmanaged.h).
I tried referencing the dll, a few different #includes, but I couldn't make it work. Is there a simple way to do this ?
For information : I am quite new to C++ programming (I do C# usually), and I use Visual Studio 2015.

It would be useful to see some code and the error message that you are seeing. But as a basic example:
CLR file containing the struct. Call it MyStruct.h:
using namespace System;
namespace ManagedNameSpace {
public value struct MyStruct {
void f() {
System::Console::WriteLine("test");
}
};
}
The unmanaged class includes the CLR struct and as an explicit example I have called the object in the constructor but you can easily move this to an implementation file (Remember to include the file in the header):
#include "MyStruct.h"
class UnManagedClass {
public:
explicit UnManagedClass() {
ManagedNameSpace::MyStruct clrObj;
clrObj.f();
std::cout << "This compiles fine";
}
};
Take note that certain CLR types require marshalling. For example String will need to be marshalled. Here is an example of converting a string to LPCWSTR
LPCWSTR lpcwStr = (LPCWSTR)(Marshal::StringToHGlobalUni(clrString)).ToPointer()

Related

C++/CLI wrapper can't use vector from native C++ dll

I have a project that goes like this: C++ -> C++/CLI wrapper -> C# app.
I have an exported class called Drawing in the C++ dll, .h contains a static std::vector<void*>, the vector is defined in the .cpp file.
The problem is that I'm getting the following errors:
Errors
C++'s native dll .lib file is linked to the wrapper, and generally the wrapper works with other stuff, but once I add the std::vector, it starts throwing linker errors.
I tried creating a function in the C++ dll that has void* as an argumument and added to the list "internally", but I still got the same errors kind of:
Errors
Any kind of help is appreciated
Answer extending my comment.
You could try to wrap the std::vector<void*> into simpler structure with functionalities you really need like following:
class YourClass
{
private:
std::vector<void*> _vec;
public:
// implement functionalities you need
void add(void* elem)
{
_vec.add(elem);
}
// etc.
};
or by inheritance:
class YourClass : public std::vector<void*>
{
public:
YourClass(int size)
: std::vector<void*>(size) {}
};

C++ on Visual Studio 2010: Cannot assign string to a string (mixed types are not supported)

I'm trying to do something very simple... declare a string in a class, and then assign it to the value of another string defined in a class constructor.
I am using a managed wrapper for an unmanaged class "Unmanaged" (using a managed wrapper because I want to use it in a C# program, and something I am using is unmanaged and its .sln file is not under my control)
As you can see, I tried including as many string headers as possible.
#pragma once
#include <string>
#include <string.h>
#include <cstring>
#include <iostream>
using namespace std;
using namespace System;
using std::string;
namespace UnmanagedWrap {
public ref class Class1
{
// TODO: Add your methods for this class here.
public:
Unmanaged *pu; //pointer to the Unmanaged class
//the constructor will allocate the pointer pu
int a;
int b;
std::string filePath; //try CString() when get back
Class1(int a_In, int b_In, std::string filePath_In) : pu(new Unmanaged()) { //constructor
a = a_In;
b = b_In;
filePath = filePath_In; //trying to assign filePath to the inputted filePath_In.......
}; //end of constructor
This is giving me 2 errors:
The first relates to the line std::string filePath;
1>c:\users\ngrace\documents\visual studio 2010\projects\unmanagedwrap\unmanagedwrap\UnmanagedWrap.h(21): error C4368: cannot define 'filePath' as a member of managed 'UnmanagedWrap::Class1': mixed types are not supported
The second relates to the line filePath = filePath_In;
1>c:\users\ngrace\documents\visual studio 2010\projects\unmanagedwrap\unmanagedwrap\UnmanagedWrap.h(25): error C2678: binary '=' : no operator found which takes a left-hand operand of type 'std::string' (or there is no acceptable conversion)
I am very lost as I have spent hours searching for an answer...
Some pages I have gone to for help:
Including headers from an unmanaged C++ code inside C++/CLI code
Mixed types are not supported
(I would post more but I need reputation of at least 10 to do so....)
Any ideas on why I'm getting these errors?
Using information from Bo Persson and user2666293, I was led to try something, which ended up being an answer to this.
You must use System::String^ type for managed strings. If using a managed string and passing it to a method in an unmanaged class, it must be converted to an unmanaged string type!
Let's say we're using the unmanaged string type std::string in the unmanaged class.
The conversion from System::String^ to std:string must be done using:
auto unmannedString = msclr::interop::marshal_as<std::string>(managedString);
and with a header file reference at the top of:
#include <msclr/marshal_cppstd.h>
where managedString is of type System::String^
:)
https://msdn.microsoft.com/en-us/library/hh699870.aspx says under bullet 2 that ref classes can only have standard c++ types if they are not public. Try using a regular class or making filePath private.
edit:
I'm not familiar with managed classes but you might try Platform::string instead of std::string : https://msdn.microsoft.com/en-us/library/hh755812.aspx
https://msdn.microsoft.com/en-us/library/hh699879.aspx
says to use platform strings when you pass strings back and forth to methods in Windows Runtime classes, or when you are interacting with other Windows Runtime components

How to make a managed (clr) multithreaded c++ .dll?

I am trying to make a managed .dll in c++ that requires the support for multithreading. I am developing in visual Studio 2013, using platform toolset version v120. the reason I need this to be a managed assembly is because it is required to integrate the assembly in LabView.
following the steps in Creating and Using a Managed Assembly in VC++ 2010 gives good results. but I obviously need to implement something more complicated and when I include threading and write the following code:
#pragma once
#include <thread>
using namespace System;
using namespace std;
namespace MultiThread_module {
public ref class multiThreadingTest
{
public:
String^ GetVersion();
int someNumber;
private:
thread testThread;
};
}
I get following errors:
"thread" is not supported when compiling with /clr or /clr:pure.
a member of a managed class cannot be of a non-managed class type
error directive: ERROR: Concurrency Runtime is not supported when
compiling /clr.
error directive: is not supported when compiling with /clr or
/clr:pure.
A friend of mine says it is impossible to write multi-threaded code in Visual Studio without using external packages like boost. It kind of seemed unlikely since Multithreading has already been already there for C# and VB for a long time!
So, I would be happy if you could let me know what I am doing wrong OR if it is really hard to have a managed multithreaded .dll developed in c++?
You can use the managed thread library: System.Threading.Thread.
#pragma once
using namespace System;
using namespace std;
using namespace System::Threading;
namespace MultiThread_module {
public ref class multiThreadingTest
{
public:
String^ GetVersion();
int someNumber;
private:
Thread^ testThread;
};
}
If it's purely CLR then I suggest you use the example provided before. If you want to have the threading completely native and just use CLR to wrap it, I'd like to refer you to my answer at : using clr and std::thread
Might be an old question, but I looked into this same problem before. Since CLR does not allow you to include std::thead at
compile time, you could try to use it only at linking time. Normally
you could resolve this be forward declaring the class in your header
and including them only in your cpp files. However you can forward
declare your own classes in header files, but you can't for
classes in namespace std. According to the C++11 standard, 17.6.4.2.1:
The behavior of a C++ program is undefined if it adds declarations or
definitions to namespace std or to a namespace within namespace std
unless otherwise specified.
A workaround for this problem is to create a threading class that
inherits from std::thread that you can forward declare. The header
file for this class would look like:
#pragma once
#include <thread>
#include <utility>
namespace Threading
{
class Thread : std::thread
{
public:
template<class _Fn, class... _Args> Thread(_Fn fn, _Args... args) : std::thread(fn, std::forward<_Args...>(args...))
{
}
private:
};
}
In the header file that you would like to use the thread you can do
forward declare it like:
#pragma once
// Forward declare the thread class
namespace Threading { class Thread; }
class ExampleClass
{
public:
ExampleClass();
void ThreadMethod();
private:
Threading::Thread * _thread;
};
In your source file you can then use the theading class like:
#include "ExampleClass.h"
#include "Thread.h"
ExampleClass::ExampleClass() :
{
_thread = new Threading::Thread(&ExampleClass::ThreadMethod, this);
}
void ExampleClass::ThreadMethod()
{
}
Hope it might help anyone.

Why can't we pass a reference from native C++ to C++/CLI?

I use a native C++ code base from C#, with a C++/CLI wrapper built around it (with Visual Studio 2013). There are two projects:
NativeCodeBase: simple C++ project set to be built into a static lib.
ManagedWrapper: C++/CLI project referencing NativeCodeBase.
I have the following native "interface" in NativeCodeBase:
class ITest {
virtual void Foo(const std::string& str, MyEnum me) = 0;
}
For which I have a native implementation in the ManagedWrapper project.
In the header:
class TestManaged : public ITest {
virtual void Foo(const std::string& str, MyEnum me) override;
}
In the cpp:
void TestManaged::Foo(const std::string& str, MyEnum me) {
int length = str.length();
}
The MyEnum enum is used both in native and managed code, so in its implementation I use a conditionally compiled C++/CLI extension, to make it usable from C#:
#ifdef _MANAGED
public
#endif
enum class MyEnum : unsigned char
{
Baz = 0,
Qux = 1
};
In my native code I have a reference to ITest and call its Foo function with a local std::string variable. When Foo is called, I can see in the debugger that the string passed as an argument is a valid string object.
The call is similar to this:
void Bar(ITest& test) {
std::string str = "test";
test.Foo(str, MyEnum::Baz);
}
However, if I put a breakpoint at the beginning of TestManaged::Foo, the debugger says that str has <undefined value>, and the length() call crashes with undefined reference error in the <xstring> header in the following function:
size_type length() const _NOEXCEPT
{ // return length of sequence
return (this->_Mysize);
}
The debugger displays <undefined value> for the this pointer as well.
What can be the reason for this? References somehow get corrupted when passed between the two libraries?
(Additional info: I used not to build the NativeCodeBase project as a separate lib, but linked all the source files from it into the CLI project, and the same code base worked without any problem. It started failing since I configured it to be built into a separate lib and added a reference in the CLI project to the native one.)
The problem wasn't with the reference itself. The problem was with the second enum parameter. The implementation of the enum class looked like this:
#ifdef _MANAGED
public
#endif
enum class MyEnum : unsigned char
{
Baz = 0,
Qux = 1
};
The #ifdef directive was put there in order to create a native enum when built for native C++, but create a CLI enum when built for C++/CLI.
This worked well when all the source files were linked to the CLI project and every piece of source was built again for the CLI project. However, this approach does not work any more when I want to use the native lib from the CLI side.
I guess the problem was that the same header was built differently in the two libraries, so the caller and the calle saw a different binary interface of the object, thus the arguments got garbled when passed. Is this correct?
I got rid of the conditionally compiled public keyword and it started working properly again.

How to wrap a C++ class in a C based dll or a CLI based dll?

I am told to import my writen class in C++ into a dll and then use that dll in a c# application. Following this guide I created the dll, but I can't simply use it in a C# application since there are some issues concerning it:
What should I place for the return type of my factory function?
What is the equivalent of const wchar_t* which is my constructors argument type?
How can I retrieve and use my functions return type which is of type vector< wstring>?
These are the problems that prevent me from using my C++ DLL inside my C# applications. I was told that I need to create a wrapper with C++/CLI and then use that inside my C#. But sadly I have no idea about it, I don't know C++.net.
The only thing that currently seems to be a bit more sensational to me is to make it somehow compatible with C and then create a C DLL and use that in my C# application. I have read that in C, class object pointers are accessible through HANDLEs, so I thought that would be good idea to get things going without a lot of changes.
So the question is how can I use Handles to access my class objects in C and use them? And how can I convert a vector<wstring> to its C counterpart?
If I want to use CLI to create a wrapper (DLL?) for my C++ DLL, to be used in other dotnet apps what should I do?
In order to make a C wrapper for a C++ class to be used in for example a C# application you can do the following.
In Visual Studio choose Win32 Console Application and Enter a name, Then click next and on the next pane choose DLL and click finish. When you are done you are represented with a DLL project including 3 files.
testdll.h
testdll.cpp
dllmain
Delete everything that exists inside your testdll.h and testdll.cpp files and copy the following contents to each respectively. Add these lines to your testdll.h
// Our C wrapper for creating a dll to be used in C# apps
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the TESTDLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// TESTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
}
It is inside this extern "C" block where you define your interface, functions to access your class member functions.Note the TESTDLL before the function prototype. All of your functions must be proceeded by that.
Add these to your testdll.cpp file:
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
return ourObject.Add(x,y);
}
}
You compile this and get a C based dll which can be used in a C# application.
There are couple of things to notice though, The more important ones are:
You need to understand that the code you use as a proxy- i mean
function definition inside your testdll.h, must only use C
compatible types, it is C after all not C++.
is that you would want to be able to allocate new objects of your
class instead of just using one global object to access all methods.
For this, if you need to pass your class objects between member functions, you need to first convert it to a void* which C can understand and then pass it and use it to access your member functions of whatever.
For example I would have something like this inside my testdll.h in order to make user capable of managing the objects indirectly:
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
TESTDLL_API void* CreateHandle();
TESTDLL_API void* GetCurrentHandle();
TESTDLL_API void DisposeCurrentHandle();
TESTDLL_API void SetCurrentHandle(void* handle);
TESTDLL_API void* GetHandle();
TESTDLL_API void DisposeHandle(void*);
TESTDLL_API void DisposeArrayBuffers(void);
}
And inside my testdll.cpp I would define them as :
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass *ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
//return ourObject.Add(x,y); -- not any more !!
ourObject = reinterpret_cast<OurClass *>(GetHandle());
}
//Handle operations
TESTDLL_API void* CreateHandle()
{
if (ourObject == nullptr)
{
ourObject = new OurClass ;
}
else
{
delete ourObject ;
ourObject = new OurClass ;
}
return reinterpret_cast<void*>(ourObject);
}
TESTDLL_API void* GetCurrentHandle()
{
return reinterpret_cast<void*>(ourObject );
}
TESTDLL_API void DisposeCurrentHandle()
{
delete ourObject ;
ourObject = nullptr;
}
TESTDLL_API void SetCurrentHandle(void* handle)
{
if (handle != nullptr)
{
ourObject = reinterpret_cast<OurClass *>(handle);
}
else
{
ourObject = new OurClass ;
}
}
//factory utility function
TESTDLL_API void* GetHandle()
{
void* handle = GetCurrentHandle();
if (handle != nullptr)
{
return handle;
}
else
{
ourObject = new OurClass ;
handle = reinterpret_cast <void*>(ourObject );
}
return handle;
}
CDLL_API void DisposeHandle(void* handle)
{
OurClass * tmp = reinterpret_cast<OurClass *>(handle);
delete tmp;
}
TESTDLL_API void DisposeArrayBuffers(void)
{
ourObject = reinterpret_cast<OurClass *>(GetHandle());
return ourObject ->DisposeBuffers();//This is a member function defined solely for this purpose of being used inside this wrapper to delete any allocated resources by our class object.
}
}
And when we compile this Dll, we can easily work with it inside our C# application. Before being able to use our functions defined in this dll we need to use appropriate [ImportDll()]. So for our TestDll we would write:
[DllImport(#"TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int OurTestFunction(int firstNumber,int secondNumber);
And finally use it like:
private void btnReadBigram_Click(object sender, EventArgs e)
{
int x = OurTestFunction(10,50);
MessageBox.Show(x.ToString());
}
This is all I did to make my C++ class member functions accessible inside a C# application without any hassle.
Note:
When compiling your C# application make sure you have chosen the x86 Platform for compiling your project not AnyCpu.You can change your platform through properties.
Note 2:
For knowing how to create a C++/CLI wrapper for your native C++ class read this: C++/CLI wrapper for your native C++ class.
Using a native C++ class directly from C# is technically possible, but it's not trivial, and it's rarely even a good idea. For starters, you have to know the names to use to import from the DLL, which will be the names after C++ name-mangling. You also can't directly access things like vector from C#.
There are basically two good options:
The first is to write a DLL with a C interface that uses only types that can be marshalled into CLR types. You may use pointers along with the IntPtr type, but you can't really dereference those pointers. You can pretty much just store them in your C# code and then pass them back to the native DLL when needed. And you can also use simple struct types as long as you don't need deep copy to work on them. This option involves using P/Invoke.
The second option is to write a mixed-mode C++/CLI assembly that implements all the logic that needs to access your native code. This assembly can directly access classes and data from your C# code and also directly access your native code, although you should be forewarned that there are annoying breaks where you can't mix the two. For example, a ref class in C++/CLI can't have a shared_ptr member. However, it can have a raw C++ pointer as a member. A (mixed-mode) native class can also have access to a CLR handle type and make calls into the C# code through this. This option involves using C++ Interop.
It's worth noting that you could also go the other way with C++ Interop. You could have your C# code access a mixed-mode C++/CLI assembly that provides a .NET interface to some native code. However, you will still have to do some translation in this case so it's not hugely better than the first option.
A full tutorial on C++ Interop would be rather lengthy. I suggest you read up here and do some further investigation of C++ Interop on Google.
C++/CLI introduces managed objects, for which the pointer token * should be replaced with a ^, and a 'new' should be replaced with 'gcnew', you don't need to delete these objects when you're done with them, they'll be garbage collected, [edit] managed classes have a ref keyword in their definition [/edit].
Wrapping the C++ MyClass class in a C++/CLI wrapper class WrapperCLass could look something like this:
#include <stdio.h>
class MyClass
{
public:
void ShowStuff(const wchar_t *a)
{
wprintf(a);
}
};
public ref class WrapperClass
{
MyClass *wrapped;
public:
WrapperClass()
{
wrapped = new MyClass;
}
~WrapperClass()
{
delete wrapped;
}
void ShowStuff(IntPtr string)
{
wrapped->ShowStuff((const wchar_t *)string.ToPointer());
}
};
If you generate a dll with this, you'll be able to use it as a reference in your C# project
and you won't have to use the factory function mechanism.
In C++/CLI are available, so const wchar_t * is as wel.
To convert a System::String to a const wchar_t * you could use something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Client
{
class Program
{
static void Main(string[] args)
{
WrapperClass w = new WrapperClass();
IntPtr tmp;
w.ShowStuff(tmp = System.Runtime.InteropServices.Marshal.StringToHGlobalUni("Test"));
System.Runtime.InteropServices.Marshal.FreeHGlobal(tmp);
}
}
}
(There could very well be better ways to do this...)
For your return type you'll have to do the conversion in your wrapper class. Make some .net collection, iterate through your vector, convert the wstring to a System::String, and add it to the .net collection, and return that.