FolderBrowserDialog在.Net安装程序项目中卡住了

4

我编写了一个工具,应该作为.Net安装程序项目的一部分调用。

它应该要求用户选择一个目录,然后更新我的配置文件。

我使用以下代码显示文件选择器对话框:

{
    FolderBrowserDialog dlg = new FolderBrowserDialog();

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

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

如果我从命令行运行工具,FolderBrowserDialog会正常显示。但如果它被作为安装程序包的一部分,从安装程序类中调用,则在ShowDialog()时无限期挂起。
编辑:当我从VStudio或命令行运行它时,行为相同...我正在运行.Net 4(不是客户端配置文件)。
有什么提示可以告诉我可能做错了什么吗?
谢谢
马里奥

安装程序类型是什么(msi、exe、Installer class)? - KMoraz
这是一个MSI安装包,工具是从项目的CustomAction中调用的(并且它有自己的安装程序类)。 - Mario The Spoon
我以前在自定义操作中显示了对话框,没有任何问题。尝试从新项目中重现它。 - leppie
@leppie:尝试过了,但也不起作用。虽然我有第二个安装项目,一切都正常。那个项目设置了一个服务,我找不到任何区别... - Mario The Spoon
@MarioTheSpoon:我会对项目文件进行差异比较,以尝试发现任何奇怪的命令行开关等。 - leppie
1
@Leppie,显示对话框似乎可以工作,但FolderBrowserDialog不行,因为它需要STA线程。 - Peter
3个回答

2

看来我错过了这个机会,但我正在寻找类似的东西,并且发现了一个真正有效的答案,我也会解释为什么。您应该向安装程序项目添加新的自定义操作。然后,您只需要执行以下操作:

[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;
}

或者,您可以在新线程中执行任何想要的操作...真正的原因是因为您需要分配一个新的线程,该线程必须具有STA公寓状态。在Windows中,UI组件通常需要在单线程(STA)公寓状态下运行,因为这可以强制执行UI组件上的适当并发性,因为只允许一个线程一次修改UI。


1

我今天遇到了类似的问题。我有以下的代码:

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);
        }
    }
}

看起来没问题,对吧?它编译和链接时没有出现错误,但生成的可执行文件只是挂起,从未显示文件夹选择器。

对我有用的解决方法是在Main()之前添加[STAThread]

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);
        }
    }
}

现在文件夹浏览器窗口可以正确地呈现了。


好的,我会检查一下 - 但是我认为我的是由 Studio 自己创建的表单应用程序,所以它应该设置正确了,但我会检查一下。 - Mario The Spoon
问题在于他在一个MSI安装项目中,而在那里你没有Main方法。 - Peter

1

问题在于自定义操作等待(无限期)用户输入,但其在SYSTEM帐户下运行。

需要UI访问权限的自定义操作必须安排到立即执行的UI序列中,并模拟用户帐户。

WiX示例:

<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>

谢谢提供的信息!我使用Visual Studio 10中的安装程序项目构建了MSI。 - Mario The Spoon
但这难道不意味着我不能显示任何对话框吗?我可以很好地显示自己的对话框,只有从我的表单调用的FolderBrowserDialog没有显示... - Mario The Spoon
简单的消息框通常可以在每个序列中显示,但是依赖于API调用到用户桌面的操作需要使用用户模拟。VS安装项目对自定义操作的支持非常差,因此我强烈建议切换到WIX。 - KMoraz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接