Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception when using FolderBrowserDialog

I'm getting the following Exception when trying to use FolderBrowserDialog: System.Threading.ThreadStateException: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process.

I have Googled this problem extensively and the solutions that everybody suggests seem to be to put [STAThreadAttribute] above the Main method, to delete all dll's from the Debug folder, or to use the Invoke method. I have tried all of these, and I still get the same exception.

Here's the code:

public partial class Form1 : Form
{
    public event EventHandler ChooseLocationHandler = null;

    public string DestFolder
    {
        set { textBox1.Text = value; }
        get { return textBox1.Text; }
    }

    public Form1()
    {
        InitializeComponent();
    }

    private void ChooseLocationButton_Click(object sender, EventArgs e)
    {
        if (ChooseLocationHandler != null)
            ChooseLocationHandler(this, e);
    }
}

And in my presenter is the following:

public partial class Presenter
{
    Form1 myForm;
    public Presenter()
    {
        myForm = new Form1();
        myForm.ChooseLocationHandler += ChooseLocationHandler;
        myForm.Show();
    }

    public void ChooseLocationHandler(object obj, EventArgs e)
    {
        Form1 sender = (Form1)obj;

        FolderBrowserDialog fbd = new FolderBrowserDialog();
        fbd.RootFolder = System.Environment.SpecialFolder.MyComputer;
        fbd.ShowNewFolderButton = true;
        if (fbd.ShowDialog() == DialogResult.Cancel)
            return;

        sender.DestFolder = fbd.SelectedPath;
    }
}

I'm getting the Exception on fbd.ShowDialog().

like image 628
Daniel Avatar asked Jul 28 '11 13:07

Daniel


3 Answers

A thread is either STA or MTA it can't be specified just for one method so the attribute must be present on the entry point.

From STAThreadAttribute in MSDN :

Apply this attribute to the entry point method (the Main() method in C# and Visual Basic). It has no effect on other methods.

If this code is called from a secondary thread you have 3 choices :

IMPORTANT NOTE: Running (as you seem to do) System.Windows.Forms code inside an MTA thread is unwise, some functionalities like file open dialogs (not only folder) require a MTA thread to work.

Changing your secondary thread apartment

If you create the thread yourself (and don't use the specificity of MTA) you could just change it's apartment before starting it :

var t = new Thread(...);
t.SetApartmentState(ApartmentState.STA);

 

Creating a thread just for it

If you don't control the thread creation you could do it in a temporary thread :

string selectedPath;
var t = new Thread((ThreadStart)(() => {
    FolderBrowserDialog fbd = new FolderBrowserDialog();
    fbd.RootFolder = System.Environment.SpecialFolder.MyComputer;
    fbd.ShowNewFolderButton = true;
    if (fbd.ShowDialog() == DialogResult.Cancel)
        return;

    selectedPath = fbd.SelectedPath;
}));

t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
Console.WriteLine(selectedPath);

 

Invoking in another(STA) thread

If your main thread also contain System.Windows.Forms code you could invoke in it's message loop to execute your code :

string selectedPath = null;
Form f = // Some other form created on an STA thread;
f.Invoke(((Action)(() => {
    FolderBrowserDialog fbd = new FolderBrowserDialog();
    fbd.RootFolder = System.Environment.SpecialFolder.MyComputer;
    fbd.ShowNewFolderButton = true;
    if (fbd.ShowDialog() == DialogResult.Cancel)
        return;

    selectedPath = fbd.SelectedPath;
})), null);
Console.WriteLine(selectedPath);
like image 59
Julien Roncaglia Avatar answered Nov 13 '22 08:11

Julien Roncaglia


This fixed my issue. [STAThread] static void Main()

Just an extra question: why can't microsoft make things simple? Are they trying to disgust people to do some coding?

like image 32
Eric Mariacher Avatar answered Nov 13 '22 08:11

Eric Mariacher


As simple as the below :

using System.Windows.Forms;
namespace fileConverterBaset64
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)

Add the command [STAThread] before your main method. That's it, it would work.

like image 2
Shankar K Arun Avatar answered Nov 13 '22 08:11

Shankar K Arun