Visual Studio Installer: Custom Actions in eigener Installer Class - Office Development is more than VBA - Site Home - MSDN Blogs

Visual Studio Installer: Custom Actions in eigener Installer Class

Visual Studio Installer: Custom Actions in eigener Installer Class

  • Comments 0

Bin ich doch wieder mal mit meiner eigenen Vergangenheit kollidiert. Wo? Beim Schreiben einer Installationsroutine für ein Outlook Add-In. Welche? MSI.

Wie gesagt, ich hatte vor, ein MSI Package zu erzeugen, welches ein Outlook Add-In [erzeugt mit VSTO 2005 SE] installiert und gleichzeitig auch noch die Trust Relationship [Code Access Security] setzt. Also eine Code Group anlegt und - basierend auf dem Strong Name, mit dem die DLL signiert wurde - FullTrust setzt. Gesagt - getan. Installer Class als neues Item der DLL hinzufügen und Install oder Commit, UnInstall und Rollback überschreiben:


public override void Install(System.Collections.IDictionary stateSaver)
{
   base.Install(stateSaver);
   CreatePolicy("User", "ContactManager", "CodeGroup for VSTO AddIn for Outlook");
}

Dann noch die Custom Actions im Setup mit der DLL verbinden:

... und es sollte funktionieren. So hatte ich mir das gedacht.

Beim Installieren unter Windows Vista bekam ich dann prompt die Quittung: Error 2867. Im Log (msiexec /i <package name> /l*v <Logfile>) stand dann folgendes:

 

MSI (s) (9C:20) [17:19:41:665]: Executing op: CustomActionSchedule(Action=_6B611CFE_8C2D_44E5_9087_8802C25060B3.install, ActionType=1025, Source=BinaryData, Target=ManagedInstall, CustomActionData=/installtype=notransaction /action=install /LogFile= /InstallPath="C:\Program Files\..." "C:\Program Files\..." "C:\Users\<username>\AppData\Local\Temp\CFG2322.tmp")

MSI (s) (9C:94) [17:19:41:665]: Invoking remote custom action. DLL: C:\Windows\Installer\MSI277A.tmp, Entrypoint: ManagedInstall

MSI (s) (9C!70) [17:19:41:743]: Note: 1: 2262 2: Error 3: -2147287038
MSI (s) (9C!70) [17:19:41:743]: Note: 1: 2262 2: Error 3: -2147287038
MSI (s) (9C!70) [17:19:41:743]:
MSI (s) (9C:94) [17:19:41:743]: Leaked MSIHANDLE (12) of type 790531 for thread 5744
MSI (s) (9C:94) [17:19:41:743]: Note: 1: 2769 2: _6B611CFE_8C2D_44E5_9087_8802C25060B3.install 3: 1
MSI (s) (9C:94) [17:19:41:743]: Note: 1: 2262 2: Error 3: -2147287038

Error 1001.
DEBUG: Error 2769:  Custom Action _6B611CFE_8C2D_44E5_9087_8802C25060B3.install did not close 1 MSIHANDLEs.

The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2769. The arguments are: _6B611CFE_8C2D_44E5_9087_8802C25060B3.install, 1,


Schwach erinnerte ich mich der verschiedenen Typen für Custom Actions und suchte heraus, was 'ActionType=1025' bedeutet.

msidbCustomActionTypeInScript (1024)
Queues for execution at scheduled point within script. This flag designates that this is a deferred execution custom action.

+ (bzw. OR)

msidbCustomActionTypeDll + msidbCustomActionTypeBinaryData (1)

Der Process wird von InstallUtil.exe ausgeführt und läuft by default im Security Context des angemeldeten Benutzers. Und hier liegt der Hase im Pfeffer. Beim Start des MSI Pakets kommt der Prompt für elevated Execution. Wenn ich das erlaube, wird das Setup als Admin ausgeführt, nur eben nicht die Custom Action, die weiterhin im User Context läuft. Das ist fatal, wenn sie Admin Rechte benötigt.

Um das Problem zu lösen, muß die Typinformation um msidbCustomActionTypeNoImpersonate (2048) erweitert werden. Daraus ergibt sich Typ 3073. Damit wird der CA (InstallUtil) Process nicht impersoniert und läuft als Admin (bzw. im LocalSystem Account). Der Typ kann auch für die UnInstall Custom Action verwendet werden. Für die RollBack Custom Action kommt noch msidbCustomActionTypeRollback (256) hinzu, was dann zum Wert 3329 führt.

Die Änderungen lassen sich leider nicht direkt im Visual Studio Installer durchführen, sondern man muß sich ein Tool aus dem MSI SDK (Bestandteil des Windows Plattform SDK) namens ORCA holen. Damit kann das fertige MSI Paket geladen und modifiziert werden (in unserem Fall die CustomActions Table).

Übrigens, wie Code Groups und Trust Relationships programmatisch angelegt werden, finden Sie hier bzw. hier. Für den Fall, daß eine StrongNameMembershipCondition verwendet werden soll, kann der Public Key so ermittelt werden:

Assembly thisAsm = this.GetType().Assembly;
AssemblyName asmName = thisAsm.GetName();
byte[] asmKey = asmName.GetPublicKey();
StrongNamePublicKeyBlob snPKBlob = new StrongNamePublicKeyBlob(asmKey);
StrongNameMembershipCondition snMemCond = new StrongNameMembershipCondition(snPKBlob, null, null);