4

I wrote a tool that should be called as part of a .Net installer project.

It should ask the user for a directory and then update my config.

I use the following code to show the file-chooser dlg:

{
    FolderBrowserDialog dlg = new FolderBrowserDialog();

    dlg.Description = "Trace-Verzeichnis auswählen";
    dlg.ShowNewFolderButton = true;

    if (DialogResult.OK ==  dlg.ShowDialog( this ))
    {
        tbTraceDir.Text = dlg.SelectedPath;
    }
}

If I run the tool from the command line, the FolderBrowserDialog shows ok. If it is called as part of the installer package, from the installer class, it hangs indefinitely at ShowDialog()

Edit: Same behaviour when I run it form VStudio or from the command line... I am running .Net 4 (not the client profile)

Any hints what I might be doing wrong?

thanks

Mario

Mario The Spoon
  • 4,799
  • 1
  • 24
  • 36
  • What type of installer (msi, exe, Installer class)? – KMoraz Apr 02 '12 at 19:05
  • it's an msi package, and the tool is called from a CustomAction of the project (and it has an installer class on its own). – Mario The Spoon Apr 02 '12 at 19:07
  • I have shown dialogs within custom action before without issue. Try reproduce it from a fresh project. – leppie Apr 02 '12 at 20:30
  • @leppie: tried but does not work either. Though I do have a second installation project where everything is working. that project sets up a service, and i can not find any differences... – Mario The Spoon Apr 02 '12 at 20:58
  • @MarioTheSpoon: I would diff the project files to try spot any weird command line switches, etc. – leppie Apr 02 '12 at 21:15
  • 1
    @Leppie, showing dialogs seems to work but the FolderBrowserDialog odes not as it requires a STA thread. – Peter Jul 29 '13 at 14:11

3 Answers3

2

Seems I missed the boat on this one, but I was looking for something similar and found an excellent answer that actually works, and I'll explain why as well. You should add a new custom action to your installer project. Then, all you would need to do is:

[CustomAction]
public static ActionResult SpawnBrowseFolderDialog(Session session)
{
    Thread worker = new Thread(() =>
    {
        FolderBrowserDialog dialog = new FolderBrowserDialog();
        dialog.SelectedPath = session["INSTALLFOLDER"];
        DialogResult result = dialog.ShowDialog();
        session["INSTALLFOLDER"] = dialog.SelectedPath;
    });
    worker.SetApartmentState(ApartmentState.STA);
    worker.Start();
    worker.Join();
    return ActionResult.Success;
}

Or, you can just do anything you want inside of the new thread...really, the reason why this works is because you need to allocate a new thread which must have an STA apartment state. UI components in Windows generally need to be run in a single threaded (STA) apartment state because this enforces proper concurrency on the UI component since just one thread is allowed to modify the UI at a time.

Alexandru
  • 12,264
  • 17
  • 113
  • 208
1

I had a similar issue today. I had the following code:

using System;
using System.Windows.Forms;

class dummy{

    public static void Main() {
        FolderBrowserDialog f = new FolderBrowserDialog();
        f.SelectedPath = System.Environment.CurrentDirectory;
        f.Description= "Select a folder, for great justice.";
        f.ShowNewFolderButton = true;
        if(f.ShowDialog() == DialogResult.OK) {
            Console.Write(f.SelectedPath);
        }
    }
}

Looks fine, right? It compiled and linked with no errors, but the resulting executable just hangs without ever displaying a folder chooser.

What fixed it for me was to add [STAThread] before Main().

using System;
using System.Windows.Forms;

class dummy{
    [STAThread]
    public static void Main() {
        FolderBrowserDialog f = new FolderBrowserDialog();
        f.SelectedPath = System.Environment.CurrentDirectory;
        f.Description= "Select a folder, for great justice.";
        f.ShowNewFolderButton = true;
        if(f.ShowDialog() == DialogResult.OK) {
            Console.Write(f.SelectedPath);
        }
    }
}

And now the folder browser window renders properly.

rojo
  • 24,000
  • 5
  • 55
  • 101
1

The issue is the custom action waits (infinitely) for user input, but its runs under SYSTEM account.

Custom action that needs UI access, must be scheduled to the UI sequence with Immediate execute which impersonates the user account.

WiX example:

<CustomAction Id='FooAction' 
              BinaryKey='FooBinary' 
              DllEntry='FooEntryPoint' 
              Execute='immediate'
              Return='check'/>

<Binary Id='FooBinary' SourceFile='foo.dll'/>

<InstallUISequence>
  <Custom Action='FooAction' After='AppSearch'></Custom>
</InstallUISequence>
KMoraz
  • 14,004
  • 3
  • 49
  • 82
  • Thanks for the info! I built the msi using a setup project in visual studio 10. – Mario The Spoon Apr 02 '12 at 20:46
  • But wouldn't this mean that I can't show any dialog? I am showing my own dialog just fine, only the FolderBrowserDialog, which is called from my form, does not show... – Mario The Spoon Apr 02 '12 at 20:57
  • Simple message boxes typically can be shown in every sequence, but actions that depends on API calls to the user desktop needs to user impersonation. VS setup projects have very poor support for custom actions, so I strongly recommend switching to WIX. – KMoraz Apr 02 '12 at 21:09