How to Call C++/Cli from C#

How do I call C++/CLI from C#?

Have you take a look at C++/CLI?

Let me give a very short example. Here is the source file from a Visual C++ -> CLR -> Class Library project. It basically get Windows username and return it.

Please note that, in order to get this compiled, you have to go into project settings and mark "Additional Dependencies" as "Inherit from parent" because we are using those Windows libs (kernel32.lib, user32.lib, ..)

// CSCPP.h

#pragma once

#include "windows.h"

using namespace System;

namespace CSCPP {

public ref class Class1
{
// TODO: Add your methods for this class here.
public:
String^ GetText(){
WCHAR acUserName[100];
DWORD nUserName = sizeof(acUserName);
if (GetUserName(acUserName, &nUserName)) {
String^ name = gcnew String(acUserName);
return String::Format("Hello {0} !", name);
}else{
return gcnew String("Error!");
}
}
};
}

Now created a new C# project and add reference to our first C++/CLI Class Library project. And then call the instance method.

namespace CSTester
{
class Program
{
static void Main(string[] args)
{
CSCPP.Class1 instance = new CSCPP.Class1();
Console.WriteLine(instance.GetText());
}
}
}

This gave the following result on my machine:

Hello m3rlinez !

C++/CLI is basically a managed extension over C++ standard. It allows you to utilize CLR classes and data types in your C++/CLI project and also expose this to managed language. You can created a managed wrapper for your old C++ library using this. There are some weird syntaxes such as String^ to define reference type to CLR String. I find "Quick C++/CLI - Learn C++/CLI in less than 10 minutes" to be useful here.

How to Use C++/CLI Within C# Application

Okay, well, I now feel dumb.

