Rozpoczynam cykl z C# z którym styczność mam na co dzień , otóż przychodzi mi rozwiązać łatwiejsze oraz trudniejsze zadania(subiektywne podejście ;)) ale dzisiaj natrafiłem na problem z wyświetleniem FolderDialogu – wyboru katalogu podczas instalacji MSI.
Wszystko działało w aplikacji testowej – jednak z instalacją był problem, po resarchu natrafiłem na taki artykuł:
http://blogs.msdn.com/b/smondal/archive/2012/12/31/10059279.aspx
wyjaśniający takie zachowanie , ogólnie chodzi o różnice działania całej aplikacji a w szczególności między wątkami STA i MTA , ogólnie chodzi o relikt przeszłości kiedy to systemy nie miały możliwości zrównoleglenia…, odsyłam do krótkiego artykułu:
http://www.pzielinski.com/?p=846
Przedstawię tutaj sposób na rozwiązanie tego problemu wzorując się na powyższym artykule z msdn :
Tworzę klasę pomocniczą:
public class DialogState
{
public DialogResult result;
public FolderBrowserDialog dialog;
public IWin32Window parent;
public void ThreadProcShowDialog()
{
result = dialog.ShowDialog(parent);
}
}
w zasadzie jedyną zastanawiającą rzeczą może być argument metody ShowDialog, otóż moje okienko jest TopMost – widoczne najwyżej , przekazując rodzica do wywołania ShowDialog moje okienko wyboru folderu będzie jeszcze wyżej 🙂
Następnie metoda wykonania wątku STA
private DialogResult STAShowDialog(FolderBrowserDialog dialog)
{
DialogState state = new DialogState();
state.dialog = dialog;
state.parent = this;
System.Threading.Thread t = new System.Threading.Thread(state.ThreadProcShowDialog);
t.SetApartmentState(System.Threading.ApartmentState.STA);
t.Start();
t.Join();
return state.result;
}
Chyba najważniejsza linijka dotycząca wątku STA:
t.SetApartmentState(System.Threading.ApartmentState.STA);
określa jaki to będzie wątek – tu tkwi cały problem instalator MSI działa jako MTA i nie wyświetli nam okienka z wyborem folderu(w moim przypadku) , następnie zapewniona synchronizacja poprzez join ,jako parenta przekazuje this – obiekt(form) na rzecz którego działa dialog.
Zastosowanie:
using (FolderBrowserDialog dialog = new FolderBrowserDialog())
{
dialog.Description = "opis";
dialog.ShowNewFolderButton = false;
dialog.RootFolder = Environment.SpecialFolder.MyComputer;
DialogResult ret = STAShowDialog(dialog);
if (ret == DialogResult.OK)
{
//do stuff
}
}
jak widać zamiast wywoływać bezpośrednio ShowDialog na obiekcie dialog stosujemy metodę STAShowDialog.
W moim przypadku musiałem zmodyfikować jeszcze tworzenie samego forma bazowego chcąc użyć go jako rodzica w argumencie metody ShowDialog – musi być stworzony jako STA.



![How to configure a test mail server with the Docker? – Cooking notes [EN]](https://rafalstepien.com/wp-content/uploads/2018/07/docker_tests-100x70.png)

