Q:

Как создать форму с отдельным потоком для обработки виндоус сообщений?

Для программы создаётся расширение на .NET с использованием WinForms. Из этого расширение вызывается форма.
Проблема в том, что поток с виндоус очередью у основного приложения повисает. Как сделать, так чтобы у формы расширения был отдельный поток на обработку очереди сообщений?
И как его правильно потом остановить после отключения расширения?
UPD
Утрированный пример:
private void button1_Click(object sender, EventArgs e)
{
    Form2 form2 = new Form2();
    form2.Show();

    Thread.Sleep(1000 * 10); // что-то долго делает.

    form2.Close();
}

Здесь требуется чтобы форма form2 нормально прорисовывалась и реагировала на действия пользователя, хотя при этом поток родительской формы виснет на обработке чего-нибудь.

A:

Чтобы form2 работала в отдельном потоке независимо от родительской окна можно создать поток и установить у него апартаменты STA. Из этом потока показываем form2.
Основываясь на этом примере создаем класс второго потока:
(UPD по совету @PavelMayorov упрощаем реализацию)
class SecondWindowsThread : IDisposable
{
    private SynchronizationContext ctx;

    public SecondWindowsThread()
    {
        ManualResetEvent mre = new ManualResetEvent(false);
        try
        {
            Thread thread = new Thread(
                () =>
                {
                    this.ctx = new WindowsFormsSynchronizationContext();
                    SynchronizationContext.SetSynchronizationContext(this.ctx);
                    mre.Set();
                    Application.Run();
                }
            );
            thread.IsBackground = true;
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            mre.WaitOne();
        }
        finally
        {
            mre.Dispose();
        }
    }

    #region IDisposable Support
    private bool disposedValue = false;

    public void Dispose()
    {
        if (disposedValue) return;

        if (this.ctx != null)
        {
            this.ctx.Send((_) => Application.ExitThread(), null);
            this.ctx = null;
        }
        disposedValue = true;
    }

    #endregion

    public SynchronizationContext SynchronizationContext
    {
        get
        {
            if (this.disposedValue) throw new ObjectDisposedException(nameof(SynchronizationContext));
            return this.ctx;
        }
    }
}

Тогда обработчик кнопки будет такой:
private void button1_Click(object sender, EventArgs e)
{
    Form2 form2 = null;

    using (var t2 = new SecondWindowsThread())
    {
        t2.SynchronizationContext.Send(
            (_) =>
            {
                form2 = new Form2();
                form2.Show();
            }, null);

        Thread.Sleep(1000 * 10); // что-то долго делает.

        t2.SynchronizationContext.Send((_) => form2.Close(), null);
    }
}

При этом надо учитывать, что работать с компонентами одной формы из другой надо через синхронизирующий контекст или методы Control.Invoke, Control.BeginInvoke.
Лабораторная работа

