New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

COM+ .NET assembly upgrade works not correctly #5679

Open
rzinnatullin opened this Issue Sep 10, 2017 · 0 comments

Comments

Projects
None yet
2 participants
@rzinnatullin

rzinnatullin commented Sep 10, 2017

Pre-requisites

  • Wix 3.11 (I believe the issue is applicable to Wix 4 as well)
  • Visual Studio 2015 Ent Update 3 (14.0.25431.01)
  • WiX Toolset Visual Studio Extension 0.9.21.62588?
  • .NET 4.0
  • Windows Server 2012 R2

Reproduction steps

  1. Create simple 32-bit .NET assembly with a COM+ component on-board (assembly name TestAsm.dll, version 1.0.0.0)
  2. Create simple installer that uses WixComPlusExtension to register the assembly (set installer's version to 1.0.0.0)
  3. Build the installer (outcome - installer 1)
  4. Set the assembly's version to 1.1.0.0
  5. Set the installer's version to 1.1.0.0
  6. Rebuild the installer (outcome - installer 2)
  7. Run installer 1 - it'll successfully install the assembly and register it in a COM+ application.
  8. Run installer 2 - it'll upgrade the assembly and re-register it in the COM+ application.
  9. Open regedit.exe and expand HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{ComPlusComponentGuid}\InprocServer32 (replace ComPlusComponentGuid with the component's GUID.
  10. Check Assembly value. It references previous version of the assembly (1.0.0.0).

Expected behaviour

  1. Assembly value should reference new version of the assembly (1.1.0.0)

Root cause

WixComPlusExtension uses RegistrationHelper class (System.EnterpriseServices.dll) to install and uninstall .NET COM+ assemblies. Let's have a look at steps happening during the upgrade:

  1. RegistrationHelper.UninstallAssembly(@"c:\Program Files (x86)\TestSetup1\TestAsm.dll", ... other args)
  2. Move "c:\Program Files (x86)\TestSetup1\TestAsm.dll" to some temporary location
  3. Extract new TestAsm.dll from new package and put it to "c:\Program Files (x86)\TestSetup1\TestAsm.dll"
  4. RegistrationHelper.InstallAssembly(@"c:\Program Files (x86)\TestSetup1\TestAsm.dll", ... other args)

Everything seems fine. Let's note some significant facts:

  1. Uninstallation and new installation is done in the scope of the same process.
  2. RegistrationHelper.UninstallAssembly loads the assembly into an Application Domain.
  3. Assemblies loaded to an App Domain could not be unloaded unless the App Domain is unloaded.
  4. Assembly file loaded to an App Domain cannot be deleted, however it can be moved/renamed (like in step 2 of the upgrade steps above).
  5. .NET won't load the same assembly twice into one App Domain (it'll use the loaded one).
  6. .NET checks that an assembly is already loaded by it's name (at least when we call Install/UninstallAssembly, because we specify assembly by it's file name only).

Now let's expand the steps that happen during the upgrade:

  1. RegistrationHelper.UninstallAssembly(@"c:\Program Files (x86)\TestSetup1\TestAsm.dll", ... other args)
  • TestAsm.dll (1.0.0.0) is loaded into an App Domain
  • It is successfully unregistered from COM+ Catalog
  1. Move TestAsm.dll to some temporary location
  • There is no more TestAsm.dll in c:\Program Files (x86)\TestSetup1 folder
  1. Extract new TestAsm.dll from new package and put it to "c:\Program Files (x86)\TestSetup1\TestAsm.dll"
  • We have TestAsm.dll of version 1.1.0.0 in c:\Program Files (x86)\TestSetup1 folder
  1. RegistrationHelper.InstallAssembly(@"c:\Program Files (x86)\TestSetup1\TestAsm.dll", ... other args)
  • .NET checks that there is TestAsm.dll in c:\Program Files (x86)\TestSetup1 (I don't actually know why it even checks the file's existence if it won't load it again).
  • .NET checks that an assembly with the specified name is already loaded into App Domain and doesn't load the new TestAsm.dll.
  • InstallAssembly registers TestAsm.dll of previous version (1.0.0.0) that was loaded into App Domain during UninstallAssembly (see step 1).

Note that this is possible during upgrading because the upgrading is done in the scope of the same process and App Domain created in the first step is not unloading until the process is done.

How to resolve

WixComPlusExtension has another significant issue - it doesn't register .NET 4.0 (and higher) assemblies, because by default it loads CLR of version 2 that cannot load 4.0 assemblies into an App Domain. I think the issues could be resolved if registration/unregistration commands run in a separate process that would load correct version of CLR and would unload immediately after registration/unregistration is done.

@barnson barnson added this to the v4.x milestone Sep 14, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment