2

I currently have a large C++ library that I need to incorporate into a C# project. I was successful in using DllImport to get access to some functions from my library, like this:

[DllImport("MyLib.dll")]
public static extern int SampleFunction(string param);

However, I can't seem to figure out how to make it work for functions that either have a parameter or return type that is not defined within the dll itself (i.e., the code in the dll imports it from another file), such as this example function that takes in a list:

[DllImport("MyLib.dll")]
public static extern std::vector<MyClass> MyFunction(string param);

For std library functions, I know I can get the dll and import that in, but what about other classes like MyClass in the above example? Do I need to create a managed wrapper class in C++ for each of these classes, or is there another way to do this?

Jeremy
  • 77
  • 1
  • 2
  • 8
  • What do you mean "other classes"? Where is `MyClass` defined? Is it a C++ class or a .NET class? – Panagiotis Kanavos May 14 '15 at 06:53
  • Regarding the standard library, "I know I can get the dll and import that in" - you may be in for a rude awakening on that. The C++ standard library as opposed to [STL/CLR](https://msdn.microsoft.com/en-us/library/bb385954.aspx) might not be what you think. Is your C++ DLL written in .NET? – WhozCraig May 14 '15 at 06:53
  • Sorry I should have clarified. `MyClass` is a C++ class from `MyLib.dll`. – Jeremy May 14 '15 at 07:05
  • And no, the C++ DLL is not written in .NET. That's why I was wondering if I need to write a managed class to basically wrap each class it uses so that I can then call that managed code from my C# project. I thought I saw an example on MSDN where they imported some functions like `puts` from the C++ standard library, so I'm trying to find that page again. – Jeremy May 14 '15 at 07:06
  • `DllImport` is really only intended for importing C-style functions. If you're trying to interop with C++, your best bet is probably using a C++/CLI wrapper library - you can directly work with both .NET *and* native C++ that way. Oh, and avoid using return values like this - it doesn't make it clear who's responsible for the memory - remember, interop in unmanaged is much harder than in managed code. Unless you have a good reason not to, I'd just stick with simple C-style functions. – Luaan May 14 '15 at 07:21

2 Answers2

1

If you need a custom class from a native lib, you'll probably need to export a type library or use managed C++ to write a wrapper. What you're effectively trying to do is marshal a piece of memory from native to managed and now have to deal with how the data type is marshaled.

If at all possible, I would actually recommend trying to do away with the marshaling as when it works it's fine, but when it breaks, it can be rage inducing to debug.

Regardless, I'm actually not sure if anything in the STL can be marshaled. At the very least, I have never seen it done. More times, I've had to do a conversion like so: How can I marshall a vector<int> from a C++ dll to a C# application?

If you want to marshal an actual class, the standard way I've done it up until now is through a type library: Import TLB into C#

Or by linking a native lib into a managed C++ class and then referencing the managed C++ dll into the C# project as a shim.

Beyond that, if you can convert the class to strict C-style functions and pass a struct around, that could allow you to just use pinvoke, this is no different from simply exporting a bunch of helper functions except you can marshal a struct representation back and forth: Marshal C++ struct array into C#

Community
  • 1
  • 1
Jun
  • 764
  • 5
  • 8
1

std::vector<MyClass>, or indeed any unmanaged C++ class, cannot be used for interop to C#. Indeed, even if you wished to consume this function from another unmanaged C++ module you'd have to make sure that you were using the same compiler and dynamic runtime as the DLL which exported the function.

You'll need to find some other way to implement this functionality. There are lots of different ways to do that.

  • You could expose a p/invoke interface to the functionality. That would likely involve declaring a struct to represent the data of your class, and serializing to and from that struct.
  • You might consider a COM interface but it won't offer great advantages over p/invoke. You'd still need to serialize your class.
  • A C++/CLI wrapper would be yet another option. You'd wrap the unmanaged class with a managed C++/CLI class, and then consume that from the C#.
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490