Using a Class Defined in a C++ Dll in C# Code

using a class defined in a c++ dll in c# code

There is no way to directly use a C++ class in C# code. You can use PInvoke in an indirect fashion to access your type.

The basic pattern is that for every member function in class Foo, create an associated non-member function which calls into the member function.

class Foo {
public:
int Bar();
};
extern "C" Foo* Foo_Create() { return new Foo(); }
extern "C" int Foo_Bar(Foo* pFoo) { return pFoo->Bar(); }
extern "C" void Foo_Delete(Foo* pFoo) { delete pFoo; }

Now it's a matter of PInvoking these methods into your C# code

[DllImport("Foo.dll")]
public static extern IntPtr Foo_Create();

[DllImport("Foo.dll")]
public static extern int Foo_Bar(IntPtr value);

[DllImport("Foo.dll")]
public static extern void Foo_Delete(IntPtr value);

The downside is you'll have an awkward IntPtr to pass around but it's a somewhat simple matter to create a C# wrapper class around this pointer to create a more usable model.

Even if you don't own this code, you can create another DLL which wraps the original DLL and provides a small PInvoke layer.

Importing a class from a c# dll into a c++ app

I normally do this kind of stuff by creating a static C++ CLR Wrapper Lib.

These are the steps I'm normally using (although I don't use it very often):

Here minimal example with using Visual Studio:

1. Create managed C# .NET library Project

Let name it HelloLibManaged
with one file Hello.cs and following content:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloLibManaged
{
public class Hello
{
public void Print()
{
System.Console.WriteLine("Hello from Managed Lib");
}
}
}

Build this lib with x86 or x64 , just dont Any CPU

2. Create a new C++ CLR static lib project within same solution.
Let's name it HelloLibCpp

  • Add a reference to HelloLibManaged project via Project->Add Reference

  • Remove automatic created existing .h/.cpp files from Project, and create these 2 files:

HelloUnmanaged.h

#pragma once

namespace hello_managed {

class Hello
{
public:
void Print();
};
}

and

HelloUnmanaged.cpp:

#include "HelloUnmanaged.h"

namespace hello_managed
{

void Hello::Print()
{
HelloLibManaged::Hello^ hello = gcnew HelloLibManaged::Hello();
hello->Print();
}

}

Und Project Properties -> General specify static lib.
In the Build settings specify x86 / x64 - use the same build type as building Managed lib from Step 1.

Now you can build the dll and use it in your other unmanaged C++ projects.

For more advanced stuff, like return types and methods with parameters you have to do Type-Marshalling between managed/unmanaged code. There are many resources online with more information about Type-Conversion between managed/unmanaged code. Keyword: Marshaling.

make c++ class in a native dll to use in C#

Having done this a bunch of times, the easiest way to do this is to write a C++/CLI wrapper to your existing classes. The reason being that P/Invoke works best on calls that are strictly C functions and not methods in a C++ class. In your example, how would you call operator new for the class that you specify?

If you can write this as a C++/CLI dll, then what you get is something that looks like this:

public ref class CliHuman {
public:
CliHuman() : _human(new Human()) { }
~CliHuman() { delete _human; }
protected:
!CliHuman() { delete _human; }
public:
void DoPee() { _human->Do_Pee(); }
private:
Human *_human;
};

Now, you might not have the freedom to do this. In this case, your best bet is to think about what it would take to expose a C API of your C++ object. For example:

extern "C" {

void *HumanCreate() { return (void *)new Human(); }
void HumanDestroy(void *p) { Human *h = (Human *)h; delete h; }
void HumanDoPee(void *p) { Human *h = (Human *)h; h->Pee(); }

};

You can P/Invoke into these wrappers very easily.

From an engineering standpoint, you would never want to do this ever since calling .NET code could pass in any arbitrary IntPtr. In my code, I like to do something like this:

#define kHumanMagic 0xbeefbeef;

typedef struct {
int magic;
Human *human;
} t_human;

static void *AllocateHuman()
{
t_human *h = (t_human *)malloc(sizeof(t_human));
if (!h) return 0;
h->magic = kHumanMagic;
h->human = new Human();
return h;
}

static void FreeHuman(void *p) /* p has been verified */
{
if (!p) return;
t_human *h = (t_human)p;
delete h->human;
h->human = 0;
h->magic = 0;
free(h);
}

static Human *HumanFromPtr(void *p)
{
if (!p) return 0;
t_human *h = (t_human *)p;
if (h->magic != kHumanMagic) return 0;
return h->human;
}
void *HumanCreate() { return AllocateHuman(); }
void HumanDestroy(void *p)
{
Human *h = HumanFromPtr(p);
if (h) {
FreeHuman(p);
}
else { /* error handling */ }
}
void HumanPee(void *p)
{
Human *h = HumanFromPtr(p);
if (h) h->Do_Pee();
else { /* error handling */ }
}

What you can see that I've done is create a light wrapper on top of the class that lets me verify that what comes in is more likely to be a correct pointer to what we want. The safety is likely not for your clients but for you - if you have to wrap a ton of classes, this will be more likely to catch errors in your code where you use one wrapper in place of another.

