17

私はwinformアプリケーション(.NET 2.0 C#)を持っています。このアプリケーションから、別のプロセス(別のwinformアプリケーション)を開始して、ウィンドウにドッキングします(または、少なくともドッキングされているように見せます)。これまでのところ、ドッキングコントロールに関する情報のみを見つけることができ、個別のプロセスのウィンドウは見つけることができません。私の最初の考えは、ウィンドウのハンドルを取得し、管理されていないシステムコールを使用して、ウィンドウの高さ/幅と位置をドッキング領域に設定することです。しかし、始める前に、私はあなたの良い人の誰かが同じようなことをしたかどうかを確認したかったのです。ドッキングしたいアプリケーションのソースコードにアクセスできますが、回避できる場合は変更を加えたくありません。親アプリケーションとなるものを完全にプログラミング制御できます。何かアドバイス?前もって感謝します!

4

3 に答える 3

32

私が以前に使用した解決策は、アプリケーションウィンドウをドッキングするコントロールの子として設定することです。

using System.Diagnostics;
using System.Runtime.InteropServices;

private Process pDocked;
private IntPtr hWndOriginalParent;
private IntPtr hWndDocked;

[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

private void dockIt()
{
    if (hWndDocked != IntPtr.Zero) //don't do anything if there's already a window docked.
        return;
    hWndParent = IntPtr.Zero;

    pDocked = Process.Start(@"notepad");
    while (hWndDocked == IntPtr.Zero)
    {
        pDocked.WaitForInputIdle(1000); //wait for the window to be ready for input;
        pDocked.Refresh();              //update process info
        if (pDocked.HasExited)
        {
            return; //abort if the process finished before we got a handle.
        }
        hWndDocked = pDocked.MainWindowHandle;  //cache the window handle
    }
    //Windows API call to change the parent of the target window.
    //It returns the hWnd of the window's parent prior to this call.
    hWndOriginalParent = SetParent(hWndDocked, Panel1.Handle);

    //Wire up the event to keep the window sized to match the control
    Panel1.SizeChanged += new EventHandler(Panel1_Resize);
    //Perform an initial call to set the size.
    Panel1_Resize(new Object(), new EventArgs());
}

private void undockIt()
{
    //Restores the application to it's original parent.
    SetParent(hWndDocked, hWndOriginalParent);
}

private void Panel1_Resize(object sender, EventArgs e)
{
    //Change the docked windows size to match its parent's size. 
    MoveWindow(hWndDocked, 0, 0, Panel1.Width, Panel1.Height, true);
}
于 2011-05-11T14:34:28.003 に答える
5

* 回答に解決策を追加.. * *

このコードは、一部の実行可能ファイルを Windows 形式でドッキングするのに役立ちました。メモ帳、エクセル、ワード、アクロバットリーダー、その他多数...

ただし、一部のアプリケーションでは機能しません。時々、アプリケーションのプロセスを開始するとき....アイドル時間を待ちます...そしてそのmainWindowHandleを取得しようとします....メインウィンドウハンドルがnullになるまで.....

だから私はこれを解決するために1つのトリックをしました

メイン ウィンドウ ハンドルを null として取得した場合は、システムで実行中のすべてのプロセスを検索し、プロセスを見つけます。次に、プロセスのメイン ハンドルとセット パネルをその親として取得します。

            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = "xxxxxxxxxxxx.exe";
            info.Arguments = "yyyyyyyyyy";
            info.UseShellExecute = true;
            info.CreateNoWindow = true;
            info.WindowStyle = ProcessWindowStyle.Maximized;
            info.RedirectStandardInput = false;
            info.RedirectStandardOutput = false;
            info.RedirectStandardError = false;

            System.Diagnostics.Process p = System.Diagnostics.Process.Start(info); 

            p.WaitForInputIdle();
            Thread.Sleep(3000);

            Process[] p1 ;
        if(p.MainWindowHandle == null)
        {
            List<String> arrString = new List<String>();
            foreach (Process p1 in Process.GetProcesses())
            {
                // Console.WriteLine(p1.MainWindowHandle);
                arrString.Add(Convert.ToString(p1.ProcessName));
            }
            p1 = Process.GetProcessesByName("xxxxxxxxxxxx");
            //p.WaitForInputIdle();
            Thread.Sleep(5000);
           SetParent(p1[0].MainWindowHandle, this.panel2.Handle);
        }
         else
        {
           SetParent(p.MainWindowHandle, this.panel2.Handle);
        }
于 2013-06-28T14:07:50.103 に答える
0

これは私が望んでいたよりもはるかに不格好ですが、これまでのところ機能しています。システムコールを使用して、ドッキング領域を反映する場所に子ウィンドウを強制します。まだ完全には機能していません。によって引き起こされるいくつかの奇妙な点がHWND_TOPMOSTありますが、ユーザーが子ウィンドウを直接移動できないようにするロジックを追加する必要があります。

    //This is my docking window
    private System.Diagnostics.Process notepad;
    private void windowDockTest()
    {
        /*
         * Docking notepad to panel2 of the splitcontainer
         */

        //if panel2 moves or is resized, call the docking function
        spcScript.Panel2.Move += new EventHandler(Panel2_Resize);
        spcScript.Panel2.SizeChanged += new EventHandler(Panel2_Resize);

        //Call the docking function if main form is moved
        this.LocationChanged += new EventHandler(Panel2_Resize);

        //Start the notepad process
        notepad = new System.Diagnostics.Process();
        notepad.StartInfo.FileName = "notepad";
        notepad.Start();

        //Wait a second for notpad to fully load
        notepad.WaitForInputIdle(1000);

        //Dock it
        Panel2_Resize(new Object(), new EventArgs());
    }

    void Panel2_Resize(object sender, EventArgs e)
    {
        //Get the screen location of panel2
        Rectangle r = spcScript.Panel2.RectangleToScreen(spcScript.Panel2.ClientRectangle);

        //Dock it
        redock(notepad.MainWindowHandle, r.X, r.Y, r.Width, r.Height);
    }

    [DllImport("user32.dll")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
    public static void redock(IntPtr handle, int x, int y, int width, int height)
    {
        IntPtr HWND_TOPMOST = new IntPtr(-1);
        const short SWP_NOACTIVATE = 0x0010;

        SetWindowPos(handle,HWND_TOPMOST, x, y, width, height,SWP_NOACTIVATE);
    }
于 2011-04-30T01:35:58.693 に答える