FeaturesDialog does not work

Jul 11, 2016 at 6:35 AM
Edited Jul 11, 2016 at 6:42 AM
Hi,

In case of using the "FeaturesDialog" form within the ManagedProject class the result msi generate internal unhandled exception:
************** Exception Text **************
System.InvalidOperationException: Visual Styles-related operation resulted in an error because no visual style is currently active.
   at System.Windows.Forms.VisualStyles.VisualStyleRenderer.IsCombinationDefined(String className, Int32 part)
   at System.Windows.Forms.VisualStyles.VisualStyleRenderer..ctor(String className, Int32 part, Int32 state)
   at System.Windows.Forms.VisualStyles.VisualStyleRenderer..ctor(VisualStyleElement element)
   at WixSharp.UI.Forms.ReadOnlyTreeNode.Behavior.treeView_DrawNode(Object sender, DrawTreeNodeEventArgs e)
   at System.Windows.Forms.TreeView.OnDrawNode(DrawTreeNodeEventArgs e)
   at System.Windows.Forms.TreeView.CustomDraw(Message& m)
   at System.Windows.Forms.TreeView.WmNotify(Message& m)
   at System.Windows.Forms.TreeView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
Could you please fix it?

PS
In case of using the ManagedProject with the following code:
project.UI = WUI.WixUI_FeatureTree;
NO(!) exception was generated and the result msi works fine
Jul 11, 2016 at 12:17 PM
Can you please be more specific. What exactly '"FeaturesDialog" form within the ManagedProject' means? Testing raw out of box CustomUI project template with "Dialogs.Features" and ManagedSetup reveals no problem. Please find the working sample project here: https://dl.dropboxusercontent.com/u/2192462/Support/dx2003/WixSharp%20Setup4.7z. May be you can also share your test code so I can have a look at it?

May be somehow in your case the target OS is not handling visual styles properly. Please test test project I shared and see if it runs OK in your test.

If for what ever reason you want to minimize custom drawing in Features dialog of MamagedUI (like in your case) you can try this setting:
project.MinimalCustomDrawing = true;
Jul 11, 2016 at 1:20 PM
Edited Jul 11, 2016 at 1:27 PM
Thank you for your replay!

The code
project.MinimalCustomDrawing = true;
have fixed the situation.... Now the msi works without exception.
so strange behavior....

Below is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Xml.XPath;

using WixSharp;
using WixSharp.CommonTasks;
using WixSharp.Forms;
using WixSharp.UI.Forms;


// https://wixsharp.codeplex.com/releases/view/624868
// https://wixsharp.codeplex.com/SourceControl/latest#readme.txt