In my code base, we have found it especially useful to have a structure where we build a static library with the low-level code and the C-ish API on top of it then link that into a C++/CLI project that calls it (although I suppose to could P/Invoke into it from C# as well) instead of having the C++/CLI directly wrap the C++. The reason is that (to our surprise), all the low-level code which was using STL, was having the STL implementations done in CLI rather than in x86 or x64. This meant that supposedly low-level code that was iterating over STL collections would do something like 4n CLI transitions. By isolating the code, we worked around that quite well.

How do I DllExport a C++ Class for use in a C# Application

C# cannot directly import C++ classes (which are effectively name-mangled C interfaces).

Your options are exposing the class via COM, creating a managed wrapper using C++/CLI or exposing a C-style interface. I would recommend the managed wrapper, since this is easiest and will give the best type safety.

A C-style interface would look something like this (warning: untested code):

extern "C" __declspec(dllexport)
void* CExampleExport_New(int param1, double param2)
{
return new CExampleExport(param1, param2);
}

extern "C" __declspec(dllexport)
int CExampleExport_ReadValue(void* this, int param)
{
return ((CExampleExport*)this)->ReadValue(param)
}

A C++/CLI-style wrapper would look like this (warning: untested code):

ref class ExampleExport
{
private:
CExampleExport* impl;
public:
ExampleExport(int param1, double param2)
{
impl = new CExampleExport(param1, param2);
}

int ReadValue(int param)
{
return impl->ReadValue(param);
}

~ExampleExport()
{
delete impl;
}
};

How to pass *& and **& parameter to C++ dll from C# code

I got the solution with below approach.

C# side code

DLL import, structure definition

[DllImport(@"C:\TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int DoOperation(ref IntPtr all, ref IntPtr[] part);

[StructLayout(LayoutKind.Sequential)]
public struct DataStruct
{
public int count { get; set; }
public float CountData { get; set; }
public bool flg { get; set; }
public IntPtr data { get; set; }
public string info { get; set; }
}

[StructLayout(LayoutKind.Sequential)]
public struct DataStructInfo
{
public int count { get; set; }
public bool flg { get; set; }
public IntPtr data { get; set; }
}

// First parameter
DataStruct alls = new DataStruct(); // set all required parameter
IntPtr intPtrsAll = new IntPtr();
intPtrsAll = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(DataStruct)));
Marshal.StructureToPtr<DataStruct>(alls, intPtrsAll, false);

// Second parameter
DataStructInfo[] part= new DataStructInfo[3]; // set all required parameter
IntPtr[] intPtrsParts= new IntPtr[part.Length];

for (int i = 0; i < intPtrsParts.Length; i++)
{
intPtrsParts[i] = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(DataStructInfo)));
Marshal.StructureToPtr<DataStructInfo>(part[i], intPtrsParts[i], false);
}

int ret = DoOperation(ref intPtrsAll, ref intPtrsParts);


Note: To set byte[] data at C# side, I have used [IntPtr] with below approach

byte[] rowData = GetRawBytes(dataHandler); // function to read byte[] data
int size = Marshal.SizeOf(rowData[0]) * rowData.Length;
data = Marshal.AllocHGlobal(size); // IntPtr property of struct's
Marshal.Copy(rowData, 0, data, rowData.Length);

Passing a C# class object in and out of a C++ DLL class

Bond was correct, I can't pass an object between managed and unmanaged code and still have it retain its stored information.

I ended up just calling C++ functions to create an object and pass the pointer back into C#'s IntPtr type. I can then pass the pointer around to any C++ function I need (provided it's extern) from C#. This wasn't excatly what we wanted to do, but it will serve its purpose to the extent we need it.

Here's C# the wrapper I'm using for example/reference. (Note: I'm using StringBuilder instead of the 'int intTest' from my example above. This is what we wanted for our prototype. I just used an integer in the class object for simplicity.):

class LibWrapper
{
[DllImport("CPPDLL.dll")]
public static extern IntPtr CreateObject();
[DllImport("CPPDLL.dll")]
public static extern void SetObjectData(IntPtr ptrObj, StringBuilder strInput);
[DllImport("CPPDLL.dll")]
public static extern StringBuilder GetObjectData(IntPtr ptrObj);
[DllImport("CPPDLL.dll")]
public static extern void DisposeObject(IntPtr ptrObj);
}

public static void CallDLL()
{
try
{
IntPtr ptrObj = Marshal.AllocHGlobal(4);
ptrObj = LibWrapper.CreateObject();
StringBuilder strInput = new StringBuilder();
strInput.Append("DLL Test");
MessageBox.Show("Before DLL Call: " + strInput.ToString());
LibWrapper.SetObjectData(ptrObj, strInput);
StringBuilder strOutput = new StringBuilder();
strOutput = LibWrapper.GetObjectData(ptrObj);
MessageBox.Show("After DLL Call: " + strOutput.ToString());
LibWrapper.DisposeObject(ptrObj);
}
...
}

Of course the C++ performs all the needed modifications and the only way for C# to access the contents is, more or less, by requesting the desired contents through C++. The C# code does not have access to the unmanged class contents in this way, making it a little longer to code on both ends. But, it works for me.

This is the references I used to come up with the basis of my solution:
http://www.codeproject.com/Articles/18032/How-to-Marshal-a-C-Class

Hopefully this can help some others save more time than I did trying to figure it out!



Related Topics



Leave a reply



Submit