How to get textbox values from Custom CLR dialog and use inside CustomAction

Nov 16, 2016 at 1:30 PM
I have a custom CLR dailog which is accepting appsetting value in textbox.
Now i want to set this value into app.config using project.AfterInstall += Project_AfterInstall

But how i'll get the textbox value inside Project_AfterInstall method.
Coordinator
Nov 17, 2016 at 2:06 AM
It's relatively easy. Though the creators of MSI have made all effort to make it almost impossible. :)

You cannot pass any data from one standard/custom action to another. MSI dust doesn't have any mechanism for that. Thus the only way to do this is to write the value in the session as a property and then read this property from another session. However... the custom actions, which allows setup to write anything (e.g. AfterInstall event) are Deferred actions and MSI "carefully" kills the session object before invoking these actions. And when the action is executed MSI passes a freshly constructed (sterilized) and totally useless session object without a single property set.

To solve this there is another work around the data needs to be preserver in another alternative property bag (not Session but AppData). Wix# makes it transparent so you only need to mark your property as a "long living" one with project.DefaultDeferredProperties += ";MyPropertyName". And when you access it you need to use extension method Session instead of indexer: session.Property("MyPropertyName").

If you are using "ManagedSetup" then you can strimpline tunneling the data to the AfterInstall event via Wix# specific (non-MSI) property bag SetupEventArgs.Data['name'] = value. "Setup Event" sample shows the technique. In fact it shows exactly how to pass DBConnection string from UI sequence to AfterInstall event.

Read about orthodox Deferred Custom Actions here: https://wixsharp.codeplex.com/wikipage?title=Deployment%20scenarios#_deferred_actions
Read about ManagedSetup events here: https://wixsharp.codeplex.com/wikipage?title=Managed%20Setup
Nov 17, 2016 at 12:23 PM
Edited Nov 17, 2016 at 1:00 PM
thanks oleg_s
I'll go through it and let you know.

BTW to just update webconfig properties CustomCLR, CustomMSI or EmbeddedUI which one is encouraged?

And "Setup Event" sample is it newly added? i can not see it in my previously downloaded sample.
Nov 17, 2016 at 1:22 PM
DEMETRON wrote:
thanks oleg_s
I'll go through it and let you know.

BTW to just update webconfig properties CustomCLR, CustomMSI or EmbeddedUI which one is encouraged?

And "Setup Event" sample is it newly added? i can not see it in my previously downloaded sample.
ok Found it thanks.
Coordinator
Nov 17, 2016 at 11:05 PM
Custom CLR Dialog - This project template and sample is referring to the MSI setup with native UI with a CLR dialog injected between two given native dialogs. This technique is an earlier effort to do simple UI customization. It has been superseded with the more advanced EmbeddedUI API. Though due to the still unfixed Burn bug #4921 EmbeddedUI cannot be used with bundles. Thus "Custom CLR Dialog" is still a valid technique. At least until Burn is fixed.

EmbeddedUI - is a recommend UI customization approach, which allows you to create a consistent, complete (not just one dialog) CLR UI sequence. The UI is embedded into MSI and invoked instead of MSI native UI. As I mentioned, sadly, it cannot be used with Burn until bug #4921 is fixed.

CustomMSI - Not sure about this one but most likely you are referring to 'ExternalUI'. ExternalUI is an external application (exe) that needs to be distributed along with the MSI file. It is an UI launcher for MSI. The launcher can also embed the msi(s) as resource so the setup can be distributed as a single exe file. Burn bootstrapper BA is an external UI app developed by WiX team. Wix# provides simplified infrastructure for building external UIs. This API model is valid but should be used only when you truly need it.
Nov 19, 2016 at 8:34 AM
I went through "Setup Events"
static void project_Load(SetupEventArgs e)
    {
        var msi = e.MsiFile;

        SetEnvVersion(e.Session);

        //MSI doesn't preserve any e.Session properties if they are accessed from deferred actions (e.g. project_AfterInstall)
        //Wix# forces some of the properties to be persisted (via CustomActionData) by using user defined 
        //project.DefaultDeferredProperties ("INSTALLDIR,UILevel" by default).
        //Alternatively you can save any data to the Wix# specific fully persisted data properties "bag" SetupEventArgs.Data.
        //SetupEventArgs.Data values can be set and accesses at any time from any custom action including deferred one.  
        var conn = @"Data Source=.\SQLEXPRESS;Initial Catalog=RequestManagement;Integrated Security=SSPI";
        __e.Data["persisted_data"]__ = conn; 

        MessageBox.Show(e.ToString(), "Load " + e.Session["EnvVersion"]);
    }
