質問: お世話になります。 以前、と規定のフォームの前面にProcess.Startで起動したプログラムが立ち上がるように したいという質問をしたのですが(C# 外部プログラムを起動させた際に、特定のフォームよりも前面に表示する方法)、その方法について、少し問題があったので、今回、 メインのフォームの中に、MDIのように外部プログラムを起動させられればと思い、 新たに質問しました。 前回教えていただいた方法で、指定のフォームの前面にGoogleChromeを立ち上げたときですが、 常に前面にするように指定したはずが、メインのフォームをアクティブにすると、背面に隠れて しまいました。 原因を調べてみると、このメインのフォームを起動する前に、通常の方法でChromeを一つ 立ち上げた後、今回のプログラムを開き、二つ目のChromeをProcess.Startで 立ち上げたところ、常に前面に表示されるという設定が効いていませんでした。 ほかにChromeが開いていないときならば、 このフォームから立ち上げたChromeは前面に来るのですが、どうやら多重起動するプログラムは 既に立ち上がっている場合は設定の変更ができないようです。 また、WordやExcelなどはそもそもこの設定ができずに、呼び出したメインウインドウが アクティブになると、その背面に隠れてしまいます。 前置きが長くなりましたが、こういったことがあったため、MDIなどにすれば、間違いなく メインフォームの中に表示されるだろうと考えました。 フォームの中にフォームを表示するのは、フォームのTopLevelをfalseにすれば簡単に できますが、同じような結果になるようにProcess.Startで起動するプログラムを メインフォームの子供フォームのように入れることはできますでしょうか。 ご教授お願いいたします。 ![こんな例外が出ています](https://i.stack.imgur.com/RCP8F.jpg)
回答: `SetParent`関数を使用するとウィンドウの親ウィンドウを変更することができます。 ``` [DllImport("user32.dll", SetLastError = true)] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll", SetLastError = true)] static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); const int ASYNCWINDOWPOS = 0x4000; var f = new Form(); f.IsMdiContainer = true; f.Shown += (_, __) => { var p = Process.Start("notepad"); p.WaitForInputIdle(); // 親ウィンドウを設定 SetParent(p.MainWindowHandle, f.Handle); // ウィンドウを移動 SetWindowPos(p.MainWindowHandle, IntPtr.Zero, 0, 0, 100, 100, ASYNCWINDOWPOS); }; f.Show(); ``` ただしMSDNにも明記されている通り、他プロセスのウィンドウと親子関係を設定するのは保証外の動作になります。