Setuppaket für .NET Addins erstellen und registrieren (regasm)

Mo, 15.03.2010 - 16:35 -- Daniel Espendiller

Erweiterung bzw Addins für Programme, die in .NET geschrieben werden, müssen im System über regasm registriert werden. Regasm erzeugt dazu Registry-Einträge, die in der Windows-Registrierung eingetragen werden.
Möchte man diesen Vorgang automatisiert über eine Setuproutine durchführen, merkt man schnell, dass für diesen einfachen Vorgang doch keine recht einfache Möglichkeit besteht.
Hier ein Sammelwerk meiner bisher probierten Lösungen.

Sharpdevolop

Mittlerweile nutze ich Sharpdevolop (Wix) nur hiermit konnte ich bisher ein ordentliches MSI-Paket erstellen, welches dann über die Softwareverteilung auf den Arbeitsplätzen installiert werden kann.
Zum Erstellen eines Grundpaketes diese Anleitung beachten. Auf Basis des Paketes können wir nur nun ein .NET Addin in Windows registrieren.
Dazu müssen wir uns die Datei heat.exe raussuchen. Durch Übergabe einer DLL generiert uns das Programm alle nötigen Informationen in einer wxs Datei, die wir dann zu unserem Installationsskript hinzufügen können.

%ProgramFiles%\SharpDevelop\3.0\bin\Tools\Wix\heat.exe file bin\PrintButtons.dll -out PrintButtons.wxs

Alle RegistryValue Variablen müssen wir in Files.wxs unterhalb der Dateikompontene einfügen und die Werte file:///[#fil...] durch unsere ersetzen file:///[#PrintButtons.dll].

<RegistryValue Root="HKCR" Key="CLSID\{74607E91-23C7-3472-814A-0C722CA5EC52}\InprocServer32\1.0.0.17" Name="CodeBase" Value="file:///[#fil42B81EB2B860BF0A024B0E2A8AABB37B]" Type="string" Action="write" />
 
<File Source="bin\PrintButtons.dll" Name="PrintButtons.dll" Id="PrintButtons.dll" KeyPath="yes" />
<RegistryValue Root="HKCR" Key="CLSID\{74607E91-23C7-3472-814A-0C722CA5EC52}\InprocServer32\1.0.0.17" Name="CodeBase" Value="file:///[#PrintButtons.dll]" Type="string" Action="write" />

Die übrig gebliebenen Werte fügen wir am Ende des Fragment Statement ein und tragen die Komponenten ID noch in unser Feature.

<Component Id="cmpFC41C28EC1A5DDF1B38CB48A5F78258C" Guid="PUT-GUID-HERE">
<Class Id="{74607E91-23C7-3472-814A-0C722CA5EC52}" Context="InprocServer32" Description="PrintButtons.InventorPlotClass+sRotatePlot" ThreadingModel="both" ForeignServer="mscoree.dll">
<ProgId Id="PrintButtons.InventorPlotClass+sRotatePlot" Description="PrintButtons.InventorPlotClass+sRotatePlot" />

Alternativ könnten wir auch ähnlich wie bei Inno Setup auch direkt aus der Setup-Routine regasm aufrufen, aber das ist natürlich nicht im Sinne des Erfinders.

<!--
register dotnet dll with regasm (we use heat.exe to generate registry entries; so this is only a alternative)
<InstallExecuteSequence>
  <Custom Action='comReg' After='InstallFinalize'>NOT REMOVE</Custom>
  <Custom Action='comUnreg' Before='RemoveFiles'>REMOVE</Custom> 
</InstallExecuteSequence>
 
<CustomAction Id='comReg' Directory='INSTALLDIR' ExeCommand='"[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\regasm.exe" "[INSTALLDIR]InventorTools.dll"' Return='check' />
<CustomAction Id='comUnreg' Directory='INSTALLDIR' ExeCommand='"[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\regasm.exe" /u "[INSTALLDIR]InventorTools.dll"' Return='check' />	
-->

Vorteile

  • Kostenlos, setzt auf WiX
  • Erzeugt MSI Dateien

Nachteile

  • Recht kompliziert, da viele Optionen innerhalb der XML Dateien geändert werden müssen (GUI ist noch nicht ausgereift)
  • x64 MSI Paket können nur unter 64Bit System erstellt werden

Inno Setup

Mittels Inno Setup erstellt man ein ISS Skript, welche die nötigen Aktionen durchführt, und Kompiliert diese dann zu einer EXE-Installation.
In meinem erstellten Skript werden die Installationsdatei kopiert, und regasm entsprechend den x64 und x86 Pfaden ausgeführt. Durch setzen der Variable ArchitecturesInstallIn64BitMode kann ein und die gleiche Setuproutine für x64/x86 genutzt werden. Schließlich holt die Routine noch den Pfad der Framework Installation aus der Windows-Registrierung, insofern kein .NET installiert ist, gibt die Routine einen Hinweis aus und bricht ab.

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
 
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{C8207074-1437-48AB-863E-4359939487E6}
AppName=Inventor-DruckButtons
AppVerName=Inventor-DruckButtons
AppVersion=2.0
DefaultDirName={pf}\Inventor-Addins\DruckButtons
DisableProgramGroupPage=yes
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
VersionInfoVersion=2.0
VersionInfoProductName=Inventor-DruckButtons
ArchitecturesInstallIn64BitMode=x64 ia64
 
