2009-04-16 10 views
58

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

答えて

12

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

はここで始めるためにOLE情報へのリンクです:

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

-1
短い答え:

短め回答:

他のアプリケーションが独自のアプリケーションに追加するためのコンポーネントを提供することで、それを許可するように設計されている場合のみ。

+2

@PaulSonier - 短い答えが完全に間違っていても? ;-)短い答えはYesです –

1

アプリ内でメモ帳を実行したい場合は、おそらくテキストエディタコンポーネントとの方が良いだろう。明らかに、WinFormsに付属の基本的なテキストボックスがありますが、私はメモ帳の機能(またはそれ以上)を提供するより高度なコンポーネントがインターウェブ上にあると思われます。

+0

メモ帳はテスト目的の単なる例でした! –

1

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

86

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); 

コードプロジェクトは、良い記事1、全体のプロセスがあります。Hosting EXE Applications in a WinForm project

+14

スーパーに役立ちます!リンクは関数のdllインポートを表示していないので、ここでそれらを共有していると思った。 [DllImport( "user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild、IntPtr hWndNewParent); [DllImport( "user32.dll")] 静的なextern int SetWindowLong(IntPtr hWnd、int nIndex、int dwNewLong); [DllImport( "user32.dll")] 静的extern bool MoveWindow(IntPtrハンドル、int x、int y、int w、int h、bool repaint); – hrh

+0

このコードはwpfでも実行されます –

+0

これをIEまたはChromeで使用すると、ブラウザの上部が黒く表示されます。これを透明に変更してメインウィンドウの色を表示する方法はありますか? – user21479

2
  • 回答でいくつかのソリューションを追加し.. **

これをコードはWindowsフォームで実行可能ファイルをドッキングするのに役立ちました。メモ帳、Excel、単語、Acrobat Readerなど多くのもの...

しかし、いくつかのアプリケーションではうまくいかないでしょう。場合によっては、いくつかのアプリケーションのプロセスを開始する....アイドル時間を待つ...とそのmainWindowHandleを取得しようとする....メインウィンドウハンドルがNULLになった時点までの.....

ので、私はのsytem上のすべての走っプロセスを検索し、その後...あなたが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); 
    } 
1

すべての以前の回答はこれを達成するために古いWin32ユーザーライブラリ関数を使用しています。私はこれがのほとんどの場合のケースで動作すると思いますが、時間の経過とともに信頼性が低下します。

これを実行していないと、うまくいくとは言えませんが、現在のWindowsテクノロジがより良い解決策であるかもしれません。Desktop Windows Manager API

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

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

DWMを使用して、アプリケーションのウィンドウを確実に表示し、別のアプリケーションのコンテナウィンドウ内で操作するために必要な変換を支援することで、これらの問題を大幅に排除できます。

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

1

別の興味深い解決策は、以下である:

[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.MinimizedにステップProcessWindowStyle.Normalから迷惑な遅延を除去します。

enter image description here

関連する問題