web-dev-qa-db-ja.com

C#プログラムのパネル内で別のアプリケーションを実行するにはどうすればよいですか?

私はC#プログラム内からアプリケーションをトリガーする方法(Process.Start())についてたくさん読んできましたが、この新しいアプリケーションをC#プログラムのパネル内で実行する方法についての情報を見つけることができませんでした。たとえば、外部ではなく、アプリケーション内でnotepad.exeを開くためにボタンをクリックしたいのですが。

67
Alex

これがまだ推奨されるものであるかどうかはわかりませんが、「オブジェクトのリンクと埋め込み」フレームワークを使用すると、特定のオブジェクト/コントロールをアプリケーションに直接埋め込むことができます。これはおそらく特定のアプリケーションでのみ機能しますが、メモ帳がそれらの1つであるかどうかはわかりません。メモ帳のような非常に単純なものの場合、使用しているメディア(WinFormsなど)によって提供されるテキストボックスコントロールを操作するだけで簡単に作業できるでしょう。

OLE開始するための情報へのリンク:

http://en.wikipedia.org/wiki/Object_Linking_and_Embedding

14
Andy White

Win32 APIを使用すると、別のアプリケーションを「食べる」ことができます。基本的に、そのアプリケーションの一番上のウィンドウを取得し、それを配置したいパネルのハンドルになるようにその親を設定します。MDIスタイル効果ウィンドウスタイルを調整して最大化し、タイトルバーを削除します。

ボタンとパネルを備えたフォームがある簡単なサンプルコードを次に示します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Process p = Process.Start("notepad.exe");
            Thread.Sleep(500); // Allow the process to open it's window
            SetParent(p.MainWindowHandle, panel1.Handle);
        }

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

スリープ状態ではなく、WaitForInputIdleを呼び出す別の例をみました。したがって、コードは次のようになります。

Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);

コードプロジェクトには、プロセス全体に関する良い記事があります。 WinFormプロジェクトでEXEアプリケーションをホストする

99
Luke Quinane
  • Answer .. **にソリューションを追加する

このコードは、Windowsフォームで実行可能ファイルをドッキングするのに役立ちました。 NotePad、Excel、Word、Acrobat Readerなど.

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

だから私はこれを解決するために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);
     }
4
Saurabh Raoot

WinFormコンテナを使用して外部アプリケーションを作成する別の興味深いソリューションは次のとおりです。

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


private void Form1_Load(object sender, EventArgs e)
{
    ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
    psi.WindowStyle = ProcessWindowStyle.Minimized;
    Process p = Process.Start(psi);
    Thread.Sleep(500);
    SetParent(p.MainWindowHandle, panel1.Handle);
    CenterToScreen();
    psi.WindowStyle = ProcessWindowStyle.Normal;
}

ProcessWindowStyle.NormalからProcessWindowStyle.Minimizedへのステップは、迷惑な遅延を取り除きます。

enter image description here

3
daniele3004

アプリ内でメモ帳を実行する場合は、おそらくテキストエディターコンポーネントを使用することをお勧めします。明らかに、WinFormsに付属する基本的なテキストボックスがありますが、メモ帳機能(またはそれ以上)を提供するより高度なコンポーネントがインターWebで見つかると思います。

1
Steve Haigh

他のアプリケーションがwin32ウィンドウハンドルに自分自身をアタッチできる場合、これが可能であることを知っています。たとえば、いずれかのウィンドウ内でDirectXアプリケーションをホストする別のC#アプリケーションがあります。私はこれがどのように実装されているかの正確な詳細に精通していませんが、他のアプリケーションにパネルのwin32 Handleを渡すだけで、そのアプリケーションがDirectXサーフェスをアタッチするには十分だと思います。

1
Anthony Brien

以前の回答では、これを達成するために古いWin32ユーザーライブラリ関数が使用されています。これはmostの場合には機能すると思いますが、時間が経つと信頼性が低下します。

今、これを行っていないので、それがどれだけうまくいくかを話すことはできませんが、現在のWindowsテクノロジーがより良い解決策であることを知っています: Desktop Windows Manager API

DWMは、タスクバーとタスクスイッチャーUIを使用してアプリのライブサムネイルプレビューを表示できるのと同じテクノロジーです。リモートターミナルサービスと密接に関連していると思います。

アプリをデスクトップウィンドウではない親ウィンドウの子にする場合に発生する可能性のある問題は、一部のアプリケーション開発者がデバイスコンテキスト(DC)、ポインター(マウス)の位置、画面の幅など。メインウィンドウに「埋め込まれた」ときに不安定または問題のある動作を引き起こす可能性があります。

DWMを使用して、アプリケーションのウィンドウを別のアプリケーションのコンテナウィンドウ内で確実に表示および操作するために必要な翻訳を管理できるようにすることで、これらの問題を大幅に解消できると思います。

ドキュメントはC++プログラミングを前提としていますが、オープンソースC#ラッパーライブラリであると主張するものを作成した人が1人見つかりました。 https://bytes.com/topic/c-sharp/answers/823547- desktop-window-manager-wrapper 。投稿は古く、ソースはGitHub、bitbucket、またはsourceforgeのような大きなリポジトリにはないため、どれだけ最新かはわかりません。

1