static void project_AfterInstall(SetupEventArgs e)
    {
        MessageBox.Show(e.ToString() +
                        "\npersisted_data = " + __e.Data["persisted_data"]__ +
                        "\nADDLOCAL = " + e.Session.Property("ADDLOCAL"),
                        caption: "AfterExecute ");

        try
        {
            System.IO.File.WriteAllText(@"C:\Program Files (x86)\My Company\My Product\Docs\readme.txt", "test");
        }
        catch { }
    }
Now here conn string is hardcoded, i am still not getting how to set it from my custom CLR dialog it's a win form combobox also at what event it should be set to session?

So basically what my understanding is.
private void Next_Click(object sender, EventArgs e)
        {
            //session["AppVersion"] = comboBox1.Text;  // value needs to be set here 'somehow'
            MSINext();
        }
Coordinator
Nov 19, 2016 at 11:52 AM
EmbeddedUI/ManagedUI
Have a look at CustomUIDialog sample. Itr shows how to set session properties aor tunneled for deferred action Data:
void next_Click(object sender, EventArgs e)
        {
            MsiRuntime.Session["PASSWORD"] = password.Text;
            MsiRuntime.Session["DOMAIN"] = domain.Text;
            MsiRuntime.Data["test"] = "test value";
            Shell.GoNext();
        }
CLR Dialog
Have a look at CustomCLRDialog. It will be something like this:
private void nextBtn_Click(object sender, EventArgs e)
{
    this.session["prop name"] = "whatever";
    MSINext();
} 
Nov 21, 2016 at 7:50 AM
let me rephrase my question.
i am doing

project.DefaultDeferredProperties += ";AppVersion";

then
private void Next_Click(object sender, EventArgs e)
        {
            session["AppVersion"] = comboBox1.Text; 
            MSINext();
        }
now when i do
private static void Project_AfterInstall(SetupEventArgs e)
        {
             var appVersion = e.Data["AppVersion"];
             //or
             //var appVersion = e.Session.Property("AppVersion");
            //or
           //var appVersion = e.Session["AppVersion"]
        }
none of them fetching data from CLR dialog.
So what i am missing here,I went to custom_ui , deferred actions and setup events sample but still not getting how data is passed from CLR dialog to after_install.

Btw thanks a lot for helping me out.
Nov 21, 2016 at 10:22 AM
finally made it work i found CustomUIDialog inside managed setup sample.
and change my project to managed one as it seems more controllable on UI.

But it was not working until i changed "AppVersion" to "APPVERSION"
I think my naming convention was not supported by wix?
Coordinator
Nov 22, 2016 at 2:25 AM
> I think my naming convention was not supported by wix?
It is actually MSI (not WiX) design perl. :)
If the property is to be used outside it needs to be declared as public. Makes sense, doesn't it? But the the way you do is is not something one would expect... You need to declare it in all capital.

>But it was not working until i changed "AppVersion" to "APPVERSION"
Strangely enough I have checked the SetupEvents sample and in my test I was able to tunnel lower-case property to the AfterInstall. Thus may be in your test it was because of mismatch of the property name in project.DefaultDeferredProperties and e.Session.Property(....

Anyway, your code snippet shows that there are a few points you need to do differently when you access your properties.

The last line will throw the exception because AfterInstall is a deferred action and the session object is already disconnected. Thus you need to access the property with e.Session.Property("AppVersion").

The e.Data["AppVersion"] statement should be used only if you set data from the dialog with this.MsiRuntime.Data["AppVersion"] = "some value"; and I am not sure you did.

And another point to remember. If you use MsiRuntime.Data then you don't need to do project.DefaultDeferredProperties as the whole MsiRuntime.Data dictionary is tunneled to the AfterInstall event handler. Meaning that there is a less chance that something will go wrong.

> change my project to managed one as it seems more controllable on UI.
100% agree.
Nov 22, 2016 at 7:11 AM
Edited Nov 22, 2016 at 7:13 AM
And another point to remember. If you use MsiRuntime.Data then you don't need to do project.DefaultDeferredProperties as the whole MsiRuntime.Data dictionary is tunneled to the AfterInstall event handler. Meaning that there is a less chance that something will go wrong.
Ok got it so previously i was using MsiRuntime.session[] and reading it with e.session.property() thus i was using new propery("APPVERSION"){isdeffered = true}
now change it to MsiRuntime.Data[].
thanks