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


While calling a OpenFileDialog (http://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 (31)

  1. Edward says:

    Thank you so much for this post. Life savers!

  2. luisnike19 says:

    Thank you!

  3. Koki says:

    This is Awh some, many many thanks 🙂

  4. vijitha says:

    i am getting at DialogState state = new DialogState(); is there any namespace fro that we have to use

  5. You would need to define it.

    public class DialogState

       {

           public DialogResult result;

           public FileDialog dialog;

           public void ThreadProcShowDialog()

           {

               result = dialog.ShowDialog();

           }

       }

  6. Michael Fiedlriver says:

    That's owesome! I just love internet!

  7. Boris P. says:

    Thanks for the code.

    Could everyone tell me, why the code is doing just fine on my local machine, but when I implement it on server (windows server 2008, .net 4 framework installed) it doesn't work (the page can not be displayed)? The problem is in line dialog.ShowDialog(), when I change it with something more simple (for example number 3), the error is not shown.

    Another question: What does command InitializeComponent means? Even if I comment it, the service work well (on my local machine of course).

    Thanks for answers.

  8. Thank a lot

    my problem resolved!

  9. p0nga says:

    Thank you very much! You solved my problem! 🙂

  10. Geleta A. says:

    great!! article. it helped me alot.

  11. Ghufran Zahidi says:

    Thank you,

    After reading to many blogs,My problem resolved here

    Thanks again for wonderful post..

  12. Anuja says:

    Excellent

  13. Flesh Sade says:

    Thanks,

    Great code – I love internet

  14. Venkat ,Bangalore says:

    Excellent post ,  while reading it self , my problem got resolved.

  15. Ntamong says:

    Thank you, is working now

  16. Stepheson Alves says:

    Thanks man!!!

    Very very good!!

  17. Viji says:

    Thanks, very helpful and neat!

  18. Priya says:

    Thank You  

  19. Nilesh says:

    Thanks Man, you saved my time….

  20. Err1 says:

    Thank you!!

  21. sabbir says:

    Great work

  22. sakthi says:

    Thank you

  23. Legesse says:

    Extremly relieving

  24. legesse says:

    Extremly useful

  25. charles says:

    More thanks 2 u.

  26. Gilberto Couto says:

    Many thanks!!

    You saved my day today.

  27. Carlos says:

    Thanks for this post, also saved my day!

  28. Richard Vogt says:

    Thank you so much. All these years later and it is still saving people!

  29. Chandan says:

    Thanks.. Problem Solved.

  30. Amar Singh says:

    Thank You ! Really Helpful.

Skip to main content