Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you call a managed (C#) function from C++?

I have a C# DLL file project (my_cs_dll.dll) which defines a static class with a static member function.

namespace Foo
{
    public static class Bar
    {
        public static double GetNumber() { return 1.0; }
    }
}

I also have a C++ DLL project which is using /clr.

#using <my_cs_dll.dll>

double get_number_from_cs() { return Foo::Bar::GetNumber(); }

I've added a reference to 'my_cs_dll.dll' in the C++ project Common Properties references section (copy local/copy dependencies are both True).

And I've also added the path to 'my_cs_dll.dll' in the C++ project Configuration Properties C/C++ General 'Resolve#using References' section.

Everything builds without error, however at runtime I keep getting a 'System.IO.FileNotFound' exception from the system claiming it can't find the my_cs_dll.dll assembly.

Both DLL files are definitely present in the same directory from which I'm running.

I have tried all sorts of variations on the settings mentioned above and read everything I could find on manged/unmanaged interop, but I can't seem to get my brain around what is wrong...

I'm using Visual Studio 2008 and .NET 3.5.

like image 654
mark Avatar asked Sep 24 '09 06:09

mark


People also ask

Why c# is called managed language?

The application is written in the languages like Java, C#, VB.Net, etc. are always aimed at runtime environment services to manage the execution and the code written in these types of languages are known as managed code.

What do you mean by managed code?

To put it very simply, managed code is just that: code whose execution is managed by a runtime. In this case, the runtime in question is called the Common Language Runtime or CLR, regardless of the implementation (for example, Mono, . NET Framework, or . NET Core/.

How do I call C++ code from C#?

Calling C++ Code from C# x code using a managed wrapper (C++/CLI) so that it can be called from a C# application. The sample wraps the minimum-volume bounding box code, but you can modify the project to replace that code by whatever else you want to expose for your C# applications.

What is meant by managed and unmanaged code?

Managed code is the code which is managed by the CLR(Common Language Runtime) in .NET Framework. Whereas the Unmanaged code is the code which is directly executed by the operating system.


1 Answers

It sounds like your C# assembly is not being resolved at runtime. Is your C# dll in the same directory as (or a subdirectory of) your executable? It's been a while since I did this, but my recollection is that unless your assembly is installed in the GAC, it must be in the directory (or a subdirectory) where your executable is located, as opposed to the location of the dll that's using it. This has to do with the .NET security features.

If you are still having problems, you can try using resolving the assembly yourself. In your clr-enabled C++ project, try adding the following:

using namespace System;
using namespace System.Reflection;
void Resolve()
{
    AppDomain::CurrentDomain->AssemblyResolve +=
        gcnew ResolveEventHandler(OnAssemblyResolve);
}
Assembly ^OnAssemblyResolve(Object ^obj, ResolveEventArgs ^args)
{
#ifdef _DEBUG
    String ^path = gcnew String(_T("<path to your debug directory>"));
#else
    String ^path = gcnew String(_T("<path to your release directory>"));
#endif
    array<String^>^ assemblies =
        System::IO::Directory::GetFiles(path, _T("*.dll"));
    for (long ii = 0; ii < assemblies->Length; ii++) {
        AssemblyName ^name = AssemblyName::GetAssemblyName(assemblies[ii]);
        if (AssemblyName::ReferenceMatchesDefinition(gcnew AssemblyName(args->Name), name)) {
            return Assembly::Load(name);
        }
    }
    return nullptr;
}

You may have to tweak the code a little bit to get it to compile in your project. In my case, I made the two functions static methods of a class in my clr-enabled project. Just make sure you call the Resolve() function early on in your code, i.e., before you try to call get_number_from_cs().

While using COM is an option, it is not necessary. You're on the right path with your current approach. If you want some hand-holding, take a look at this CodeProject example. It's the one I following to get my unmanaged application to use my managed assemblies.

like image 184
Matt Davis Avatar answered Oct 11 '22 05:10

Matt Davis