It turns out that the problem I was having (which I solved a couple weeks ago - just got around to updating this answer) was that I had included the header file (see Chris' answer for that), but I hadn't actually included the CPP file (which is empty other than including the header file).

Once I did this, the DLL compiled correctly and I could call the C++ functions (using C++/CLI) from my C# code.

How to call a C# library from Native C++ (using C++\CLI and IJW)

I found something that at least begins to answer my own question. The following two links have wmv files from Microsoft that demonstrate using a C# class in unmanaged C++.

This first one uses a COM object and regasm: http://msdn.microsoft.com/en-us/vstudio/bb892741.

This second one uses the features of C++/CLI to wrap the C# class: http://msdn.microsoft.com/en-us/vstudio/bb892742. I have been able to instantiate a c# class from managed code and retrieve a string as in the video. It has been very helpful but it only answers 2/3rds of my question as I want to instantiate a class with a string perimeter into a c# class. As a proof of concept I altered the code presented in the example for the following method, and achieved this goal. Of course I also added a altered the {public string PickDate(string Name)} method to do something with the name string to prove to myself that it worked.

wchar_t * DatePickerClient::pick(std::wstring nme)
{
IntPtr temp(ref);// system int pointer from a native int
String ^date;// tracking handle to a string (managed)
String ^name;// tracking handle to a string (managed)
name = gcnew String(nme.c_str());
wchar_t *ret;// pointer to a c++ string
GCHandle gch;// garbage collector handle
DatePicker::DatePicker ^obj;// reference the c# object with tracking handle(^)
gch = static_cast<GCHandle>(temp);// converted from the int pointer
obj = static_cast<DatePicker::DatePicker ^>(gch.Target);
date = obj->PickDate(name);
ret = new wchar_t[date->Length +1];
interior_ptr<const wchar_t> p1 = PtrToStringChars(date);// clr pointer that acts like pointer
pin_ptr<const wchar_t> p2 = p1;// pin the pointer to a location as clr pointers move around in memory but c++ does not know about that.
wcscpy_s(ret, date->Length +1, p2);
return ret;
}

Part of my question was: What is better? From what I have read in many many efforts to research the answer is that COM objects are considered easier to use, and using a wrapper instead allows for greater control. In some cases using a wrapper can (but not always) reduce the size of the thunk, as COM objects automatically have a standard size footprint and wrappers are only as big as they need to be.

The thunk (as I have used above) refers to the space time and resources used in between C# and C++ in the case of the COM object, and in between C++/CLI and native C++ in the case of coding-using a C++/CLI Wrapper. So another part of my answer should include a warning that crossing the thunk boundary more than absolutely necessary is bad practice, accessing the thunk boundary inside a loop is not recommended, and that it is possible to set up a wrapper incorrectly so that it double thunks (crosses the boundary twice where only one thunk is called for) without the code seeming to be incorrect to a novice like me.

Two notes about the wmv's. First: some footage is reused in both, don't be fooled. At first they seem the same but they do cover different topics. Second, there are some bonus features such as marshalling that are now a part of the CLI that are not covered in the wmv's.

Edit:

Note there is a consequence for your installs, your c++ wrapper will not be found by the CLR. You will have to either confirm that the c++ application installs in any/every directory that uses it, or add the library (which will then need to be strongly named) to the GAC at install time. This also means that with either case in development environments you will likely have to copy the library to each directory where applications call it.

How to call standalone C++/CLI function from C# code?

Create a class as seen in the tutorials and then let it have a static function. You cannot have free functions in C#. The function you created in C++ is just that... a C++ function without any CLI involved.

Call c# class from C++/CLI

You don't need __declspec(dllexport) for managed classes, as they are exported automatically unless you declare them private/internal. Just change the class signature like this:

public ref class clr

Also if you want to use this from C# you should use managed arrays in the signature of the calculate method:

String^ calculate(array<Double*>^ Robot_Points_Values, CameraSpacePoint* human_point_cloud, array<unsigned char*>^ bodyindexdata);

How to call C++/Cli function with ValueType argument from C#

I ended up calling the function as follows,

ValueType now = DateTime.Now;
StartRecording(ref now, "Path to file");

assigning DateTime object to ValueType resolved the problem.

Calling C# function from a C++/CLI function

Maybe this example can help you:

Write a Managed DLL

To create a simple managed DLL that has a public method to add two numbers and return the result, follow these steps:

Start Microsoft Visual Studio .NET or Microsoft Visual Studio 2005.
On the File menu, point to New, and then click Project. The New Project dialog box opens.
Under Project Types, click Visual C# Projects.

Note In Visual Studio 2005, click Visual C# under Project Types.
Under Templates, click Class Library.
In the Name text box, type sManagedDLL, and then click OK.
Open the Class1.cs file in Code view.
To declare a public interface that has a method to add two numbers, add the following code to the Class1.cs file:

// Interface declaration.
public interface ICalculator
{
int Add(int Number1, int Number2);
};

To implement this public interface in a class, add the following code to the Class1.cs file:

// Interface implementation.
public class ManagedClass:ICalculator
{
public int Add(int Number1,int Number2)
{
return Number1+Number2;
}
}

Register the Managed DLL for Use with COM or with Native C++
To use the managed DLL with COM or with native C++, you must register the assembly information of your DLL in the Windows registry. To do this, follow these steps:

Call the Managed DLL from Native C++ Code

// Import the type library.
#import "..\ManagedDLL\bin\Debug\ManagedDLL.tlb" raw_interfaces_only

Change the path of the type library if the path on your computer differs from this path.
To declare the namespace to use, add the following code to the CPPClient.cpp file:

using namespace ManagedDLL;

Complete Code Listing

  //Managed DLL
// Class1.cs
// A simple managed DLL that contains a method to add two numbers.
using System;

namespace ManagedDLL
{
// Interface declaration.
public interface ICalculator
{
int Add(int Number1, int Number2);
};

// Interface implementation.
public class ManagedClass:ICalculator
{
public int Add(int Number1,int Number2)
{
return Number1+Number2;
}
}
}

//C++ Client
// CPPClient.cpp: Defines the entry point for the console application.
// C++ client that calls a managed DLL.

#include "stdafx.h"
#include "tchar.h"
// Import the type library.

#import "..\ManagedDLL\bin\Debug\ManagedDLL.tlb" raw_interfaces_only
using namespace ManagedDLL;
int _tmain(int argc, _TCHAR* argv[])
{
// Initialize COM.
HRESULT hr = CoInitialize(NULL);

// Create the interface pointer.
ICalculatorPtr pICalc(__uuidof(ManagedClass));

long lResult = 0;

// Call the Add method.
pICalc->Add(5, 10, &lResult);

wprintf(L"The result is %d\n", lResult);

// Uninitialize COM.
CoUninitialize();
return 0;
}

Reference:
How to call a managed DLL from native Visual C++ code in Visual Studio.NET or in Visual Studio 2005

Invoke C++/CLI code from C#

Make sure your native code (C++) is compiled with the same format (32 bits or 64 bits) as the .Net execution format of your C# application(32 bits or 64 bits again). This may be the cause of your problem.

By default .Net executes itself in the same format as the OS. You can force execution in a chosen format by setting a compilation option in visual studio.



Related Topics



Leave a reply



Submit