0

I need to:

  1. get data from users (from a UI), and put that data into Properties
  2. import the Properties into some C# code using a Custom Action
  3. do some stuff to the Properties (encrypt the values),
  4. export the values back to WiX, where I will
  5. create a registry key and put the encrypted values into them

I can accomplish everything on that list except for #4. That is, I can't seem to import and export values into the C# code. I think the problem is in the timing.

Here's an example of a Custom Action that is used to import some properties into some C# code:

  <Property Id="VALUE" Value="value"/>
  <SetProperty Id="CustomAction_PassProperty"
               Value="VALUE=[VALUE]"
               Sequence="execute"
               Before="CustomAction_PassProperty"/> 

  <Binary Id="Binary_PassProps"
          SourceFile="$(var.CreateRegistryKey.TargetDir)CreateRegistryKey.CA.dll"/>

  <!-- Note that 'Impersonate="no"' elevates the privilege of the C# code, needed to create keys -->
  <CustomAction Id="CustomAction_PassProperty"
                BinaryKey="Binary_PassProps"
                DllEntry="CreateKeys"
                Execute="deferred"
                Impersonate="no"
                Return="check" 
                HideTarget="yes"/>

  <InstallExecuteSequence>
      <Custom Action="CustomAction_PassProperty"
              After="InstallInitialize"/>
  </InstallExecuteSequence>

Notice that the action is done after InstallInitialize.

Next, how to take the imported properties and convert them into variables in the C# code:

    [CustomAction]
    public static ActionResult CreateKeys(Session session)
    {
        string value = session.CustomActionData["VALUE"];
        return ActionResult.Success;
    }

Next, here's an example of how to export variables in C# code back into WiX, as properties:

<Binary Id="Binary_CustomActionTemplate" 
        SourceFile="$(var.CustomAction.TargetDir)CustomAction.CA.dll"/>

<CustomAction Id="CustomAction_CustomActionTemplate" 
              BinaryKey="Binary_CustomActionTemplate" 
              DllEntry="CustomActionTemplate" 
              Execute="immediate" 
              Return="check"/>

<InstallUISequence>
    <Custom Action="CustomAction_CustomActionTemplate" After="LaunchConditions"/>
</InstallUISequence>

And this time the action is done after LaunchConditions.

Finally, how to create a Property, give it a value, and send it back to WiX in C#:

    [CustomAction]
    public static ActionResult CreateKeys(Session session)
    {
        session["VALUE"] = "Hello, world.";
        return ActionResult.Success;
    }

I think the problem lies in when -- that is, when during the installation sequence -- that I do both things (import and export), but I'm not sure. That is, I need to import the data into the C# code, do stuff in the C# code, then export data from C# code. But how?!? (waves hands dramatically at sky)

To sum up: how to import and export data into C# Custom Action in WiX (using the same C# code)?

Bob
  • 369
  • 1
  • 4
  • 24
  • I added an alternative option to my answer in case you read already it and didn't see the edit. The answer is kind of a mess sorry =] – Brian Sutherland Feb 15 '17 at 21:25

1 Answers1

0

AFAIK you cannot alter property values once in the execute sequence. Someone can correct me if I'm wrong and that would be an alternative answer to your question.

You should be able to encrypt the properties in the UI phase of the install. In your immediate custom action you can access the msi properties with session["PROPERTYNAME"] as opposed to session.CustomActionData["PROPERTYNAME"]. You can also set the properties: session["PROPERTYNAME"] = "new value string";.

Then on your Next/Install control on the page where the information is added you can put

<Control Id="Install" ...>
    <Publish Event="DoAction" Value="EncodeAndSetValuesAction">1</Publish>
    ....
</Control>

If they are marked Secure='yes' and public (all caps name) then they should be usable in the execute phase of your installation with the encoded values.

Do note that if you launch your custom action with a DoAction control event (clicking next on the page where the user enters the values) you won't be able to get logging information in the msi log. See here for more info.

Small edit: I was writing this answer when you edited the question which shows you already know how to get the properties and set them in an immediate action.

Alternatively, you may be able to just schedule an immediate custom action to encrypt and set the values in the InstallExecuteSequence before InstallInitialize (or before WriteRegistryValues or anywhere?) and it will set the properties before the elevated Server portion of the install starts. I think the InstallExecuteSequence happens in two parts. One where it does a pass figuring out values and which files to install making an install script for the elevated Server portion of the install where it actually copies the files around and writes registry keys ect. This part is still the client context where you can run immediate custom actions and read/set properties. Secondly it will start the Server portion of the install with set in stone properties and follow the execution script that was just created.


I decided to put a short simplified explanation about the differences between immediate and deferred custom actions here as well.

There are basically two main differences between deferred and immediate custom action. Immediate custom actions can access the msi DB directly to read and/or modify properties but can't do anything that requires elevation unless the installer was run "as administrator" since it runs in the user's context.

Deferred actions can only run in the execute sequence and can only read property values set explicitly through CustomActionData with the same name as the action but they always have elevated privileges.

Community
  • 1
  • 1
Brian Sutherland
  • 4,698
  • 14
  • 16
  • This question actually stems from [this](http://stackoverflow.com/questions/42256748/wix-removeregistrykey-element-not-behaving-as-advertised) question. What I originally planned to do was get the properties from UI and set the registry in the C# code itself. However, I'm unable to delete the registry that is created in the C# code during uninstallation (and I don't want to be the developer that leaves random crap all over the user's registry). So I thought maybe I'd set the registry back in WiX and just encrypt the properties in the Custom Action. – Bob Feb 16 '17 at 14:32
  • With that said, the fact is I don't understand the sequencing of the installation process: how to make some stuff happen before other stuff, etc. Frankly, this ignorance makes your "alternatively" suggestion hard for me to parse, and your short explanation on the differences between immediate and deferred custom actions super-useful (thanks!). So what I'll do is learn me some stuff, re-read your "alternatively" suggestion, and give it a shot. – Bob Feb 16 '17 at 14:38
  • @Bob A great tool you can use to understand the sequencing a bit more is Orca.exe from Microsoft. You can look at the InstallExecuteSequence table and order it by "sequence" and see the order all the action (custom and standard) will run. Immediate vs Deferred in the Execute sequence is a little weird because I *think* all the immediate ones run first then in the second pass the deferred ones run. That's why I put "anywhere?" as a valid sequencing since it should get run before any deferred actions anyways. – Brian Sutherland Feb 16 '17 at 15:27
  • Also, you should be able to remove your created registry keys in a deferred custom action that is sequenced after "RemoveRegistryValues" and just make sure the condition is `NOT UPGRADINGPRODUCTCODE AND Remove~="ALL"` – Brian Sutherland Feb 16 '17 at 15:30
  • Let me ask you about your original suggestion. What you're saying is that I might be able to do the encryption custom action in the InstallUISequence, right? And then remove the key in the InstallExecuteSequence? If that's the case, is the value `EncodeAndSetValues` in the `Publish` element the Id of the Custom Action that would do the encoding? Also, what does the "1" do in the `Publish` element? – Bob Feb 17 '17 at 13:42
  • Yes the name of the custom action you want to run should be `Value` of the Publish event. The "1" is a conditional evaluation. Basically it means "Always true" so always do this when you click the button. https://www.firegiant.com/wix/tutorial/events-and-actions/control-your-controls/ this may be quite useful for learning how do to actions from your UI. Should you handle incorrect values entered by the user? Blank values? Do you read these values from the registry if they exist to remember what was entered before? Lots to consider. – Brian Sutherland Feb 17 '17 at 16:31