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

CustomAction that sets ProductName

8 views
Skip to first unread message

Steven Bethard

unread,
Apr 30, 2009, 1:31:12 PM4/30/09
to
I need to modify the ProductName at runtime [1]. Currently, I have a
CustomAction registered that does something like:

Session.Property("ProductName") = ... new calculated name ...

This seems to mostly work, e.g. titles and stuff in the MSI interface
display the new ProductName correctly. However, the updated ProductName is
not used for the entry in Add/Remove Programs. Inspecting the MSI log, I see:

Property(S): ProductName = argparse-0.9.1
...
Property(C): ProductName = Python 2.6 argparse-0.9.1

The client (C) ProductName is the one that my script set, while the server
(S) ProductName is the one that Add/Remove Programs appears to be using.

I'm therefore guessing I need to set the ProductName for the server to fix
my problem. How do I do that? My CustomAction is called in both
InstallUISequence and InstallExecuteSequence, so that doesn't seem to be the
problem. Other ideas?

Thanks in advance,

Steve

[1] In case you're curious why I need to do this, I'm working on the code
that generates Windows Installers for Python modules. When a user installs a
new Python module, they need to select the version of Python to install it
with. Thus, the same MSI needs to be able to generate multiple entries in
Add/Remove Programs: "Python 2.4 XXXmoduleXXX", "Python 2.5 XXXmoduleXXX",
etc.

Richard [Microsoft Windows Installer MVP]

unread,
Apr 30, 2009, 5:03:36 PM4/30/09
to
[Please do not mail me a copy of your followup]

=?Utf-8?B?U3RldmVuIEJldGhhcmQ=?= <Steven...@discussions.microsoft.com> spake the secret code
<4B8DEAB6-5EE0-4A4A...@microsoft.com> thusly:

>[1] In case you're curious why I need to do this, I'm working on the code
>that generates Windows Installers for Python modules. When a user installs a
>new Python module, they need to select the version of Python to install it
>with. Thus, the same MSI needs to be able to generate multiple entries in
>Add/Remove Programs: "Python 2.4 XXXmoduleXXX", "Python 2.5 XXXmoduleXXX",
>etc.

This isn't going to work... you really want to parameterize your build
process and generate unique product MSIs for each module or some other
solution.
--
"The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download
<http://www.xmission.com/~legalize/book/download/index.html>

Legalize Adulthood! <http://blogs.xmission.com/legalize/>

Steven Bethard

unread,
Apr 30, 2009, 8:53:01 PM4/30/09
to
"Richard [Microsoft Windows Installer MVP" wrote:
> StevenBethard spake thusly:

> >[1] In case you're curious why I need to do this, I'm working on the code
> >that generates Windows Installers for Python modules. When a user installs a
> >new Python module, they need to select the version of Python to install it
> >with. Thus, the same MSI needs to be able to generate multiple entries in
> >Add/Remove Programs: "Python 2.4 XXXmoduleXXX", "Python 2.5
> > XXXmoduleXXX", etc.
>
> This isn't going to work... you really want to parameterize your build
> process and generate unique product MSIs for each module or some other
> solution.

Could you explain why it won't work? Is it because MSI doesn't allow
ProductName and ProductCode to be changed at install time or something like
that?

Note that most Python code works with many versions of Python, so it's very
common to run a Python module that was written with, say, Python 2.5, on
machines that only have Python 2.4 or 2.6 installed. The only things that
change between installing a module for Python 2.4 and installing a module for
Python 2.6 are the TARGETDIR and the product name.

Is there any other solution which doesn't require generating a different MSI
for each Python version? If that's the only solution, I'm going to recommend
that Python abandon the .msi installers and go back to the .exe installers it
was using before (since these did support a single installer that worked with
any Python version).

Bob Arnson [MSFT]

unread,
May 1, 2009, 7:05:13 AM5/1/09
to Steven Bethard
Steven Bethard wrote:
> Note that most Python code works with many versions of Python, so it's very
> common to run a Python module that was written with, say, Python 2.5, on
> machines that only have Python 2.4 or 2.6 installed. The only things that
> change between installing a module for Python 2.4 and installing a module for
> Python 2.6 are the TARGETDIR and the product name.
>
> Is there any other solution which doesn't require generating a different MSI
> for each Python version?

Your approach is doesn't fit the MSI model, so use a simpler one that
does: Use multiple features, one for each version of Python you support.

That also lets you avoid custom actions, which are discouraged,
especially VBScript custom actions, which are highly discouraged.

