Thursday, June 01, 2006

Deferred custom actions with WiX

Definition of Deferred Custom Actions


The installer does not execute a deferred execution custom action at the time the installation sequence is processed. Instead the installer writes the custom action into the installation script.


Custom actions that set properties, feature states, component states, or target directories, or that schedule system operations by inserting rows into sequence tables, can in many cases use immediate execution safely. However, custom actions that change the system directly, or call another system service, must be deferred to the time when the installation script is executed.

Purpose of deferred Custom Actions


The purpose of a deferred execution custom action is to delay the execution of a system change to the time when the installation script is executed. This differs from a regular custom action, or a standard action, in which the installer executes the action immediately upon encountering it in a sequence table or in the form with tag.


<Publish Event="DoAction" Value="CustomActionName">
<![CDATA[1]]>
</Publish>

How to define deferred custom action in WiX


Deferred custom action is defined in the following way:


<CustomAction Id="MyAction" Return="check" Execute="deferred"
BinaryKey="CustomActionsLibrary" DllEntry="_MyAction@4"
HideTarget="yes"/>


Lets describe the sample above:
- Execute=“deferred” – means that custom action with Id “MyAction” will execute in deferred mode ( in-script ).
- DllEntry="_MyAction@4" – the name of the function to be called, when installer executes generated install script.
- HideTarget="yes" - for security reasons, you may transfer confidential info to your custom action, this attribute notifies installer not to log parameters passed to custom action.

How to Transfer Properties to Deferred Custom Action


Because the installation script can be executed outside of the installation session in which it was written, the session may no longer exist during execution of the installation script. This means that the original session handle and property data set during the installation sequence is not available to a deferred execution custom action. Deferred custom actions that call dynamic-link libraries (DLLs) pass a handle which can only be used to obtain a very limited amount of information.


Properties that can be retrieved during in-script execution are:

- CustomActionData - value at time custom action is processed in sequence table. The “CustomActionData” property is only available to deferred execution custom actions. Immediate custom actions do not have access to this property.
- ProductCode - unique code for the product, a GUID string.
- UserSID - set by the installer to the user's security identifier (SID).


If other property data is required by the deferred execution custom action, then their values must be stored in the installation script. This can be done by using a second custom action.
In order to write the value of a property into the installation script for use during a deferred execution custom action we have to do the following:


- Insert a small custom action into the installation sequence that sets the property of interest to a property having the same name as the deferred execution custom action. For example, if Id for the deferred execution custom action is "MyAction" set a property named "MyAction" to the property X which you need to retrieve. You must set the "MyAction" property in the installation sequence before the "MyAction" custom action.


Although any type of custom action can set the context data, the simplest method is to use a property assignment custom action.


At the time when the installation sequence is processed, the installer will write the value of property X into the execution script as the value of the property CustomActionData.


Lets illustrate the above said with WiX sample.


At first we define custom action that will assign CustomActionData property.


<Property Id=”SOME_PUBLIC_PROPERTY”>
<![CDATA[Hello, from deferred CA]]>
</Property>


<CustomAction Id="MyAction.SetProperty" Return="check"
Property="MyAction" Value="[SOME_PUBLIC_PROPERTY]">
</CustomAction>


Then we put above defined custom action into execution sequence along with “MyAction” deferred custom action


<InstallExecuteSequence>
<Custom Action="MyAction.SetProperty" After="ValidateProductID"/>
<Custom Action="MyAction" After="MyAction.SetProperty"/>
</InstallExecuteSequence>


Our custom action will reside in DLL. Below is the sample where we retrieve “SOME_PUBLIC_PROPERTY”, during deferred (in-script) installer execution.


<Binary Id='CustomActionsLibrary'
SourceFile='Binary\CustomActionsLibrary.dll' />


#include <windows.h>
#include <msi.h>
#include <msiquery.h>
#include <tchar.h>


#pragma comment(linker, "/EXPORT:MyAction=_MyAction@4")


extern "C" UINT __stdcall MyAction (MSIHANDLE hInstall)

{

TCHAR szActionData[MAX_PATH] = {0};

MsiGetProperty (hInstall, "CustomActionData",
szActionData,sizeof(szActionData));


::MessageBox(NULL, szActionData, _T(“Deferred Custom Action”),
MB_OK | MB_ICONINFORMATION);


return ERROR_SUCCESS;


}


If there is need to transfer multiple properties into deferred custom action, “CustomActionData” property may contain value pairs e.g. PropertyName=PropertyValue with some separator symbol ( ; ).