namespace MsiAppFormTest
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    private void btDeploy_Click(object sender, EventArgs e)
    {
      Compiler.WixLocation = @"some_location2\_msi\WixSharp.1.0.40.0\Wix_bin\bin\";

      var general = new Feature("General files", true, false);
      var modules = new Feature("Modules files", true, true);
      var modulett0 = new Feature("t0Module", true, true);
      var modulet1 = new Feature("t1Module", true, true);
      var modulet2 = new Feature("t2Module", true, true);
      var modulet2 = new Feature("t3Module", true, true);
      var modulet4 = new Feature("t4Module", true, true);
      var modulet5 = new Feature("t5Module", false, true);
      var modulet6 = new Feature("t6Module", false, true);
      var modulet7 = new Feature("t7odule", false, true);

      modules.Add(modulet0);
      modules.Add(modulet1);
      modules.Add(modulet2);
      modules.Add(modulet3);
      modules.Add(modulet4);
      modules.Add(modulet5);
      modules.Add(modulet6);
      modules.Add(modulet7);

      general.Add(modules);

      ManagedProject project = new ManagedProject("agent",
                        new Property("RURL", @"https://url.com") { IsDeferred = true },

                        new Dir(@"%ProgramFiles%\agent",
                          new File(modulet0, @"some_location\t0.dll"),
                          new File(modulet1, @"some_location\t1.dll"),
                          new File(modulet2, @"some_location\t2.dll"),
                          new File(modulet3, @"some_location\t3.dll"),
                          new File(modulet4, @"some_location\t4.dll"),
                          #region MySql
                          new File(modulet5, @"some_location\t51.dll"),
                          new File(modulet5g, @"some_location\t52.dll"),
                          #endregion
                          #region oracle
                          new File(modulet6, @"some_location\t6.dll"),
                          new Dir(modulet6, @"OraClient.x64",
                            new File(modulet6, @"some_location\OraClient.x64\oci.dll"),
                            new File(modulet6, @"some_location\OraClient.x64\ociw32.dll"),
                            new File(modulet6, @"some_location\OraClient.x64\orannzsbb10.dll"),
                            new File(modulet6, @"some_location\OraClient.x64\oraocci10.dll"),
                            new File(modulet6, @"some_location\OraClient.x64\oraociei10.dll")),
                          new Dir(modulet6, @"OraClient.x86",
                            new File(modulet6, @"some_location\OraClient.x86\oci.dll"),
                            new File(modulet6, @"some_location\OraClient.x86\ociw32.dll"),
                            new File(modulet6, @"some_location\OraClient.x86\orannzsbb10.dll"),
                            new File(modulet6, @"some_location\OraClient.x86\oraocci10.dll"),
                            new File(modulet6, @"some_location\OraClient.x86\oraociei10.dll")),
                          #endregion
                          #region ftp
                          new File(modulet7, @"some_location\t7.dll"),
                          new File(modulet7, @"some_location\t71.dll"),
                          new File(modulet7, @"some_location\t72.dll"),
                          #endregion

                          new Dir(general, @"x64", new File(@"some_location\x64\SQLite.Interop.dll")),
                          new Dir(general, @"x86", new File(@"some_location\x86\SQLite.Interop.dll")),

                          new File(general, @"some_location\a0.db"),
                          new File(general, @"some_location\a1.pos"),
                          new File(general, @"some_location\a2.json"),
                          new File(general, @"some_location\agent.config"),

                          new File(general, @"some_location\System.Data.SQLite.dll"),
                          new File(general, @"some_location\a5.dll"),
                          new File(general, @"some_location\agent.exe"),

                          new File(general, @"some_location\u0.config"),
                          new File(general, @"some_location\u1.exe"))
                        );

      project.DefaultFeature = general;
      project.DefaultFeature.Children.Add(modulet0);
      project.DefaultFeature.Children.Add(modulet1);
      project.DefaultFeature.Children.Add(modulet2);
      project.DefaultFeature.Children.Add(modulet3);
      project.DefaultFeature.Children.Add(modulet4);
      project.DefaultFeature.Children.Add(modulet5);
      project.DefaultFeature.Children.Add(modulet6);
      project.DefaultFeature.Children.Add(modulet7);

      //if( Environment.GetEnvironmentVariable("buid_as_64") != null ) project.Platform = Platform.x64; // работает НЕвсегда....
      if( IntPtr.Size == 8 ) project.Platform = Platform.x64;

      project.GUID = new Guid("0c47a0be-437d-4ab6-883a-f0ecc38ddbff");
      project.PreserveTempFiles = true;
      //project.MinimalCustomDrawing = true; // <-------------------------- fix the problem

      project.ManagedUI = new ManagedUI();
      project.ManagedUI.InstallDialogs.Add<WelcomeDialog>()
                                      .Add<LicenceDialog>()
                                      .Add<InstallDirDialog>()
                                      .Add<FeaturesDialog>()
                                      .Add<CustFormSrvAdr>()
                                      .Add<ProgressDialog>()
                                      .Add<ExitDialog>();

      project.ManagedUI.ModifyDialogs.Add<FeaturesDialog>()
                                     .Add<ProgressDialog>()
                                     .Add<ExitDialog>();

      project.AfterInstall += Project_AfterInstall;
      Compiler.BuildMsi(project);

      MessageBox.Show("Completed successfully!", "Status");
      Close();
    }

    private static void Project_AfterInstall(SetupEventArgs e)
    {
      if( e.IsInstalling ) {
        string strSrvUrl = e.Session.Property("RURL");
        string configFile = System.IO.Path.Combine(e.InstallDir, "Agent.config");

        UpdateAsXml(configFile, strSrvUrl);
      }
      else if( e.IsUninstalling ) {
        try {
          System.IO.Directory.Delete(e.InstallDir, true);
        }
        catch { /*log error if required*/ }
      }
    }

    static public void UpdateAsXml(string configFile, string strSrvUrl)
    {
      var xDoc = XDocument.Load(configFile);
      xDoc.XPathSelectElement("//configuration/appSettings/add[@key='bla-bla']").Attribute("value").Value = strSrvUrl;
      xDoc.Save(configFile);
    }
  }
}
Jul 12, 2016 at 10:55 AM
I tested your code. And it seems to have no problems rendering the TreeView on my system (Win10 x64). It's kinda expected as everything indicated it was a pure rendering problem, which doesn't depend on the MSI content but on the target system rendering capabilities.

Image

Have you tested my sample?

It means that as I suspected your target system and Wix# tree node rendering algorithm are incompatible in some way. What way? It's hard to say as I have no test case to work with.

However that setting MinimalCustomDrawing is implemented exactly for the cases like yours. It doesn't do much, it simply excludes custom drawing of the node and falls back to the default system drawing algorithm. Custom drawing was needed only to improve the the appearance of the feature text in the TreeView . If you have it disabled with MinimalCustomDrawing = true the disabled feature text color will still be black instead of gray (limitation of TreeView WinForms control). Not a big lost particularly in your case as your target system where new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Opened); cannot be executed without the exception. Why? Who knows. It's deep in WinForms implementation. Fixing it impossible because it's not in Wix# code. Work around is possible but not feasible without the test case and as far as I know it's not reproducible on other systems except yours.

