Share via


“Current thread must be set to single thread apartment (STA) mode before OLE calls can be made”

While calling a OpenFileDialog (https://msdn.microsoft.com/en-us/library/system.windows.forms.openfiledialog.aspx) via Installer class as a Custom Action in the Visual Studio Setup project, it just hangs there.

When we attach a debugger we receive an error: "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."

The same code works fine on Win XP and 2003. It only occurs on Win Vista and higher version of Operating Systems

The sample code is mentioned below:

            MessageBox.Show("Cannot Locate Config File");

            MessageBox.Show("Pid : " + System.Diagnostics.Process.GetCurrentProcess().Id.ToString());

            String Location = String.Empty;

            OpenFileDialog frm = new OpenFileDialog();  

            frm.InitializeLifetimeService();

            frm.Filter = "Config Files (*.config)|*.config| (*.xml)|*.xml";

            frm.Title = "Browse Config file";

            DialogResult ret = frm.ShowDialog();

            if (ret == DialogResult.OK)

            Location = frm.FileName;

            InitializeComponent();

The problem is that the MSI thread is running as an MTA thread, but the FileDialog.ShowDialog requires an STA thread. To achieve this you will need to start a STA background thread and call the dialog from that thread. Basically I did the following:

- Added the DialogState class. This keeps track of the input and output for the thread.

- Added the STAShowDialog function. This function takes a FileDialog, calls ShowDialog on a background STA thread, and then returns the results.

- Changed the call from DialogResult ret = frm.ShowDialog(); to DialogResult ret = STAShowDialog(frm);

You may need to add exception handling separately.

Here is the complete code:

using System;

using System.Collections;

using System.Collections.Generic;

using System.ComponentModel;

using System.Configuration.Install;

using System.Linq;

using System.Windows.Forms;

 

namespaceWindowsFormsApplication1

{

    [RunInstaller(true)]

    public partial class Installer1 : Installer

    {

        publicInstaller1()

        {

            MessageBox.Show("Cannot Locate Config File");

            MessageBox.Show("Pid : " + System.Diagnostics.Process.GetCurrentProcess().Id.ToString());

            String Location = String.Empty;

            OpenFileDialog frm = new OpenFileDialog();

            frm.InitializeLifetimeService();

            frm.Filter = "Config Files (*.config)|*.config| (*.xml)|*.xml";

            frm.Title = "Browse Config file";

            DialogResultret = STAShowDialog(frm);

 

            if (ret == DialogResult.OK)

                Location = frm.FileName;

 

            MessageBox.Show(Location);

 

            InitializeComponent();

        }

 

        /* STAShowDialog takes a FileDialog and shows it on a background STA thread and returns the results.

         * Usage:

         * OpenFileDialog d = new OpenFileDialog();

         * DialogResult ret = STAShowDialog(d);

         * if (ret == DialogResult.OK)

         * MessageBox.Show(d.FileName);

         */

        private DialogResult STAShowDialog(FileDialogdialog)

        {

            DialogState state = new DialogState();

            state.dialog = dialog;

            System.Threading.Thread t = new System.Threading.Thread(state.ThreadProcShowDialog);

            t.SetApartmentState(System.Threading.ApartmentState.STA);

            t.Start();

            t.Join();

            returnstate.result;

        }

    }

 

    /* Helper class to hold state and return value in order to call FileDialog.ShowDialog on a background thread.

     * Usage:

     * DialogState state = new DialogState();

     * state.dialog = // <any class that derives from FileDialog>

     * System.Threading.Thread t = new System.Threading.Thread(state.ThreadProcShowDialog);

     * t.SetApartmentState(System.Threading.ApartmentState.STA);

     * t.Start();

     * t.Join();

     * return state.result;

     */

    public class DialogState

    {

        public DialogResultresult;

        public FileDialogdialog;

 

        public voidThreadProcShowDialog()

        {

            result = dialog.ShowDialog();

        }

    }

}

Comments

  • Anonymous
    March 23, 2011
    Thank you so much for this post. Life savers!

  • Anonymous
    May 10, 2011
    Thank you!

  • Anonymous
    February 25, 2012
    This is Awh some, many many thanks :)

  • Anonymous
    March 14, 2012
    i am getting at DialogState state = new DialogState(); is there any namespace fro that we have to use

  • Anonymous
    March 18, 2012
    You would need to define it. public class DialogState    {        public DialogResult result;        public FileDialog dialog;        public void ThreadProcShowDialog()        {            result = dialog.ShowDialog();        }    }

  • Anonymous
    April 29, 2012
    That's owesome! I just love internet!

  • Anonymous
    June 27, 2012
    The comment has been removed

  • Anonymous
    December 30, 2012
    Thanks, nice code

  • Anonymous
    July 08, 2013
    Thank a lot my problem resolved!

  • Anonymous
    September 17, 2013
    Thank you very much! You solved my problem! :-)

  • Anonymous
    December 02, 2013
    great!! article. it helped me alot.

  • Anonymous
    January 15, 2014
    Thank you, After reading to many blogs,My problem resolved here Thanks again for wonderful post..

  • Anonymous
    March 14, 2014
    Excellent

  • Anonymous
    April 17, 2014
    Thanks, Great code - I love internet

  • Anonymous
    July 10, 2014
    Excellent post ,  while reading it self , my problem got resolved.

  • Anonymous
    July 15, 2014
    Thank you, is working now

  • Anonymous
    September 02, 2014
    Thanks man!!! Very very good!!

  • Anonymous
    September 11, 2014
    Thanks, very helpful and neat!

  • Anonymous
    January 06, 2015
    Thank You  

  • Anonymous
    January 27, 2015
    Thanks Man, you saved my time....

  • Anonymous
    February 05, 2015
    Thank you!!

  • Anonymous
    February 10, 2015
    Great work

  • Anonymous
    May 21, 2015
    Thank you

  • Anonymous
    May 21, 2015
    Extremly relieving

  • Anonymous
    May 21, 2015
    Extremly useful

  • Anonymous
    July 19, 2015
    More thanks 2 u.

  • Anonymous
    November 11, 2015
    Many thanks!! You saved my day today.

  • Anonymous
    November 12, 2015
    Thanks for this post, also saved my day!

  • Anonymous
    September 21, 2016
    Thank you so much. All these years later and it is still saving people!

  • Anonymous
    October 12, 2016
    Thanks.. Problem Solved.

  • Anonymous
    October 18, 2016
    Thank You ! Really Helpful.