Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Background: As part of a larger assignment I need to make a C# library accessible to unmanaged C++ and C code. In an attempt to answer this question myself I have been learning C++/CLI the past few days/ weeks.

There seems to be a number of different ways to achieve using a C# dll from unmanaged C++ and C. Some of the answers in brief appear to be: using Interlope services, Using .com. and regasm, Using PInvoke (which appears to go from C# to C++ only), and using IJW in the C++/CLR (which appears to be Interlope services). I am thinking it would be best to set up a library that is perhaps a CLR wrapper that uses IJW to call my C# dll on the behalf of native C++ and C code.

Specifics: I need to pass values of string as well as int to a C# dll from c++ code, and return void.

Relevance: Many companies have many excuses to mix and match C++, C and C#. Performance: unmanaged code is usually faster, interfaces: Managed interfaces are generally easier to maintain, deploy, and are often easier on the eyes, Managers tell us too. Legacy code forces us too. It was there (Like the mountain that we climbed). While examples of how to call a C++ library from C# are abundant. Examples of how to call C# libraries from C++ code are difficult to find via Googling especially if you want to see updated 4.0+ code.

Software: C#, C++/CLR, C++, C, Visual Studio 2010, and .NET 4.0

Question details: OK multi-part question:

  1. Is there an advantage to using com objects? Or the PInvoke? Or some other method? (I feel like the learning curve here will be just as steep, even though I do find more information on the topic in Google Land. IJW seems to promise what I want it to do. Should I give up on looking for an IJW solution and focus on this instead?) (Advantage/ disadvantage?)

  2. Am I correct in imagining that there is a solution where I write a wrapper that that utilizes IJW in the C++/CLR? Where can I find more information on this topic, and don’t say I didn’t Google enough/ or look at MSDN without telling me where you saw it there. (I think I prefer this option, in the effort to write clear and simple code.)

  3. A narrowing of question scope: I feel that my true issue and need is answering the smaller question that follows: How do I set up a C++/CLR library that an unmanaged C++ file can use within visual studio. I think that if I could simply instantiate a managed C++ class in unmanaged C++ code, then I might be able work out the rest (interfacing and wrapping etc.). I expect that my main folly is in trying to set up references/#includes etc. within Visual Studio, thought clearly I could have other misconceptions. Perhaps the answer to this whole thing could be just a link to a tutorial or instructions that help me with this.

Research: I have Googled and Binged over and over with some success. I have found many links that show you how to use an unmanaged library from C# code. And I will admit that there have been some links that show how to do it using com objects. Not many results were targeted at VS 2010.

References: I have read over and over many posts. I have tried to work through the most relevant ones. Some seem tantalizingly close to the answer, but I just can’t seem to get them to work. I suspect that the thing that I am missing is tantalizingly small, such as misusing the keyword ref, or missing a #include or using statement, or a misuse of namespace, or not actually using the IJW feature properly, or missing a setting that VS needs to handle the compilation correctly, etc. So you wonder, why not include the code? Well I feel like I am not at a place where I understand and expect the code I have to work. I want to be in a place where I understand it, when I get there maybe then I'll need help fixing it. I'll randomly include two of the links but I am not permitted to show them all at my current Hitpoint level.

http://www.codeproject.com/Articles/35437/Moving-Data-between-Managed-Code-and-Unmanaged-Cod

This calls code from managed and unmanaged code in both directions going from C++ to Visual Basic and back via C++CLR, and of course I am interested in C#.: http://www.codeproject.com/Articles/9903/Calling-Managed-Code-from-Unmanaged-Code-and-vice

like image 733
amalgamate Avatar asked Nov 08 '12 16:11

amalgamate


People also ask

How do you call C from R?

The most basic method for calling C code from R is to use the . C() function described in the System and foreign language interfaces section of the Writing R Extensions manual. Other methods exist including the . Call() and .

Can I call ac function from C++?

Just declare the C function extern "C" (in your C++ code) and call it (from your C or C++ code). For example: // C++ code.


Video Answer


2 Answers

You can do this fairly easily.

  1. Create an .h/.cpp combo
  2. Enable /clr on the newly create .cpp file. (CPP -> Right click -> Properties)
  3. Set the search path for "additional #using directories" to point towards your C# dll.

Native.h

void NativeWrapMethod(); 

Native.cpp

#using <mscorlib.dll> #using <MyNet.dll>  using namespace MyNetNameSpace;  void NativeWrapMethod() {     MyNetNameSpace::MyManagedClass::Method(); // static method } 

That's the basics of using a C# lib from C++\CLI with native code. (Just reference Native.h where needed, and call the function.)

Using C# code with managed C++\CLI code is roughly the same.

There is a lot of misinformation on this subject, so, hopefully this saves someone a lot of hassle. :)


I've done this in: VS2010 - VS2012 (It probably works in VS2008 too.)

like image 134
Smoke Avatar answered Sep 20 '22 14:09

Smoke


UPDATE 2018

It seems like as if the solution does not work for Visual Studio 2017 and onwards. Unfortunately I am currently not working with Visual Studio and therefore cannot update this answer by myself. But kaylee posted an updated version of my answer, thank you!

UPDATE END

If you want to use COM, here's my solution for this problem:

C# library

First of all you need a COM compatible library.

  • You already got one? Perfect, you can skip this part.

  • You have access to the library? Make sure it's COM compatible by following the steps.

    1. Make sure that you checked the "Register for COM interop" option in the properties of your project. Properties -> Build -> Scroll down -> Register for COM interop

The following screenshots shows where you find this option.

Screenshot Project Properties Build

  1. All the interfaces and classes that should be available need to have a GUID

    namespace NamespaceOfYourProject {     [Guid("add a GUID here")]     public interface IInterface     {         void Connect();          void Disconnect();     } }  namespace NamespaceOfYourProject {      [Guid("add a GUID here")]      public class ClassYouWantToUse: IInterface      {          private bool connected;           public void Connect()          {              //add code here          }           public void Disconnect()          {              //add code here          }      } } 

So that's pretty much what you have to do with your C# code. Let's continue with the C++ code.

C++

  1. First of all we need to import the C# library.

After compiling your C# library there should be a .tlb file.

#import "path\to\the\file.tlb" 

If you import this new created file to your file.cpp you can use your object as a local variable.

#import "path\to\the\file.tlb"  int _tmain(int argc, _TCHAR* argv[]) {     CoInitialize(NULL);      NamespaceOfYourProject::IInterfacePtr yourClass(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));      yourClass->Connect();      CoUninitialize(); } 
  1. Using your class as an attribute.

You will noticed that the first step only works with a local variable. The following code shows how to use it as a attribute. Related to this question.

You will need the CComPtr, which is located in atlcomcli.h. Include this file in your header file.

CPlusPlusClass.h

#include <atlcomcli.h>  #import "path\to\the\file.tlb"  class CPlusPlusClass { public:     CPlusPlusClass(void);     ~CPlusPlusClass(void);     void Connect(void);  private:     CComPtr<NamespaceOfYourProject::IInterface> yourClass; } 

CPlusPlusClass.cpp

CPlusPlusClass::CPlusPlusClass(void) {     CoInitialize(NULL);      yourClass.CoCreateInstance(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));  }  CPlusPlusClass::~CPlusPlusClass(void) {     CoUninitialize(); }  void CPlusPlusClass::Connect(void) {     yourClass->Connect(); } 

That's it! Have fun with your C# classes in C++ with COM.

like image 41
0lli.rocks Avatar answered Sep 19 '22 14:09

0lli.rocks