RCode

a software development blog by Bojan Resnik

Archive for the ‘Inventor’ Category

Installing the same managed addin in 32bit and 64bit Autodesk Inventor

Posted by Bojan Resnik on May 21, 2009

I have an addin for AutoDesk Inventor 2009, written in C# and a setup project to go with it. In order to register the addin with Inventor, I needed to register the assembly with “/codebase” switch, so I made a custom installer action:

[RunInstaller(true)]
public partial class AddinInstaller : Installer
{
    public override void Install(System.Collections.IDictionary stateSaver)
    {
        base.Install(stateSaver);
        RegistrationServices regsrv = new RegistrationServices();
        regsrv.RegisterAssembly(GetType().Assembly, AssemblyRegistrationFlags.SetCodeBase);
    }

    public override void Uninstall(System.Collections.IDictionary savedState)
    {
        base.Uninstall(savedState);

        RegistrationServices regsrv = new RegistrationServices();
        regsrv.UnregisterAssembly(GetType().Assembly);
    }
}

The actual registration code run by the registration service modifies some registry keys under HKEY_CLASSES_ROOT. This worked fine on Windows XP, but when run on my Vista 64, the setup completed successfully, but failed to register the addin with Inventor. The reason became apparent when I realized that my Inventor installation is also 64 bit – which means it looks for the keys using the 64bit view of the registry, while the installer action runs with the 32bit view.

The code itself is all C#, compiled as “Any CPU”, so it should have no problems running unmodified with both 64 and 32 bit Inventors. The only problem is how to run the installer as 64 bit. I also wanted to allow the same MSI to be used on all platforms, so compiling multiple versions was not an option. And searching the net, I got the impression that it would not solve the problem anyway – at least not without some other tools.

The solution I came up with is simpler: instead of using RegistrationServices object, I can manually execute the RegAsm.exe tool to register the assembly. On my Vista 64, there are two versions of this tool:

  • C:\Windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe
  • C:\Windows\Microsoft.NET\Framework64\v2.0.50727\RegAsm.exe

The directories might not be the same on other machines, of course. Fortunately, .NET provides the RuntimeEnvironment.GetRuntimeDirectory() static method which returns the folder of the common language runtime. On my machine, it returns C:\Windows\Microsoft.NET\Framework\v2.0.50727\ inside the installer action. We can use this, combined with RuntimeEnvironment.GetSystemVersion() to construct the paths to 32bit and 64bit versions of the tool:

[RunInstaller(true)]
public partial class AddInInstaller : Installer 
{
    public AddInInstaller() 
    { InitializeComponent(); }

    public override void Install(IDictionary stateSaver) 
    {
        base.Install(stateSaver);
        RegAsm("/codebase");
    }

    public override void Uninstall(IDictionary savedState) 
    {
        RegAsm("/u");
        base.Uninstall(savedState);
    }

    private static void RegAsm(string parameters)
    {
        // RuntimeEnvironment.GetRuntimeDirectory() returns something like
        //    C:\Windows\Microsoft.NET\Framework64\v2.0.50727\
        // We need to get to the
        //    C:\Windows\Microsoft.NET
        // part in order to create 32 and 64 bit paths
        var net_base = Path.GetFullPath(Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), @"..\.."));
                    
        // Create paths to 32bit and 64bit versions of regasm.exe
        var to_exec = new[]
        {
            string.Concat(net_base, "\\Framework\\", RuntimeEnvironment.GetSystemVersion(), "\\regasm.exe"), 
            string.Concat(net_base, "\\Framework64\\", RuntimeEnvironment.GetSystemVersion(), "\\regasm.exe")
        };

        var dll_path = Assembly.GetExecutingAssembly().Location;
 
        foreach (var path in to_exec)
        {
            // Skip the executables that do not exist
            // This most likely happens on a 32bit machine when processing the path to 64bit regasm
            if ( !File.Exists(path) )
                continue;
                
            var process = new Process
            {
                StartInfo =
                {
                    CreateNoWindow = true,
                    ErrorDialog = false,
                    UseShellExecute = false,
                    FileName = path,
                    Arguments = string.Format("\"{0}\" {1}", dll_path, parameters)
                }
            };
            
            using (process)
            {
                process.Start();
                process.WaitForExit();
            }
        }
    }
}
Advertisements

Posted in .NET, C#, Inventor | 8 Comments »