I have a program which needs to function in both an x86 and an x64 environment. It is using Oracle\'s ODBC drivers. I have a reference to Oracle.DataAccess.DLL. This DLL is
This is a working solution for your problem:
Add the 2 DLL's (x86 and x64) to your solution in a subfolder. Make them "Copy if newer"
Reference the correct DLL you use for development for debugging from the 2 DLL's you added. Make it Copy Local=false.
What this does is that when you app starts the DLL is not autoloaded. It will not be loaded until you use a Type from that assembly. Once that happens an event will be triggered in .Net that asks where it can find your assembly.
So sometime before the first use of that assembly make sure you attach yourself to that event.
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
In the content of the handler make sure you load the DLL (x86 or x64) when it asks for it.
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
if (args.Name.Equals("MyFullAssemblyName")) {
var path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
if (IntPtr.Size > 4) {
var dll = System.IO.Path.Combine(path, @"MySubDir\MyDLL_x64.dll");
return System.Reflection.Assembly.LoadFile(dll);
}
else {
var dll = System.IO.Path.Combine(path, @"MySubDir\MyDLL.dll");
return System.Reflection.Assembly.LoadFile(dll);
}
}
return null;
}
Voila. You can now run your app as both 32 bit and 64 bit.
Alternatively to adding the DLLs in a subfolder, you can make them as Embedded Resources, and then load them like this:
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
if (args.Name.Equals("MyFullAssemblyName")) {
var ass = Assembly.GetExecutingAssembly();
if (IntPtr.Size > 4) {
var strm = ass.GetManifestResourceStream("the.resource.name.for.MyDLL_x64.dll");
var data = new byte[strm.Length];
strm.Read(data, 0, data.Length);
return Assembly.Load(data);
}
else {
var strm = ass.GetManifestResourceStream("the.resource.name.for.MyDLL.dll");
var data = new byte[strm.Length];
strm.Read(data, 0, data.Length);
return Assembly.Load(data);
}
}
return null;
}
This does not work for all assemblies. Some "hybrid" assemblies tends to fail unless they are loaded from disk (can be solved by writing them to disk just before loading).
Using AnyCPU with native early bindings is just not going to work, for that you need two separate solutions and builds as you saw. You have to get hold of a 64-bit system to develop or at least test x64 compiled dlls on.
However, with late binding, you can use AnyCPU and System properties to figure out what architecture you're running as and link to the correct dll, if you keep the named like Oracle.DataAccess.x86.dll. If they're installed into the GAC, it's even easier, you can bind without even bothering to test for architecture first, but I believe you still have to late bind.
Note that VMware can run a 64-bit guest on a 32-bit host, if you really can't be bothered to reinstall Windows.
This is purely a deployment problem, you should never have to maintain different projects. It is an awkward one though, and boo on Oracle for not taking care of this themselves. Another consideration is that this assembly really should be ngen-ed on the target machine. Some options
If you're running on a 32-bit machine, then you have to load the 32-bit version of the Oracle DLL. A 32-bit program can't reference a 64-bit DLL. And, a 64-bit program can't reference a 32-bit DLL.
"Any CPU" is the correct target if you have multiple versions of the external DLL. The trick is making sure that the proper Oracle DLL is located and loaded. Your best bet is to locate the 64-bit version of the DLL on your 32-bit system and rename it so that the runtime can't find it.
You shold be able to configure the same solution to build x86/x64 versions separately. You may also need to add post build steps to copy correct version of DLL to corresponding output folders...
At least if you have to build 2 solutions - use the same source (add files as refernce to second solution, not copy into second solution).