Groups | Blog | Home
all groups > visual studio .net setup > april 2004 >

visual studio .net setup : Possible design flaw in windows installer during an uninstall/install.


Dave
4/9/2004 4:27:09 AM
I've run into what appears to be a bug/design flaw in windows installer.
This occurs when an MSI file is configured so that it will automatically
uninstall a previously installed older version before running the install of
the new version, and the MSI file contains a custom action that is to be run
in managed code in one of the assemblies that is to be updated to a newer
version.

I added diagnostics to the custom action so that it printed out to a trace
listener the version number of the executing assembly. I then built two
versions of the MSI file, each time changing the version number of the
assembly and the MSI file.

I installed the older version and then ran the install of the newer version.
When running the install of the newer version it correctly detected the
older version and 1st uninstalled it - when it ran the custom action during
the uninstall the version number of the old assembly was printed out. It
then ran the install of the newer version. When it ran the custom action in
what was supposed to be the new assembly it printed out the version number
of the old assembly (that was supposedly uninstalled).

The bits on disk were correct but the wrong assembly was executing code!

It appears that windows installer creates a single appdomain and executes
all custom actions from within the default appdomain. It appears that it
never recycles the appdomain between the time the uninstall completes and
before the install begins - if so, then this is a major problem.

The problem is that once an assembly is loaded into an appdomain it stays
loaded and cannot be unloaded from that appdomain. Once the original
assembly is loaded, even if a newer version of it is on disk the fusion
layer will ignore it and continue to run the version that has been loaded.
The assembly was not signed with a strong name, but I would expect this
behavior even if it was signed. The result is that code in the original
assembly is executing when that assembly should have been deleted.

It may be that windows installer expects shadow copying to permit this (I'm
guessing that's what it uses) but if so, this is a faulty assumption.

If the installer wants to execute only once the code that hosts the CLR,
then it should run all custom actions in managed code from a second
appdomain, and then unload that appdomain after the uninstall and reload it
for the install. That is the only way to unload all the assemblies that have
been loaded without unloading the entire CLR.

So...I'm wondering if my analysis is correct, and if anyone else has run
into this. And I'm also wondering if there's a workaround other then forcing
users to manually uninstall the old version before installing the new
version.

Thanks
David Levine

Phil Wilson
4/9/2004 10:11:48 AM
You're right, I think this is a bug that the Windows Installer team is aware of.
It's not quite as exotic as you describe. Once MSI has loaded a DLL (any kind of
DLL) to call a custom action, it doesn't load another copy with the same name,
even though it's a different version. It's most common in the major upgrade
scenario you describe. See the thread "Windows Installer bug when same custom
action called twice" in platformsdk.msi, starting 3/16/2004.
--
Phil Wilson [MVP Windows Installer]
----
[quoted text, click to view]

Dave
4/10/2004 6:58:40 AM
Thanks for the link to that thread. After reading that thread I am not sure
if this is the same problem.

From what I could gather from that thread the windows installer will not
load the same DLL twice (as determined by its simple name), but it also
sounds as if it uses a different algorithm for loading native .net
assemblies. The thread mentions that it invokes actions in .net assemblies
by going through the InstallUtilLib.dll layer instead of loading it
directly. In this other thread's case an assembly of the same name was in
two different locations at install time. This could have been a problem
because MSI does not invoke the same named assembly twice, and it could also
be because of the way the CLR runtime loads assemblies and resolves
references - the fusion layer in .net could be the source of the problem. If
the assembly is identical in both merge modules (same name, strong name,
etc) then fusion will not load the 2nd copy since the 1st assembly satisfies
all the binding requirements.

The part I am unclear on in my situation is how the installer can invoke the
method in the old assembly when that assembly has been deleted as part of
the uninstall process.

The situation I have is:

1. Old assembly exists. Invoke uninstall custom action, then remove assembly
(all files and directories are blown away).
2. New assembly gets installed at same location as old one (new directories
are created exactly as old directory layout and new files copied in).
3. Invoke install custom action.

In step 3, the custom action invoked is running code in the old assembly
even though that assembly has been removed. To verify this I printed out
the assembly version number from within the install routine and its the old
version number. It sounds like it's keeping a copy of the assembly loaded in
memory (or in another location) even though the bits have been deleted.

Is this the same problem as the one in the thread you mentioned?

Any insight into this is appreciate. Thanks.

Dave



[quoted text, click to view]

Phil Wilson
4/10/2004 1:43:51 PM
A couple of thoughts:
I think the issue isn't so much MSI or InstallUtilLib.Dll, it's just that
the LoadLibrary API ends up not loading the "same" DLL into the process no
matter which piece of code calls it, most likely because each is not loaded
using a unique full path. If you LoadLibrary("x.dll") twice, the second call
won't load another copy. That's my guess at why this might be happening.
Regarding the fusion stuff, I don't think it's heavily involved. You can see
the parameters passed to the ManagedInstall call, and none of them specify a
strong name or version of the custom action assembly, so I'm guessing that
locating the assembly isn't using strong names or assemblyversions.

You're probably right that the assembly stays loaded in the process even
though the file has been removed, so the custom action called from the new
install doesn't load the new assembly DLL that has the same name.
--
Phil Wilson
[MVP Windows Installer]
[quoted text, click to view]

Dave
4/11/2004 10:14:14 AM

[quoted text, click to view]

Could be. The loading rules for .net are very different then for win32. I'm
reserving the right to disagree later on :-)


[quoted text, click to view]

If the assembly wasn't signed then all that is needed is the simple name. If
the assembly was signed with a strong name but the parameters used to invoke
the custom action did not specify a full name (simple name, strong name,
culture, and version) then this would be a major flaw. It should be possible
to install two assemblies, each with the same simple name, but both signed
with a strong name and of a different version, and invoke custom actions in
each (they would need to be in different folders to avoid naming conflicts
with the file system). I say "should" because I haven't tried this with MSI,
but this loading two assemblies of the same simple name but with different
full names is definitely supported in .net itself.

I would think that if the target of the custom action then MSI would defer
all assembly loading to the InstallUtilLib.Dll, which should have been smart
enough to handle this. But there I go assuming again...

[quoted text, click to view]

Yah, that's pretty scary :-) I wonder how they pulled that one off...

Thanks for the feedback. If I learn anything further from MSFT I'll post
what I find out up here.


Phil Wilson
4/11/2004 10:56:36 AM
I think MSI *does* defer assembly loading to InstallUtilLib, but
InstallUtilLib doesn't know anything about the sn or version of the assembly
it should load. I think it's basically a shim to host the runtime and use
the AssemblyInstaller class, passing the command line.
--
Phil Wilson
[MVP Windows Installer]
[quoted text, click to view]

AddThis Social Bookmark Button