I have a Managed C++ dll that I am referencing from a C# project. The C# project will be compiled as AnyCPU. Is there any way to compile a 32-bit and 64-bit version of the Managed C++ dll and then tell the C# project at runtime to load the correct one depending on which architecture it is being run?
Managed C++ and AnyCPU
Asked Answered
The trick to getting the AnyCPU dll to play with the C++ dll, is at runtime make sure the assembly cannot load the C++ dll and then subscribe to the AppDomain AssemblyResolve event. When the assembly tries to load the dll and fails, then your code has the opportunity to determine which dll needs to be loaded.
Subscribing to the event looks something like this:
System.AppDomain.CurrentDomain.AssemblyResolve += Resolver;
Event handler looks something like this:
System.Reflection.Assembly Resolver(object sender, System.ResolveEventArgs args)
{
string assembly_dll = new AssemblyName(args.Name).Name + ".dll";
string assembly_directory = "Parent directory of the C++ dlls";
Assembly assembly = null;
if(Environment.Is64BitProcess)
{
assembly = Assembly.LoadFrom(assembly_directory + @"\x64\" + assembly_dll);
}
else
{
assembly = Assembly.LoadFrom(assembly_directory + @"\x86\" + assembly_dll);
}
return assembly;
}
I have created a simple project demonstrating how to access C++ functionality from an AnyCPU dll.
Me too. I am not sure if I would do this in production, but this is at least a viable idea. Upvoted back to zero to revert the injustice –
Apiary
Thanks Ivan! I appreciate your support:) –
Salinas
Thanks Ivan for the comment. I have been thinking about what you said, not doing this in production. So I am trying to do a little learning here:) Is the source of your comment concerning security? I do realize this is a hack, but as far as I know, this is one few ways I know how to accomplish supporting C#'s AnyCPU declaration from Managed C++. The only other approach I am aware of is using PInvoke, which I think suffers from the same issue. I am coming to the realization that the correct approach is to mange the issue at installation. –
Salinas
Using assembly resolver to load dependencies in a production app means that the custom dependency resolution logic will have to be added to every tool that works with your code: unit testing frameworks, coverage tools, etc. Otherwise they won't be able to find all required assemblies. This problem may not seem like a big deal at first, but it gets very annoying very quickly. I worked for a company whose entire library versioning scheme was based on a custom assembly resolver; they struggled with it for a few years and finally gave up, reverting to standard .NET assembly loading. –
Apiary
Actually, this isn't true. The dependency resolution logic is encapsulated in the net dll. Thus, any C# code dependent on the net dll can use the public objects in the net dll just like any other net dll. –
Salinas
What do you mean by 'resolution logic is encapsulated in the net dll'? E.g. if you load it in nUnit, how do you tell nUnit to load proper dependencies? Hook up your assembly resolver in assembly test setup class? Well, OK, but now you want to load it in some kind of code analyzer... What then? An organization I worked in, a large investment bank, tried to implement custom resolution logic on a company-wide, ran it for several years, and in the end gave up, since real inconveniences popped left and right. –
Apiary
For the record, we've used this method in production for about 5 years now. I'm sure there are scenarios where it's cumbersome or problematic, but we've found it to be a reasonably simple yet robust approach for development, unit testing, and deployment. And yes, for unit testing we do exactly as Ivan suggests and hook up our custom assembly resolver in the test initialization method. –
Citizen
The assembly resolver is encapsulated in AnyCPU.dll, thus all client code is directly dependent on only the AnyCPU.dll interface. If you look at the source code I provided, there is no assembly resolving code in AnyCPU.Test.Develop or AnyCPU.Test.Distribute. If resolver code is needed in the unit tests, that would suggest the dependencies of the code being tested are not completely encapsulated away from the client. –
Salinas
To answer Ivan's question: ModelInitializer enables early registration of the assembly resolver method so that AnyCPU.dll can resolve it's own dependencies. –
Salinas
I don't know how do you 'reference' the C++ dll(P/Invoke vs .net assembly reference) but either way you could swap the two versions of the .dll at installation time.
© 2022 - 2024 — McMap. All rights reserved.