Yes, you can target both x86 and x64 with the same code base in the same project. In general, things will Just Work if you create the right solution configurations in VS.NET (although P/Invoke to entirely unmanaged DLLs will most likely require some conditional code): the items that I found to require special attention are:
- References to outside managed assemblies with the same name but their own specific bitness (this also applies to COM interop assemblies)
- The MSI package (which, as has already been noted, will need to target either x86 or x64)
- Any custom .NET Installer Class-based actions in your MSI package
The assembly reference issue can't be solved entirely within VS.NET, as it will only allow you to add a reference with a given name to a project once. To work around this, edit your project file manually (in VS, right-click your project file in the Solution Explorer, select Unload Project, then right-click again and select Edit). After adding a reference to, say, the x86 version of an assembly, your project file will contain something like:
<Reference Include="Filename, ..., processorArchitecture=x86">
<HintPath>C:\path\to\x86\DLL</HintPath>
</Reference>
Wrap that Reference tag inside an ItemGroup tag indicating the solution configuration it applies to, e.g:
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<Reference ...>....</Reference>
</ItemGroup>
Then, copy and paste the entire ItemGroup tag, and edit it to contain the details of your 64-bit DLL, e.g.:
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<Reference Include="Filename, ..., processorArchitecture=AMD64">
<HintPath>C:\path\to\x64\DLL</HintPath>
</Reference>
</ItemGroup>
After reloading your project in VS.NET, the Assembly Reference dialog will be a bit confused by these changes, and you may encounter some warnings about assemblies with the wrong target processor, but all your builds will work just fine.
Solving the MSI issue is up next, and unfortunately this will require a non-VS.NET tool: I prefer Caphyon's Advanced Installer for that purpose, as it pulls off the basic trick involved (create a common MSI, as well as 32-bit and 64-bit specific MSIs, and use an .EXE setup launcher to extract the right version and do the required fixups at runtime) very, very well.
You can probably achieve the same results using other tools or the Windows Installer XML (WiX) toolset, but Advanced Installer makes things so easy (and is quite affordable at that) that I've never really looked at alternatives.
One thing you may still require WiX for though, even when using Advanced Installer, is for your .NET Installer Class custom actions. Although it's trivial to specify certain actions that should only run on certain platforms (using the VersionNT64 and NOT VersionNT64 execution conditions, respectively), the built-in AI custom actions will be executed using the 32-bit Framework, even on 64-bit machines.
This may be fixed in a future release, but for now (or when using a different tool to create your MSIs that has the same issue), you can use WiX 3.0's managed custom action support to create action DLLs with the proper bitness that will be executed using the corresponding Framework.
Edit: as of version 8.1.2, Advanced Installer correctly supports 64-bit custom actions. Since my original answer, its price has increased quite a bit, unfortunately, even though it's still extremely good value when compared to InstallShield and its ilk...
Edit: If your DLLs are registered in the GAC, you can also use the standard reference tags this way (SQLite as an example):
<ItemGroup Condition="'$(Platform)' == 'x86'">
<Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
<Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64" />
</ItemGroup>
The condition is also reduced down to all build types, release or debug, and just specifies the processor architecture.
Best Answer
You are swimming upstream against MSI on this one. (Although I can understand why. )
Officially MSI is never platform nuetral. I assume you are using a custom action to read the registry values because MSI's AppSearch/Reglocator will constrain you to the WoWSys64 node. After that, MSI will substitute even hard coded references to program files as part of an application compatibility approach ( basically microsoft assumes you didn't know what you were doing and that they know what you really meant to do ).
Unofficially- read this thread to find a hack that I figured out to work around this. The summary is I found that if you convert C:\Program Files\ to a short path ( C:\Progra~1 ) that MSI is no smart enough to figure out what you are referring to so it doesn't substitute the value.
http://www.joyofsetup.com/2010/03/27/wix-msbuild-v2-0-and-x64-systems/
Note, this a hack and there is no way of telling if Microsoft will 'fix it' in future releases. The only other approach I can think of is you to then not use the shortcut table and instead write custom actions to create the shortcuts for you.
If you don't want to swim against MSI, consider this workaround. Create a small 64bit EXE ( yes, you can deploy a 64bit or AnyCPU exe to Program Files x86 is a x86 MSI ) that acts as a front end launcher to AutoCAD. Make it query the registry table and find the file then launch it or display a message saying AutoCAD is unavailable if it can't be found.
If you do this you make your install far cleaner.