別アプリをMDIの子フォームとして表示

時々、別アプリをMDIの子フォームとして表示したいなんて話がありますけれど(´Д`)
.NETだけに閉じた世界なら参照設定して使いなさいよだとか正論はあるわけですが、まあ、それは置いておいて、非.NETのアプリをどうしてもMDIの子フォームにしたい時のやりかたとかそんなの。


この辺にも書いてありますけれど(・∀・)
Hosting another process in your GUI
http://geekswithblogs.net/gyoung/archive/2006/04/26/76521.aspx


ソースも載せておくとこんなん。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MdiHosting
{
    public static class MdiUtil
    {
        [DllImport( "user32.dll", SetLastError = true )]
        private static extern uint SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        public static void LoadProcessInControl(string filename, Control ctrl)
        {
            Process p = Process.Start( filename );
            p.WaitForInputIdle();
            SetParent( p.MainWindowHandle, ctrl.Handle );
        }

        public static MdiClient GetMdiClient(Form form)
        {
            foreach( Control c in form.Controls )
            {
                if( c is MdiClient )
                {
                    return (MdiClient)c;
                }
            }

            return null;
        }
    }
}

// 使う側
MdiUtil.LoadProcessInControl( "calc.exe", MdiUtil.GetMdiClient( this ) );

要するにSetParent()を使って無理矢理親子関係を設定してあげるわけで。
『親ウィンドウと子ウィンドウは、同一アプリケーションに属していなければなりません』と書かれていようが気にせずに(・3・)


まあ、これだけできても実用上はもうちょい解決しないといけない問題もありますしね(´Д`)
起動直後に一瞬表示されるウィンドウをどうしようかとか、位置の制御をどうしようかだとか。
あと、実行するアプリがVB 6製の場合、Process.MainWindowHandleがThunderRT6Mainの方のハンドルを返してくるので、FindWindow()でもするる(´ω`)