Bob

Steven Bethard

unread,
May 1, 2009, 12:17:01 PM5/1/09
to

"Bob Arnson [MSFT]" wrote:

> Steven Bethard wrote:
> > Note that most Python code works with many versions of Python, so it's very
> > common to run a Python module that was written with, say, Python 2.5, on
> > machines that only have Python 2.4 or 2.6 installed. The only things that
> > change between installing a module for Python 2.4 and installing a module for
> > Python 2.6 are the TARGETDIR and the product name.
> >
> > Is there any other solution which doesn't require generating a different MSI
> > for each Python version?
>
> Your approach is doesn't fit the MSI model, so use a simpler one that
> does: Use multiple features, one for each version of Python you support.

Can you give me a hint on how to go about this? I'm guessing it would look
something like:

* Add a row to the Feature table for each possible version of Python
* Add duplicates of the current Components for each possible version of Python
* Map features to components in the FeatureComponents table
* Have a separate <version>TARGETDIR for each version
* At install time, for each version:
* Look up SOFTWARE\Python\PythonCore\<version> using RegLocator
* If absent, set the feature Display and/or Level to 0 somehow...
* If present, set the <version>TARGETDIR
* Let the user select one or more versions (features) to install the module to

Does that seem about right?

Phil Wilson

unread,
May 1, 2009, 2:21:41 PM5/1/09
to
If you can do a command line install in your environment then you could look
at creating a transform to change those, then launch with the transform in
the command line.
--
Phil Wilson

"Steven Bethard" <Steven...@discussions.microsoft.com> wrote in message
news:4B8DEAB6-5EE0-4A4A...@microsoft.com...

Steven Bethard

unread,
May 1, 2009, 9:26:01 PM5/1/09
to
"Steven Bethard" wrote:

> "Bob Arnson [MSFT]" wrote:
> > Your approach is doesn't fit the MSI model, so use a simpler one that
> > does: Use multiple features, one for each version of Python you support.
>
> Can you give me a hint on how to go about this? I'm guessing it would look
> something like:
>
> * Add a row to the Feature table for each possible version of Python
> * Add duplicates of the current Components for each possible version of Python
> * Map features to components in the FeatureComponents table
> * Have a separate <version>TARGETDIR for each version
> * At install time, for each version:
> * Look up SOFTWARE\Python\PythonCore\<version> using RegLocator
> * If absent, set the feature Display and/or Level to 0 somehow...
> * If present, set the <version>TARGETDIR
> * Let the user select one or more versions (features) to install the module to
>
> Does that seem about right?

I played around with this a bit, but I'm stuck on the TARGETDIR part. Orca
tells me that "Only TARGETDIR or its children can have files". But I
potentially need to install files to multiple Python installations, e.g.
C:\Python24 and C:\Python25. I can use RegLocator etc. to set TARGETDIR to
one or the other of these, but not both as far as I can tell. I guess I could
set TARGETDIR to C: but that seems a little odd...

Kalle Olavi Niemitalo

unread,
May 2, 2009, 1:56:29 AM5/2/09
to
Steven Bethard <Steven...@discussions.microsoft.com> writes:

> I played around with this a bit, but I'm stuck on the TARGETDIR part. Orca
> tells me that "Only TARGETDIR or its children can have files". But I
> potentially need to install files to multiple Python installations, e.g.
> C:\Python24 and C:\Python25. I can use RegLocator etc. to set TARGETDIR to
> one or the other of these, but not both as far as I can tell. I guess I could
> set TARGETDIR to C: but that seems a little odd...

In the Directory table, insert rows like:

Directory='TARGETDIR', Directory_Parent=NULL, DefaultDir='SourceDir';
Directory='PYTHON24', Directory_Parent='TARGETDIR', DefaultDir='Python24';
Directory='PYTHON25', Directory_Parent='TARGETDIR', DefaultDir='Python25';

Then use RegLocator to set the PYTHON24 and PYTHON25 properties.
As long as you set those properties before CostFinalize, Windows
Installer will use them to set the target locations of the
corresponding directories, and TARGETDIR will not affect them.
If RegLocator doesn't find e.g. Python 2.4 and leaves PYTHON24
unset, then TARGETDIR does affect the PYTHON24 directory, but
in that case you'll disable the feature, so no components will
be installed there.

