Loading CLR references from relative paths

I have a native program that uses LoadLibrary() to load a DLL from a specified path other than the working directory. This DLL happens to be a C++/CLI assembly that references a C# DLL. Loading the C++/CLI assembly works fine, but when it tries to call code from the referenced assembly, it fails because it can't find it in the working directory.
Is there any way I can modify the loader's behavior to also try the directory the DLL is in?
If the C++/CLI assembly loads the C# dll statically both need to be in the same folder.
You could try to modify the C++/CLI assembly so that it loads the C# dll with Assembly::Load but this is much more work.

https://msdn.microsoft.com/en-us/library/25y1ya39(v=vs.110).aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1
The C# DLL is a reference of the C++/CLI DLL, and is loaded at whatever time the runtime loads CLR references.
Does it work if all the files are in the same folder ?
Including the main executable? Yes, it works. It also works if the DLLs the C++/CLI DLL depends on are with the executable, but the C++/CLI DLL is in a different directory. If the executable is in one place and all the other DLLs are in another, it doesn't work.
I managed to get it working. My native API has a function that must be called before any other function, to allow the plugin to perform initialization steps. In it, I did this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using namespace System;

public ref class AssemblyResolver{
public:
    static System::Reflection::Assembly ^ResolveEventHandler(System::Object ^sender, System::ResolveEventArgs ^args){
        auto sb = gcnew System::Text::StringBuilder();
        sb->Append(GetAssemblyDirectory());
        const char * const name = "\\required_assembly.dll";
        for (auto p = name; *p; p++)
            sb->Append((Char)*p);
        return System::Reflection::Assembly::LoadFrom(sb->ToString());
    }

    //Returns the containing directory of the assembly that contains the function.
    static String ^GetAssemblyDirectory(){
        auto codeBase = System::Reflection::Assembly::GetExecutingAssembly()->CodeBase;
        auto uri = gcnew UriBuilder(codeBase);
        auto path = Uri::UnescapeDataString(uri->Path);
        return System::IO::Path::GetDirectoryName(path);
    }
};

API Instance *initialize(){
    auto domain = System::AppDomain::CurrentDomain;
    domain->AssemblyResolve += gcnew System::ResolveEventHandler(AssemblyResolver::ResolveEventHandler);
    
    //(Application-specific stuff)
}
Last edited on
Topic archived. No new replies allowed.