Why can't we change apartment state of a ThreadPool thread and why don't we require a messagepump when ShowDialog is used?
The apartment is selected by a call to CoInitializeEx(). A thread in the thread pool has already made that call, changing the apartment after that call is not possible.
That a thread pool would choose MTA makes sense, it is after all intended as a worker thread and shouldn't be blocked by method calls that need to be marshaled. Selecting a single-threaded apartment has the additional requirement of pumping a message loop. Something you'd never expect a threadpool thread to do.
The message loop is necessary because that's the vehicle that COM uses to marshal a call made on another thread. That call has to be "injected" in the STA thread, that's only possible if the thread is in a known quiescent state. If it isn't, such a call would cause major re-entrancy problems. Which it sometimes does even if the thread is pumping the loop.
You didn't need to pump a message loop yourself with Application.Run() because ShowDialog() starts its own message loop. That's how it gains modality. That nested loop exits as soon as the dialog closes.
You shouldn't rely on specific behavior for thread pool threads. In general, a thread in the threadpool should be able to be replaced at any time by the CLR, without your knowledge. Thread pool threads are meant to be used with simple tasks, preferably short lived ones.
If you want to have fine grained control over thread settings, you should create a dedicated thread. Setting the apartment state is a perfect example of this.
In addition to the above, theoretical reasons, there's a practical problem with what you are attempting. Hosting a form on a second thread doesn't work (without a lot of extra work in place). Forms must be run on the same thread as the message pump - otherwise, they won't receive any windows messages, and will not update properly.
You can create a form on a separate thread if you implement a full message pump for that thread, but it's usually a better idea to just put your work items onto background threads, and use asyncrhonous programming techniques to keep your since UI thread responsive.