If you're going to install files only in PYTHON24 and PYTHON25
and not directly in TARGETDIR, then you can leave TARGETDIR at
its default, typically "C:\". I don't know how you should then
set ARPINSTALLLOCATION. On the other hand, if you're also going
to install some READMEs or such that aren't specific to one
version of Python, then you can use a custom action to set
TARGETDIR pointing somewhere in Program Files, and put the
READMEs there.

However, when making an administrative installation (msiexec /a),
the directories work differently.

Steven Bethard

unread,
May 2, 2009, 2:08:01 PM5/2/09
to

"Kalle Olavi Niemitalo" wrote:

> Steven Bethard <Steven...@discussions.microsoft.com> writes:
>
> > I played around with this a bit, but I'm stuck on the TARGETDIR part. Orca
> > tells me that "Only TARGETDIR or its children can have files". But I
> > potentially need to install files to multiple Python installations, e.g.
> > C:\Python24 and C:\Python25. I can use RegLocator etc. to set TARGETDIR to
> > one or the other of these, but not both as far as I can tell. I guess I could
> > set TARGETDIR to C: but that seems a little odd...
>
> In the Directory table, insert rows like:
>
> Directory='TARGETDIR', Directory_Parent=NULL, DefaultDir='SourceDir';
> Directory='PYTHON24', Directory_Parent='TARGETDIR', DefaultDir='Python24';
> Directory='PYTHON25', Directory_Parent='TARGETDIR', DefaultDir='Python25';
>
> Then use RegLocator to set the PYTHON24 and PYTHON25 properties.
> As long as you set those properties before CostFinalize, Windows
> Installer will use them to set the target locations of the
> corresponding directories, and TARGETDIR will not affect them.
> If RegLocator doesn't find e.g. Python 2.4 and leaves PYTHON24
> unset, then TARGETDIR does affect the PYTHON24 directory, but
> in that case you'll disable the feature, so no components will
> be installed there.

Excellent. Thanks for the detailed information.

One more question about this approach. How do I disable a feature based on
something I looked up from the registry? In particular, if I've tried and
failed to set PYTHON24DIR from the registry, how do I set the corresponding
entry in the Feature table to not display? I assume I need to modify the
Level column, but I can't see how to do that at install time.

Bob Arnson [MSFT]

unread,
May 2, 2009, 2:25:16 PM5/2/09
to Steven Bethard
Steven Bethard wrote:
> One more question about this approach. How do I disable a feature based on
> something I looked up from the registry? In particular, if I've tried and
> failed to set PYTHON24DIR from the registry, how do I set the corresponding
> entry in the Feature table to not display? I assume I need to modify the
> Level column, but I can't see how to do that at install time.

Use the Condition table.

sig://boB
http://joyofsetup.com/

Steven Bethard

unread,
May 2, 2009, 2:47:01 PM5/2/09
to

"Steven Bethard" wrote:

I think I figured this out - looks like I just need to add an entry to the
Condition table with something like:

Feature_=Python24Feature, Level=0, Condition=NOT PYTHON24DIR

Thanks again everyone for your help!

Kalle Olavi Niemitalo

unread,
May 3, 2009, 1:47:54 AM5/3/09
to
Steven Bethard <Steven...@discussions.microsoft.com> writes:

The documentation of the Condition table
<http://msdn.microsoft.com/en-us/library/aa368014.aspx> warns:

| Conditions should be carefully chosen so that a feature is not
| enabled on install and then disabled on uninstall. This will
| orphan the feature and the product will not be able to be
| uninstalled.

So please test this scenario:

1. Install Python 2.4.
2. Install your package, so Python24Feature gets installed.
3. Uninstall Python 2.4.
4. Uninstall your package. Is Python24Feature properly uninstalled?

On the other hand, the documentation also says Windows Installer
does not use the Condition table if the REMOVE property has been set.
When uninstalling a product via Add or Remove Programs, I think
Windows Installer sets REMOVE=ALL, so perhaps it'll work correctly.
It's worth testing though.

Bob Arnson [MSFT]

unread,
May 3, 2009, 9:44:01 PM5/3/09
to Kalle Olavi Niemitalo
Kalle Olavi Niemitalo wrote:
> | Conditions should be carefully chosen so that a feature is not
> | enabled on install and then disabled on uninstall. This will
> | orphan the feature and the product will not be able to be
> | uninstalled.

http://www.joyofsetup.com/2008/05/16/make-sure-features-are-always-enabled-so-they-can-be-removed/

Definitely an issue to verify.

--
sig://boB
http://joyofsetup.com/

0 new messages