[Code]
 
function InitializeSetup(): Boolean;
var
    NetFrameWorkInstalled : Boolean;
    Result1 : Boolean;
begin
 
      NetFrameWorkInstalled := RegKeyExists(HKLM,'SOFTWARE\Microsoft\.NETFramework\policy\v2.0');
      if NetFrameWorkInstalled =true then
      begin
            Result := true;
      end;
 
      if NetFrameWorkInstalled = false then
      begin
            NetFrameWorkInstalled := RegKeyExists(HKLM,'SOFTWARE\Microsoft\.NETFramework\policy\v2.0');
            if NetFrameWorkInstalled = true then
            begin
 
                  Result := true;
            end;
 
            if NetFrameWorkInstalled =false then
                  begin
                        Result1 := MsgBox('This setup requires the .NET Framework 2.0. Please download and install the .NET Framework and run this setup again.',
                                    mbConfirmation, MB_OK) = idYes;
                        if Result1 =false then
                        begin
                              Result:=false;
                        end
                        else
                        begin
                              Result:=false;
                              //Run the .NET redistributable here using shellexec.
          end;
      end;
      end;
end;
 
 
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
 
[Files]
Source: "icos\*"; DestDir: "{app}\icos"; Flags: ignoreversion recursesubdirs createallsubdirs;
Source: "install\*"; DestDir: "{app}\install"; Flags: ignoreversion recursesubdirs createallsubdirs;
Source: "drucker.xml"; DestDir: "{app}"; Flags: ignoreversion;
Source: "DruckButtons.dll"; DestDir: "{app}"; Flags: ignoreversion;
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
 
 
[run]
Filename:"{reg:HKLM\SOFTWARE\Microsoft\.NETFramework,InstallRoot}\v2.0.50727\RegAsm.exe"; Parameters: /codebase DruckButtons.dll;WorkingDir: {app}; StatusMsg: "Registering controls ..."; Flags: runhidden;
 
[UninstallRun]
Filename:"{reg:HKLM\SOFTWARE\Microsoft\.NETFramework,InstallRoot}\v2.0.50727\RegAsm.exe"; Parameters: /unregister DruckButtons.dll;WorkingDir: {app}; StatusMsg: "Unegistering controls ..."; Flags: runhidden;

Vorteile

  • Kostenlos
  • Erzeugt eine Setupdatei für x64 und x86; die Pfade werden automatisch angepasst

Nachteile

  • Erzeugt EXE Setup, keine MSI möglich
  • Regasm.exe wird bei der Installation ausgeführt

Microsoft Visual Studio

Man möchte meinen, dass Microsoft mit Visual Studio gerade für .NET Anwendung eine einfache Lösung parat hat, dem ist allerdings nicht so. Mithilfe eines Setupprojektes lässt sich ohne weiteres eine MSI-Datei erstellen. Zur Registrierung von Addins steht dann allerdings keine Option zur Verfügung.
Hierzu muss man sich ein „Benutzerdefiniertes Event“ erstellen, welches nach der Installation der Dateien, innerhalb einer .NET Bibliothek eine Install bzw Uninstall Methode aufruft. Ein komplettes Beispiel Projekt findet sich im Autodesk Forum (SimpleAddIn).

[...]
public override void Install(IDictionary stateSaver)
{
	base.Install (stateSaver);
 
	RegistrationServices regsrv = new RegistrationServices();
	regsrv.RegisterAssembly(base.GetType().Assembly, AssemblyRegistrationFlags.SetCodeBase);
}
 
public override void Uninstall(IDictionary savedState)
	{
	base.Uninstall (savedState);
 
	RegistrationServices regsrv = new RegistrationServices();
	regsrv.UnregisterAssembly(base.GetType().Assembly);
}
[...]

Vorteile

  • Keine Zusatztools nötig, alles kann über Visual Studio erledigt werden
  • Erzeugt MSI Dateien

Nachteile

  • Setuppakte können nicht mit der kostenlose Express Version erstellt werden
  • Installationsroutine muss bereits in der DLL integriert werden

Batch-Datei

Zu Testzwecken nutze ich eine einfache Batchdatei, die für x64 und x86 die regasm aus den unterschiedlichen .NET Framework Pfaden ausführt und die DLL registriert.

@echo off
IF %PROCESSOR_ARCHITECTURE% == AMD64 GOTO x64
IF %PROCESSOR_ARCHITECTURE% == x86 GOTO x86
echo unbekannter CPU-Typ
 
:x86
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe /codebase "%ProgramFiles%\Autodesk\Druckbuttons\DruckButtons.dll"
echo x86 - RegAsm
goto ende
 
:x64
C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\RegAsm.exe /codebase "%ProgramFiles%\Autodesk\Druckbuttons\DruckButtons.dll"
echo x64 - RegAsm
goto ende
 
:ende