views:

32

answers:

2

I'm writing an application for the Peachtree API and it needs to work with any version of the API. Unfortunately the dll from Peachtree 2011 can't interact with Peachtree 2010, and vice versa, even though the two dlls are stored in the same location and run with exactly the same code.

I thought I should be able to refer to the dll by it's file path, leave specific version at false, embed interop types at false, and copy local at false and it would just use whatever version the machine had, but I get an error when I do that - "Exception has been thrown by the target of an invocation."

Is there a way to late-bind the dll even though it's COM?

I can provide code samples of whatever you think would be helpful, but it's more of a project setup issue than anything.

EDIT: Thank you all very much for your help. I found my solution on a different person's question and posted it here.

+3  A: 

Late-binding to COM objects requires that you do NOT add a reference to the COM library to your .NET project. Instead, you should you use something like this to create COM objects:

   Type type = Type.GetTypeFromProgID("Excel.Application")
   object app = Activator.CreateInstance(type);

Then, it will bind to any version of the COM library at runtime.

See this article for more details.

fmunkert
and with .net 4.0 you can use the new `dynamic` type and have late method call binding, eliminating the need to add a type reference http://msdn.microsoft.com/en-us/library/dd264736.aspx
Remus Rusanu
One thing I'd like to add is that, when you get the object from create instance, you can cast it to the right interface type, so you still have static binding, even though though creation is late-bound.
zumalifeguard
Thanks for your help. Your ideas got me on the right path.
Yoenhofen
A: 

This is the solution

http://stackoverflow.com/questions/277817/compile-a-version-agnostic-dll-in-net-using-manifests/284462#284462

In case that link ever dies, the key is to handle the AppDomain.CurrentDomain.AssemblyResolve event like below. The event fires any time an assembly binding fails, so you can resolve it yourself, fixing version conflicts.

using System.Reflection;

static Program()
{
    AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
    {
        AssemblyName requestedName = new AssemblyName(e.Name);

        if (requestedName.Name == "Office11Wrapper")
        {
            // Put code here to load whatever version of the assembly you actually have

            return Assembly.LoadFile("Office11Wrapper.DLL");
        }
        else
        {
            return null;
        }
    }
}
Yoenhofen