35024
タイトルの方法を実現する方法として、  
メニューをexeにして、各アプリをDLLにしてメニューから呼び出すという方法が  
一つ思い浮かびますが、この場合各アプリ画面でモーダル表示のダイアログ画面を表示している間、  
メニュー画面にフォーカスを戻せなくなる問題があると認識しています。

この問題を解決したい場合はやはりメニューのexeと各アプリのexeを分けるしか  
方法はないでしょうか？

何かこの問題を回避する方法がありましたらご教示頂ければ幸いです。
CC BY-SA 3.0
2017-05-26T00:11:05.997
35019
2017-05-26T06:58:33.810
2017-05-26T04:04:16.813
9228
9228
question
c# winforms
C# Windows Formでメニューのexeと起動するアプリのexeを分けずにメニューからアプリを起動する方法が知りたいです。
`Program.cs`の`Main()`メソッドには

```

    Application.Run(new Form1());
    
```

のように記述されていると思います。[`Application.Run(Form)`](https://msdn.microsoft.com/ja-
jp/library/ms157902\(v=vs.110\).aspx)は引数に渡された`Form`を表示し、その`Form`が閉じられた時点で終了します。この`Application`単位でモーダルダイアログが実現されています。  
ところでこの`Application`はプロセス単位ではなくスレッド単位の概念です。ですので、異なるスレッドで起動すれば相互に影響することはありません。

メニュー画面から各アプリ画面を開く際、

```

    var thread2 = new Thread(() => Application.Run(new Form2()));
    thread2.SetApartmentState(ApartmentState.STA);
    thread2.Start();
    
```

と新たなスレッド上で実行開始してあげれば、メニュー画面はアプリ画面のモーダルの影響をうけなくなります。もちろん、この例での`Form2`が閉じられた時点で`thread2`は終了します。

* * *

### `Application.Exit()`について

pgrhoさんが言及されていたので加筆します。[`Application.Exit()`](https://msdn.microsoft.com/ja-
jp/library/ms157894\(v=vs.100\).aspx)は

> Exit メソッドは全スレッドで実行中のメッセージ ループをすべて停止し、アプリケーションのウィンドウをすべて閉じます。  
>  現在のスレッドだけのメッセージ ループを終了するには、ExitThread を呼び出します。

と説明されているように全スレッドのメッセージループを停止させるメソッドですから仕様通りの動作をします。また現在のスレッドだけを終了させるためには[`Application.ExitThread()`](https://msdn.microsoft.com/ja-
jp/library/system.windows.forms.application.exitthread\(v=vs.100\).aspx)を使用すべきとも案内されています。  
次善策として`AppDomain`を分離することを提案されていますが、それでもプロセスを終了させる`Enviroment.Exit()`に対しては無力ですし、質問文にあるようにプロセスを分離したとしても`ExitWindowEx()`でPCを止められることもあり得ます。

結局、どこまでを許容するかの話でしかないと思います。
CC BY-SA 3.0
2017-05-26T01:53:39.860
35024
2017-05-26T06:58:33.810
2017-05-26T06:58:33.810
4236
4236
35019
answer
`System.Windows.Form.Application`はスレッドセーフということになっていますが、`Application.OpenForms`などの一部フィールドが全スレッド共有のため、全フォームに対する処理が行われると想定外の動作をする場合があります。たとえば`Application.Exit()`はスレッドに関係なくすべてのフォームを閉じようとします。

ですので少なくとも`AppDomain`は分離した方が良いです。user.configを共用にしたいなどの理由がなければ別プロセスで実行するのが簡単です。ちなみにapp.configについては起動直後に`AppDomain.CurrentDomain.SetData("APP_CONFIG_PATH",
path)`を呼び出すことで参照先を変更することが出来ます。
CC BY-SA 3.0
2017-05-26T03:22:21.480
35027
2017-05-26T03:22:21.480
5750
35019
answer