cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
wimcolgate
Level 4

UILevel property from within a custom action

I've inherited a fairly complex installer.

There are a few SprintfBox calls there were protected by the following code. The code is a generic logging function that is access from dialog code and custom action code.


if (MODE != SILENTMODE && msgbox) then
SprintfBox (msgtype, msgtitle, msg);
endif;


This does not seem to work when invoked from the custom action code.

After a little web searching, I tried to rewrite to something this:


nvSize = 256;
MsiGetProperty (hMSI, "UILevel", UILevelName, nvSize);
if (UILevelName != "2") then
SprintfBox (msgtype, msgtitle, msg);
endif;


This does not work either. In the latter case, UILevelName is the empty string.

What is the best practice for not throwing a pop-up during a silent (unattended) install from a custom action?

Thanks,

Wim
Labels (1)
(7) Replies
Reureu
Level 10

First of all, reading the property "UILevel" instead of the MODE InstallScript variable is correct. The "MODE" system variable makes sense in an InstallScript project, not in a Basic MSI project.
So that's all good.

So am I right in thinking that you are working on a Basic MSI project?
If that's the case, your code looks correct.

But you might want to check the return value of MsiGetProperty. See http://msdn.microsoft.com/en-us/library/windows/desktop/aa370134%28v=vs.85%29.aspx for a list of possible values.

You might also want to check the "In-Script Execution" setting of your custom action. I am not sure whether UILevel is available in custom-action set for "Deferred Execution" or "Commit Execution".

See here: http://helpnet.flexerasoftware.com/installshield19helplib/helplibrary/AccessingProps-DeferredCAs.htm

Does that help?
0 Kudos
wimcolgate
Level 4

Correct, I have Basic MSI project. So I will remove the inherited code (MODE check) and replace with a similar UILevel check.

In the logs, UILevel is set as such when running in silent mode:

MSI (s) (2C:EC) [15:37:32:995]: PROPERTY CHANGE: Adding UILevel property. Its value is '2'.

If I read what you are intending: near initialization, get the UILevel property and set a custom action property with the value -- and then retrieve that value in the logger function.

But please forgive my ignorance, I've just picked up IS in the last 6 weeks -- Are the custom action properties permanent? Meaning if I set them in one custom action I can retrieve it in another? The reason I ask is that I've seen in the custom actions The "Property Value" entry that sets custom action "variables" to property values (i.e.: /InstallDir=[INSTALLDIR]). The Logger is called from just about everywhere -- and it would be untenable (I think) to plumb /UILevel=[UILevel] on every single custom action...

And if I'm talking gibberish, please feel free to educate me!

Wim


Reureu wrote:
First of all, reading the property "UILevel" instead of the MODE InstallScript variable is correct. The "MODE" system variable makes sense in an InstallScript project, not in a Basic MSI project.
So that's all good.

So am I right in thinking that you are working on a Basic MSI project?
If that's the case, your code looks correct.

But you might want to check the return value of MsiGetProperty. See http://msdn.microsoft.com/en-us/library/windows/desktop/aa370134%28v=vs.85%29.aspx for a list of possible values.

You might also want to check the "In-Script Execution" setting of your custom action. I am not sure whether UILevel is available in custom-action set for "Deferred Execution" or "Commit Execution".

See here: http://helpnet.flexerasoftware.com/installshield19helplib/helplibrary/AccessingProps-DeferredCAs.htm

Does that help?
0 Kudos
Reureu
Level 10

Well the link I gave you about CustomActionData says:
Deferred, commit, and rollback custom actions in Basic MSI and InstallScript MSI installations have access to only some of the built-in Windows Installer properties: CustomActionData, ProductCode, and UserSID. If you want a custom action to access any other properties during deferred, commit, or rollback execution, you can pass them as CustomActionData. You can do so by scheduling an immediate set-a-property type of custom action to set a property that matches the name of the custom action. The value of this property is then available in the CustomActionData property within the deferred, commit, or rollback custom action.


So you don't need to use a CustomActionData for every single Custom Action. You need to do it if:

  • the custom action is scheduled for Deferred, Commit or Rollback Execution
AND
  • you need to access properties other than "CustomActionData", "ProductCode", and "UserSID" in your custom action

I don't think the conditions above apply to all your custom actions, do you?

Bearing that in mind, you need to remember the following points:

  • Custom Actions scheduled for immediate execution don't need to use this CustomActionData property.
  • You need to set a CustomActionData for EVERY custom action that fulfils the 2 conditions above (if I remember well).

Now it's my turn to ask questions... 😉

  • Does that help?
  • Did you try?
  • Did that solve your problem?
0 Kudos
wimcolgate
Level 4

The custom actions are defined as "deferred in system context".

I really only want UILevel to determine if a pop-up should be displayed; Again, the reason is that the logger function -- which is called from absolutely everywhere -- has a parameter that indicates whether a message box (actually an SprintfBox) should be thrown in addition to logging to the file. If running in Silent mode (Or unattended install) -- a pop-up throws a monkey wrench into things.

So according to your criteria, both apply. the custom actions are deferred AND I need something that is not ProductCode or UserSID -- and not normally in CustomActionData. Which means to me that I need to add it.

So my real question is that can I add it ONLY ONCE to the CustomActionData, like in an initialization function, and then retrieve it at will, OR do I need to add it on entry to every custom action?

Wim
0 Kudos
wimcolgate
Level 4

Our custom actions are defined into two separate pieces. One that sets up custom action data, and then the custom action itself.

I found that simply plumbing /UILevel=UIlevel in the custom action data setup and then in the logger code do:

    nvSize = 256;
MsiGetProperty(hMSI, "UILevel", UILevelName, nvSize);
if (UILevelName == "") then
UILevelName = MsiGetCustomActionDataAttribute(hMSI, "/UILevel=");
endif;
if ((UILevelName != "2") && (msgbox)) then //silent install check
SprintfBox (msgtype, msgtitle, msg);
endif;


It correctly functions for both normal code flow and custom actions.

Regards,

Wim
0 Kudos
Reureu
Level 10

So your project already had this CustomActionData set? Good!
Just as a suggestion: you might also want to treat UILevel=3 differently.
0 Kudos
ankita_solanki
Level 3

Awesome.. this solution works for me. Thank you
0 Kudos