3

My WIX installer launches an immediate custom action. The custom action starts a WPF dialog prompting the user for a BD connection parameters (I basically wrote the 'new connection' DB prompter dialog in WPF, to get me a connection string that the custom action can inject in the installed application's configuration file). The WIX code is fairly simple to figure out, and I know I execute the custom action just fine - I put there a MessageBox and a MmsiBreak on the call to my custom action method. I get there without a problem. When the custom action instantiates my WPF dialog window, I get an InvaliOperationException: "The calling thread must be STA, because many UI components require this".

The same code runs fine when I put it in a standard WPF application, because VisualStudio generates boiler plate code with Main() that has a STAThreadAttribute on it. I can't tack that attribute on the msiexec caller, and if I try to set the thread apartment state in my custom action, it fails:

Thread.CurrentThread.SetApartmentState(ApartmentState.STA);

Is not supposed to work for framework past 2.0.

Is there any way to do what I'm trying to do here? I'd appreciate some pointers.


EDIT

I even tried to run the dialog in its own thread, e.g. the code is like this:

// Static class members
static ManualResetEvent _done = new ManualResetEvent(false);
static ActionResult _caResult;
static Session _session;
static Thread _worker;

[CustomAction]
static public ActionResult PromptForDB(Session session)
{
    _session = session;
    _worker = new Thread(WorkerThread);
    _worker.Start();
    _done.WaitOne();
    return _caResult;
}

[STAThread]
static void WorkerThread()
{
    try
    {
        Prompter wnd = new Prompter();
        if (!(bool)wnd.ShowDialog())
        {
            _caResult = ActionResult.SkipRemainingActions;
        }
        else
        {
            // Harvest our properties (omitted from this post)
            _caResult = ActionResult.Success;
        }
        catch (Exception ex)
        {
            _caResult = ActionResult.Failure;
            _session.Log("Error: " + ex.Message);
        }
        finally
        {
            _done.Set();
        }
    }

That does not work either.

Sam Dahan
  • 871
  • 1
  • 8
  • 20

1 Answers1

3

Before starting your new thread, set its ApartmentState as follows:

_worker.SetApartmentState(ApartmentState.STA);

See this:
The calling thread must be STA, because many UI components require this in WPF

Community
  • 1
  • 1
Rami A.
  • 10,302
  • 4
  • 44
  • 87
  • The answer is that SetpartmentState() has to be called before the thread is created. Thanks a bunch, Rami! – Sam Dahan Jan 17 '12 at 22:05