1

Thanks to this question, I was able to make a custom action that temporary update and modifies the MSI Database on the fly.

In a nutshell I am doing

[CustomAction]
public static ActionResult VerifyLog(Session session)
{
  var sRtfText = @"{\rtf1\ansi\deff0{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}THIS IS NOT DEFAULT TEXT}";
  var view = session.Database.OpenView("SELECT * FROM Control WHERE 
  Dialog_='EndDlg' AND Control='Verification'");
  view.Execute();
  var record = view.Fetch();
  view.Delete(record);
  record.SetString("Text", sRtfText);
  view.InsertTemporary(record); // also tried original post's view.Modify(ViewModifyMode.InsertTemporary, record); as well

  return ActionResult.Success;
}

and my default state of the Control is following

<Dialog Id="EndDlg" Width="600" Height="400" Title="$(var.PRODUCT_NAME)">
  <Control Id="Verification" Type="ScrollableText" X="180" Y="80" Width="410" Height="280" Sunken="yes" TabSkip="no" Text="{\rtf1\ansi\deff0{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}default text\line}"/>
  <!-- Buttons for Navigation... -->
</Dialog>

My CustomAction element is following.

  <CustomAction Id="CA_01_Verify"
                BinaryKey="WiXCustomAction"
                DllEntry="VerifyLog"
                Execute="immediate"
                Return="check"/>

My InstallExecuteSequence is following.

  <InstallExecuteSequence>
    <Custom Action="CA_01_Verify" Before="CostInitialize"></Custom>
  </InstallExecuteSequence>

However, upon the End Dialog is opened on exit via <Show Dialog="EndDlg" OnExit="success"/>, somehow, the updated text is gone and the control only displays the default text.

When I do check for the text column, in the custom action, I can see that it has been updated properly. (I checked ahead of modification via CA to make sure default WAS there and IS UPDATED).

Just for the sake of it I made another custom action that just checks for the Text entry in the EndDlg Verification Control and I confirmed that the Text column for Verification Control is properly updated.

If it is updated properly in the table, why is it not updated on the UI?

Just as a reference followings are the result log

Action 11:49:35: CA_01_Verify. 
Action start 11:49:35: CA_01_Verify.
MSI (s) (2C:A8) [11:49:35:044]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSIAC6F.tmp, Entrypoint: VerifyLog
MSI (s) (2C:C8) [11:49:35:045]: Generating random cookie.
MSI (s) (2C:C8) [11:49:35:057]: Created Custom Action Server with PID 26272 (0x66A0).
MSI (s) (2C:80) [11:49:35:086]: Running as a service.
MSI (s) (2C:80) [11:49:35:089]: Hello, I'm your 32bit Impersonated custom action server.
SFXCA: Extracting custom action to temporary directory: C:\WINDOWS\Installer\MSIAC6F.tmp-\
SFXCA: Binding to CLR version v4.0.30319
Calling custom action WiXCustomAction!WiXCustomAction.CustomActions.VerifyLog
VerifyLog started
MSI (s) (2C!90) [11:49:35:230]: PROPERTY CHANGE: Adding VerifyLog property. Its value is 'Started'.
Opening the view from control table
view.Execute()
view.Fetch()
Current Text Column: {\rtf1\ansi\deff0{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}default text\line}
view.Delete()
setting the text with rtf content : {\rtf1\ansi\deff0{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}THIS IS NOT DEFAULT TEXT}
Current Text Column Before set string : {\rtf1\ansi\deff0{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}default text\line}
Current Text Column After set string : {\rtf1\ansi\deff0{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}THIS IS NOT DEFAULT TEXT}
view.Modify
Current Text Column Before Insert: {\rtf1\ansi\deff0{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}THIS IS NOT DEFAULT TEXT}
Current Text Column After Insert: {\rtf1\ansi\deff0{\colortbl;\red0\green0\blue0;\red255\green0\blue0;}THIS IS NOT DEFAULT TEXT}
Success
Shintaro Takechi
  • 1,215
  • 1
  • 17
  • 39
  • 1
    Will have a look tomorrow. I seem to recall that the Session object is lost when you get to the EndDialog since you are then back from the system context `InstallExecuteSequence` to the user context `InstallUISequence`. Let me have a quick search to see if I can find what I wrote before. It was messy and surprising. – Stein Åsmul Nov 07 '20 at 04:39
  • Thank you so much Stein! I am counting on your masterful knowledge! – Shintaro Takechi Nov 07 '20 at 05:08
  • There are some update problems when it comes to MSI dialogs. This can cause them to show incorrect text. Stefan Kruger has a good sample here of how he deals with this: [Using Dual ListBoxes as Replacement for a Multi-Selection ListBox](http://www.installsite.org/pages/en/msi/articles/MultiListBox/index.htm). He essentially jumps between two identical-looking dialogs to force-update all fields. This dialog switch forces all fields to be refreshed so you see their actual value all the time - as opposed to the value that was before something was updated under the hood and not refreshed in GUI. – Stein Åsmul Nov 08 '20 at 16:17
  • What is the content you want to show in your end dialog? Some sort of log file? Some other form of information? I have something in testing that might work. I have a button on the end dialog that spawns a dialog with some content in there. It is really clunky as of now. – Stein Åsmul Nov 08 '20 at 16:19
  • @SteinÅsmul I am trying to display log. Since scrollable text takes in RTF, I was hoping that I can color some error if needed. Coloring is not mandatory but I do want to display dynamic log that is not constant text. Button would still work. – Shintaro Takechi Nov 09 '20 at 03:57
  • Would that be the MSI log itself or some other log? I know you can shell out to `Notepad.exe` and open the MSI log that way (provided there is a log created for the install). I would guess you want to build a log of your own with color encoding? Spawning a dialog from the `EndDialog` to show the log should work OK, and perhaps you can use the [RichTextBox control](https://stackoverflow.com/a/37825246/129130) to build the text? I will be away for a few hours. – Stein Åsmul Nov 09 '20 at 04:17
  • I actually have been calling separate exe after installation is exited to display the log with coloring but my boss does not like how it looks and asked to include it in installer. But I guess it is better if I made my exe look more like installer and display the log than to make installer to display custom RTF... – Shintaro Takechi Nov 09 '20 at 04:22
  • I think you might want to go with your application exe itself or a separate exe. When I test opening the MSI log from within a spawned MSI dialog it lacks the last 132 lines of the log file as opposed to when the MSI finish dialog is closed. I think this means that the last log batch has not been written to disk yet - and you can't see the whole log this way. There is an option to flush to log continuously, but that slows the setup to a crawl. – Stein Åsmul Nov 10 '20 at 13:04
  • So far I have a dialog with a check box that can be ticked to open the log file for the MSI session - if there was one created (no guarantee of that). This seems to work OK when connected to the "Finish" button on the last WiX dialog. Not sure if this is 100% reliable either. What are the timing issues here? Does msiexec.exe close the log file first reliably with a wait or does it just do so asynchronously and it works "most of the time". I don't know. Maybe there is a command to "close" the log file? I also spawn a dialog with log content from the Finish dialog, and here log data is missing. – Stein Åsmul Nov 10 '20 at 13:13
  • 1
    If there is an MSI log available, you can get it from the path stored in the property: [MsiLogFileLocation](https://learn.microsoft.com/en-us/windows/win32/msi/msilogfilelocation). I suppose you could even launch your own application exe with this as a path handed to it? The problem is: when the installation fails there is no application installed to hand to? That is when you really need the log? Just "thinking out loud" and it makes little sense. I guess what you could do is to use the "setup failed" end dialog and open the log file from there? – Stein Åsmul Nov 10 '20 at 14:44
  • Log is different from MSI log generated in temp folder generated by msiexec, it is some other scanning done in C# that I just need to display. It is just not small enough to display with text control, and hence I was hoping to use `ScrollableText` with rich text. – Shintaro Takechi Nov 10 '20 at 16:45
  • As I wrote that is possible using a Spawned dialog invoked from a button click, but I assume you are already moving this to your application? – Stein Åsmul Nov 11 '20 at 02:39
  • @SteinÅsmul I actually tried to add the PushButton Control to the end dialog that pops NewDialog which has ScrollableText. Updated it via custom action. However, I did not achieve the ScrollableText modification like you mentioned. I am not sure what is wrong with my code... – Shintaro Takechi Nov 11 '20 at 16:49
  • Just for the reference, I added my EndDlg, InstallUISequence, VerifyDlg, and CustomAction. I know this is asking a lot, but if you have a chance and time, would you please take a look from my github repo? https://github.com/publicst/SharingContents/tree/master/WiX/VerificationAttempt – Shintaro Takechi Nov 11 '20 at 17:05
  • Had a quick look. There were some includes missing, I checked into github.com a quick test of a similar approach. Please do a test compile. I used VS2019 to upload to github.com. I think that works in 2017 too. – Stein Åsmul Nov 11 '20 at 21:52

1 Answers1

1

There is a mock-up example checked into github.com here: https://github.com/glytzhkof/WiXViewLogExperiment

This sample features a spawned dialog from a custom setup ExitDialog (called MyExitDialog) which shows the content of an RTF file. Please replace the "TestFile.rtf" on disk with your own RTF file and just compile and run the resulting MSI to check how this works.

Screenshot


Open MSI Log: I have another sample here for how to open the MSI log from the last MSI dialog: https://github.com/glytzhkof/WiXOpenLogFile (made first without understanding requirements properly - but always wanted this feature - it is not finished, but a functional demo).

(there is a feature to hide the open log checkbox if there is no MSI log created - use the Enable Global MSI Logging.reg file to enable MSI logging for all MSI operations. The log shows up with a random name in the TEMP folder.)


Link Section:

WiX GUI is both the embedded MSI GUI inside MSI files, but also the Burn setup.exe launcher GUI that can be created with many different and modern technologies. So MSI GUI versus setup.exe GUI.

Some selected links on WiX GUI:

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
  • Wow... confirmed working. The main difference I see is you are calling DoAction upon clicing viewing log button. Now I added that on my UISequence via `1` and I now see mine working. But I do not get it. The custom action is already called. Why do I have to call it again??? – Shintaro Takechi Nov 11 '20 at 22:41
  • Oh the very first comment you have regarding the difference between `InstallExecuteSequence` and `InstallUISequence` may be something that I might have to look deeper... – Shintaro Takechi Nov 11 '20 at 22:56
  • Yes, I was just writing that right now. I am honestly not sure of all the details involved here, but I think I found that the Install.Session object is still alive on the exit dialog, but some property values and temporary record could be gone from the database by then? Not sure I am afraid, but I remember something I wrote about this before (can't fnd it). Could it be that I format the text as RTF before handing it to the scrollable text control and that makes display work? – Stein Åsmul Nov 11 '20 at 22:59
  • I actually kept the C# customaction code as same as before, and called it via the DoAction on upon install button is clicked (not via `InstallExecuteSequence`). If I do that, the EndDlg's ScrollableText is updated properly. So I am guessing InstallExecuteSequence Custom Action calling is not going to update the UI, and if I want to update the ScrollableText, I would have to do it during the UI. If I word it like this it makes sense but was definitely tough clog for me to narrow down the cause without your assistance. Thank you so much Stein. – Shintaro Takechi Nov 11 '20 at 23:04
  • 1
    Glad it worked, but I am wondering too about the details. The `InstallExecuteSequence` runs as `LocalSystem`, the GUI runs as the `current user`. With that much impersonation going on it might be the case that the custom action changes are lost in the complexity involved. Keep in mind that when you run an MSI silently the `InstallUISequence` does not run at all. Just in case you have something relying on being done only in the `InstallUISequence`. No changes should be made to the system from there - viewing logs should be find though. – Stein Åsmul Nov 11 '20 at 23:24
  • Ah good point. If I want to generate the log under silent mode, I definitely have to call the custom action separately just so it would properly generate the log outside of UISequence. – Shintaro Takechi Nov 11 '20 at 23:26
  • 1
    Yes, this is a common error in many MSI files: the failure to do a complete install in silent mode. Failing to generate a log might not be the worst though, and could pass as acceptable, but one must always ensure that silent installs are complete. [Silent uninstall and interactive uninstall produces different effects](https://stackoverflow.com/a/29679464/129130). – Stein Åsmul Nov 11 '20 at 23:40