Thus you can safely disable advanced custom drawing with 'project.MinimalCustomDrawing = true;'. I did not defaulted it to true because I thought that the chances of incompatibility are very low. And it is the case as it is the first report for the last 2-3 years the feature exists. But if I have at least another report like yours I will change the defaults.
Jul 12, 2016 at 3:24 PM
I checked the source code and the impact of MinimalCustomDrawing = true is even less than I anticipated. It is in fact a check box who gets grayed out if the node is a read-only one, not the text. Thus the visual compromize is very minor.

I also saw the opportunity there to fall back to default TreeView checkbox node rendering automatically as the result of the handled runtime exception. This way you don't have to set MinimalCustomDrawing = true at compile time. This change will be available with the very next release (very soon).
Jul 13, 2016 at 5:26 AM
The latest NuGet prerelease v1.0.40.3
Install-Package WixSharp.bin -Pre
does the trick with automatic fallback to the minimized custom drawing in case of any runtime error in the drawing routine.

Note that if you don't set the value of MinimalCustomDrawing Wix# will try to determine its value at runtime. This is the whole algorithm expressed in a pseudo-code:
if MinimalCustomDrawing.IsSet:
    if MinimalCustomDrawing == true:
        CustomDrawModel = TextOnly 
    else:
        CustomDrawModel = DrawAll
else:
    if current_DPI == 96:
        CustomDrawModel = DrawAll 
    else:
        CustomDrawModel = TextOnly 
...
void DrawAll_Routine()
{
    try:
        // do the drawing
    catch:
        CustomDrawModel = TextOnly
}
I checked the source code and the impact of MinimalCustomDrawing = true is even less than I anticipated. It is in fact a check box who gets grayed out if the node is a read-only one, not the text. Thus the visual compromize is very minor.

I also saw the opportunity there to fall back to default TreeView checkbox node rendering automatically as the result of the handled runtime exception. This way you don't have to set MinimalCustomDrawing = true at compile time. This change will be available with the very next release (very soon).
Jul 13, 2016 at 11:27 AM
Edited Jul 13, 2016 at 11:28 AM
Oleg,
I am trying new (1.0.40.3) version. The result:
Image

With previous (1.0.40.2) version the project works.
Jul 13, 2016 at 11:41 AM
Yeah, I sent you the message about that yesterday but it somehow didn't go through.

You see, when working on your problem report I discovered that there is a logical flaw in the feature hierarchy building algorithm that Wix# using. I logged the defect for this (https://wixsharp.codeplex.com/workitem/131) and it got fixed in the v1.0.40.3.

However the defect (before the fix) was hiding the problem with your code. The defect is fixed now and as expected your code can no longer compile.
The problem in your code is that you are adding modulet0 to both DefaultFeature and modules and this is wrong. According MSI feature model a single feature can only be present in a single point of the feature tree. Thus if you want to fix your code you will need to remove the following code block:
project.DefaultFeature.Children.Add(modulet0);
...
project.DefaultFeature.Children.Add(modulet1);
Jul 13, 2016 at 12:02 PM
Edited Jul 13, 2016 at 12:06 PM
Oleg, thank you for your FAST reply!

I have removed the following part of code:
project.DefaultFeature.Children.Add(modulet0);
...
project.DefaultFeature.Children.Add(modulet1);
The project works but no msi is generated....
In other words the project does not generate an error but does not create the result msi file....
Jul 13, 2016 at 12:50 PM
It's hard for me to comment as I have very little information about how you conduct your testing.

I know for sure that the code you shared with me is not exactly the same the code you test. I conclude this from the fact that there were a few C# syntax errors that Visual Studio could not possibly pass through and yet you have reached somehow MSI testing stage.

I don't know how you build your msi. Is it VS Wix# project? Is it VS C# project? Where do you look for errors?

Why don't we change the approach to be more productive. Let's try to build/run/test something that already works.
I have already shared with you a complete VS project for the first problem described in this thread. Did you run it? I had no feed back from you on this. Though arguably it doesn't matter any more.

Please download the complete test case from here: https://dl.dropboxusercontent.com/u/2192462/Support/dx2003/FeatureTree.7z and tell me if you can build it.

It is not a VS project but a build script that you can run if you have Wix# installed (download page on this site). In order to build it you will need to ensure the correct locations in the build.cmd and setup.cs.

Though if you have difficulties running the build script with batch file then you will have to prepare a proper test case - VS project that I can load and test in my environment.
Jul 13, 2016 at 1:44 PM
Edited Jul 13, 2016 at 1:44 PM
Oleg,
your test case works well!
sorry, I have found the error in my project.... and have fixed it.
now it works fine also.
no problem with your new (10.0.40.3) build
thank you!
Jul 13, 2016 at 5:29 PM
Great. Thank you. Now I will be making a proper release.
Jul 14, 2016 at 7:17 AM
All done. Fixed in Release v1.0.41.0