Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Sequencing of StartServices and RemoveExistingProducts

261 views
Skip to first unread message

ShadowChaser

unread,
Mar 25, 2010, 12:01:02 PM3/25/10
to
What's the correct sequencing of the StartServices action in regards to
RemoveExistingProducts?

We have a scenario where we are trying to perform a major upgrade without
removing the user's data files and configuration. If we sequence
RemoveExistingProducts just before InstallInitialize or just after
InstallInitialize, the old version gets uninstalled and all of the settings
and configuration files are deleted.

If we sequence RemoveExistingProducts between InstallExecute and
InstallFinalize, the user settings are kept intact but the new version of our
Windows service is started *before* the old version is uninstalled. Our
service depends on plugins, and this has the unfortunate effect of loading
*both* the new plugins and the old ones at the same time! Not only that, the
old plugins get deleted out from under the service when the "commit" takes
place.

What are the best practices in this case - rewriting the entire service with
a different plugin loader isn't an option :)

Wilson, Phil

unread,
Mar 25, 2010, 1:29:12 PM3/25/10
to
I'm missing something in that second scenario. The entire install of the new
product version takes place before the old one is uininstalled. That
includes replacement of plug-in files, surely? I don't see how old plugins
are being loaded when all new files have been installed. But maybe your
reference to Commit means the updated plugins are in the GAC? If so, is it
an option to have them in the normal file system?

Otherwise I think you'd have to give up on the ServiceControl table and have
a custom action start your newly-installed service after
RemoveExistingProducts in a Commit custom action if you have the GAC
problem, but that's not exactly ideal.

--
Phil Wilson
The Definitive Guide to Windows Installer
http://www.apress.com/book/view/1590592972


"ShadowChaser" <Shadow...@discussions.microsoft.com> wrote in message
news:2407AFB3-B76D-4C76...@microsoft.com...

ShadowChaser

unread,
Mar 25, 2010, 2:37:02 PM3/25/10
to
I forgot to mention that we are removing one of the plugins - effectively
we're seeing three upgraded plugins load and the one "removed" old plugin.

The plugins are loaded based on filename, unfortunately. The original design
made the filenames the same as the CLSIDs of the COM objects they host. The
server startup code lists the filenames and creates the COM objects. In the
case of the upgrade, the old plugin DLLs are still in the directory and
registered at the time the upgraded service starts.

There might be a case I'm missing though - I'm infering the behavior based
on the MSI installation logs and our service startup logs showing 4 plugins
loading instead of 3. When I look at the plugin directory, I see three files.
Everything seems to point to the fact the old plugins exist on disk in their
original names and are still registered.

Wilson, Phil

unread,
Mar 26, 2010, 11:31:28 AM3/26/10
to
I still don't see how this is happening. Everything is installed and
replaced before StartServices will start up the new service which should
load newly installed plug-ins. If there were some files in-use then that
might have an effect and if file versions weren't incremented in all
plug-ins there would be "old" ones remaining.

What exactly does "registered" mean? Is this COM? And you're sure there is
nothing in the GAC? There are definitely issues if you do an upgrade and
register COM assemblies in the GAC because of that darn behavior of
assemblies not being available in the GAC until Commit time, because you've
written a whoile bunch of registry entries referring to an assembly in the
GAC that is not in fact there yet.

--
Phil Wilson
The Definitive Guide to Windows Installer
http://www.apress.com/book/view/1590592972


"ShadowChaser" <Shadow...@discussions.microsoft.com> wrote in message

news:4C5CAE7F-35E3-41B5...@microsoft.com...

ShadowChaser

unread,
Mar 26, 2010, 3:49:02 PM3/26/10
to
Definitely nothing in the GAC. We have a few "xcopied" .NET assemblies, some
COM/ATL dlls (including the plugins) and a COM/ATL service.

ShadowChaser

unread,
Mar 26, 2010, 4:21:01 PM3/26/10
to
Dug through the verbose logs of an upgrade, here's what I'm seeing:

MSI (s) (AC:A4) [13:09:19:792]: Doing action: StartServices
MSI (s) (AC:A4) [13:09:19:800]: Doing action: InstallExecute
MSI (s) (AC:A4) [13:09:23:896]: Executing op: ServiceControl(,Name=<our
service name>,Action=1,Wait=1,)

Action start 13:09:25: RemoveExistingProducts.

MSI (s) (AC:88) [13:09:29:183]: Executing op: FileRemove(,FileName=<removed
plugin>.dll,,ComponentId={DB87FB19-3555-43DE-87B9-39C02833DD5C})

We have InstallExecute sequenced at 6500, RemoveExistingProducts sequenced
at 6501, and InstallFinalize at 6600.

The InstallExecute block includes all of the "new install" actions including
"StartServices", while the old plugin removal happens in
RemoveExistingProducts. Idealy MSI would let us schedule
RemoveExistingProducts "in" the InstallExecute block.