23 comments:

  1. What IS this CDATA anyway?

    ReplyDelete
  2. Have a look at
    http://en.wikipedia.org/wiki/CDATA

    ReplyDelete
  3. Thank you very much for this. I was having so much trouble finding an example.

    ReplyDelete
  4. There is nice tutorial on http://www.tramontana.co.hu/wix/

    ReplyDelete
  5. Thanks for a very good explanation!

    I have a question:

    If I want to transfer muliple in the way you suggest I suppose I still have to access them thru the CustomActionData property and "parse" the content by myself... or is it an built in functionality for accessing the multiple property values?

    ReplyDelete
  6. Nope, there is no built in functionality to access multiple data in CustomActionData.

    To store multiple data you can make name=value pairs with a separator, say ";". And parse them in the custom action.

    ReplyDelete
  7. Thank you for this article. In similar context we have a problem - hope you are able to provide some inputs on it. Your articles explains well how to pass properties to deferred custom actions. In our case these properties are updated with user inputs and we need to pass the updated data to deferred custom actions. However when we try to do that - we end up getting the original value of the property and not the updated one.
    In short - problem is how to pass dynamically collected data to deferred custom actions.
    Any help would be appreciated.
    Thanks,
    Piyush
    piyush [dot] bhatnagar [at] proteans [dot] com

    ReplyDelete
  8. Deferred CA is run when install script is executed (no user inputs here).

    So, at the end of UI phase (when you're done collecting data from the inputs) you assign the data from the inputs to the CustomActionData property. This property is visible from deferred CA.

    ReplyDelete
  9. I was wandering why your blog post is so uncomprehensive, until I found that you have copied whole paragraphs from msdn. Shame on you.

    ReplyDelete
  10. The post gives a solution for Transferring parameters into deferred CAs. A lot of information about the topic is given in MSDN. IMO if MSDN gives good explanation why not use it? If something is missing I'm giving my own explanation.

    ReplyDelete
  11. Nvin Installer is a simple installer developed using WiX toolset. It is really useful if somebody don't want scratch their head to create MSI files.

    ReplyDelete
  12. Your website is fine for all its distinctive features. However, I have found http://www.infysolutions.com to be another content enriched website containing details on Outsourcing software development,ecommerce solutions and software development.
    Thanks.

    ReplyDelete
  13. Very useful information! Thank you.

    ReplyDelete
  14. Very good posts on wix, thank you very much. Good bless you.

    ReplyDelete
  15. Thanks for the tips & the excellent post.

    ReplyDelete
  16. Hi !.
    You re, I guess , probably curious to know how one can collect a huge starting capital .
    There is no initial capital needed You may commense to receive yields with as small sum of money as 20-100 dollars.

    AimTrust is what you need
    The firm represents an offshore structure with advanced asset management technologies in production and delivery of pipes for oil and gas.

    Its head office is in Panama with offices around the world.
    Do you want to become an affluent person?
    That`s your chance That`s what you desire!

    I feel good, I started to take up real money with the help of this company,
    and I invite you to do the same. If it gets down to select a proper partner utilizes your funds in a right way - that`s the AimTrust!.
    I take now up to 2G every day, and what I started with was a funny sum of 500 bucks!
    It`s easy to get involved , just click this link http://ofawalinob.freecities.com/eteryb.html
    and go! Let`s take this option together to feel the smell of real money

    ReplyDelete
  17. Hi !.
    You re, I guess , perhaps very interested to know how one can collect a huge starting capital .
    There is no need to invest much at first. You may start to get income with as small sum of money as 20-100 dollars.

    AimTrust is what you need
    The company represents an offshore structure with advanced asset management technologies in production and delivery of pipes for oil and gas.

    Its head office is in Panama with affiliates everywhere: In USA, Canada, Cyprus.
    Do you want to become really rich in short time?
    That`s your chance That`s what you wish in the long run!

    I`m happy and lucky, I started to take up income with the help of this company,
    and I invite you to do the same. It`s all about how to select a correct companion who uses your funds in a right way - that`s the AimTrust!.
    I earn US$2,000 per day, and my first deposit was 1 grand only!
    It`s easy to get involved , just click this link http://jovuhubun.mindnmagick.com/ipykexi.html
    and go! Let`s take this option together to get rid of nastiness of the life

    ReplyDelete
  18. Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now keep it up!

    ReplyDelete
  19. Good day, sun shines!
    There have were times of hardship when I felt unhappy missing knowledge about opportunities of getting high yields on investments. I was a dump and downright pessimistic person.
    I have never imagined that there weren't any need in big initial investment.
    Now, I'm happy and lucky , I begin to get real income.
    It's all about how to select a proper companion who uses your funds in a right way - that is incorporate it in real business, and shares the profit with me.

    You may ask, if there are such firms? I have to tell the truth, YES, there are. Please be informed of one of them:
    http://theinvestblog.com [url=http://theinvestblog.com]Online Investment Blog[/url]

    ReplyDelete
  20. In our installer we are using the Immediate custom action to install our assemblies. While installing our setup when custom action comes to play there is no progress in the installer.

    I think we have to go for the deferred custom action. Then how we get the MSI properties in the Custom action ?. Can we use the customactiondata to get the properties of the C# custom action.

    Can you please share your ideas ?

    ReplyDelete
  21. Have you looked in this link . It seems to answer your question

    ReplyDelete
  22. thanks! this helps a lot.
    i'm thinking that i'm going to make my iis7 compatible installer a custom action.
    i needed a way to pass config info collected from the user to it.
    this will do the trick.

    ReplyDelete