views:

305

answers:

2

I have a c# dll 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's 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 VS2008 & .NET 3.5

A: 

Try checking out the links provided in this question, they helped me with a similar problem.

thepocketwade
+2  A: 

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.

Matt Davis
Hi Matt, "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" The dll's are nested several sub-directories beneath the exe. Moving the managed dll to the same directory as executable cleared the problem right up.Thank You!!
mark
OK, great. I was under the impression that as long as the dll was in a subdirectory of the executable, regardless of how deep, the assembly would be resolved. But as I said, it's been a while since I looked at this.
Matt Davis