Looks like a custom action is the only choice? :(

vijaygos

unread,
Apr 28, 2010, 11:40:01 PM4/28/10
to
Phil,
I am Sorry. Sort of new to the Visual Studio project thingy. I was
trying to get the update working for my project from a 5.0.0 version to a
5.0.1 version.
I was following the instructions given by you on your web site
http://www.simple-talk.com/dotnet/visual-studio/updates-to-setup-projects/
I have a new product code and the same upgrade code as expected.
Correct me if I am wrong here. I was under the impression that the old
product is first uninstalled and then the newer version is installed.
But I tested my first upgrade scenario this morning and I found it to be the
other way around. The installation was happening first and then the
uninstallation of my old version. There is a custom Install script that I
execute in the Uninstall operation. This sort of messes up my entire
installation in the current sequence (install new version and then remove the
old version).
Is this behavior correct?
I opened up the msi file using Orca. In the InstallExecuteSequence table, I
see that the InstallExecute operation has a sequence number 6500 and the
RemoveExistingProducts a sequence number 6550. Can I swap the two and expect
it to work the way I want to (i.e. remove old version first and then install
new version) ?? Thanks in advance.

Vijay

Kalle Olavi Niemitalo

unread,
Apr 29, 2010, 3:41:26 PM4/29/10
to
vijaygos <vija...@discussions.microsoft.com> writes:

> I opened up the msi file using Orca. In the InstallExecuteSequence table, I
> see that the InstallExecute operation has a sequence number 6500 and the
> RemoveExistingProducts a sequence number 6550. Can I swap the two and expect
> it to work the way I want to (i.e. remove old version first and then install
> new version) ??

I assume RemoveExistingProducts would then be preceded by
PublishProduct and followed by InstallExecute. That would
violate the sequence restrictions for RemoveExistingProducts:
http://msdn.microsoft.com/en-us/library/aa371197(VS.85).aspx

If I understand correctly, you want to remove the old version
before starting the service, but not let the user's configuration
files be deleted. Phil Wilson suggested starting the service
with a commit custom action, and that should indeed work.
Other options might include:

- If the user configuration files are in a separate feature in
the old version (seems unlikely), then you could set the
Upgrade table of the new version so that it uninstalls all
other features of the old version but leaves that one
installed.

- Define custom actions that copy or move the data to a safe
place before the old version is removed, then restore it.
This approach seems very error-prone.

- Create a separate MSI package that contains just the
configuration files, with the correct component codes. Then
make a bootstrapper install this configuration-file package,
uninstall the old version, install the new version, and
optionally uninstall the configuration-file package. This
should stop Windows Installer from removing the configuration
files when uninstalling the old version.

- Use the RemoveFile table to directly remove the plugins of the
old version before starting the service, even though the old
version has not yet been uninstalled at that time and Windows
Installer expects the files to still be there. I suppose you
cannot do this if you use self-registration for the plugins.

Overall, the commit custom action seems the easiest and safest
solution.

vijaygos

unread,
Apr 30, 2010, 12:21:01 AM4/30/10
to
Thanks a lot. Great help. Really really appreciate it.
I went through the msdn link and I decided to move the
RemoveExistingProducts in between the InstallValidate action and the
InstallInitialize action as described in that link. This did the trick for me.
My old version is first uninstalled. This runs the custom action uninstall
script of the old version as well. The new version is then installed and the
custom install action in the new version is then executed. which does
everything the way I want it to be done.
But there seems to be a small glitch in this process. I use the select
folder dialog to allow users to select a folder during installation. While
performing an update, it seems really odd to ask the user to pick a folder
once again. Some users may chose to pick a different folder during an update.
Isn't this sort of odd?
I have a configuration file in my setup project. There may be instances when
the user of my application may want to retain the settings after an update.
For this purpose, I decided to mark the configuration file as "permanent".
This way, the file would never be overwritten. But by allowing users to
select an alternate folder, I would run into a scenario where I will have to
install a new configuration file in the new location. I like the idea of
copying the old configuration file from the old location to the new one using
a custom action. But my question is, how would I know what my old path was?
I have a registry that has this path stored. But by the time the custom
action from the new version kicks in, the old version uninstalls this
registry key as well (as the uninstall of the old version is performed
first). Is there any way I can run certain custom actions based on the
operation thats' performed. For instance, I would not want to delete the
registry key, if an update is performed but I would like to remove it if it
is an "Uninstall". I saw that there is a property (condition) called
"Installed" to differentiate between an Install and a repair. Is there
anything for an update and an Uninstall as well ?
Thanks once again for the help.

"Kalle Olavi Niemitalo" wrote:

> .
>

Wilson, Phil

unread,
May 4, 2010, 1:21:37 PM5/4/10
to
It's not actually an update. If it was only an update it would do something
only if the base product was installed, like a patch does. It's a Windows
Installer major upgrade, and will work as a fresh install too. Also, Visual
Studio setups don't give you the option of skipping the browse folder dialog
on an upgrade, but you could use Orca and the ControlCondition table to
Hide/Disable the Browse button if it's an upgrade (PREVIOUSVERSIONSINSTALLED
is, I think, the property name VS uses).

--
Phil Wilson
The Definitive Guide to Windows Installer
http://www.apress.com/book/view/1590592972

"vijaygos" <vija...@discussions.microsoft.com> wrote in message
news:5F339C1D-F669-4AAD...@microsoft.com...

0 new messages