C# プログラム (Process.Start()) 内からアプリケーションをトリガーする方法についてたくさん読んできましたが、この新しいアプリケーションを C# プログラムのパネル内で実行する方法に関する情報を見つけることができませんでした。 . たとえば、ボタンをクリックして、外部ではなく、アプリケーション内で notepad.exe を開きたいと思います。
8 に答える
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);
Code Project には、プロセス全体の優れた記事があります: Hosting EXE Applications in a WinForm project
これがまだ推奨されているかどうかはわかりませんが、「オブジェクトのリンクと埋め込み」フレームワークを使用すると、特定のオブジェクト/コントロールをアプリケーションに直接埋め込むことができます。これはおそらく特定のアプリケーションでのみ機能しますが、メモ帳がその1つであるかどうかはわかりません. メモ帳のような非常に単純なものの場合は、使用しているメディア (WinForms など) が提供するテキスト ボックス コントロールを使用するだけで作業が簡単になるでしょう。
開始するための OLE 情報へのリンクは次のとおりです。
- Answer..**にいくつかのソリューションを追加する
このコードは、一部の実行可能ファイルを 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);
}
以前の回答はすべて、これを達成するために古い Win32 ユーザー ライブラリ関数を使用していることに気付きました。これはほとんどの場合うまくいくと思いますが、時間の経過とともに確実に機能しなくなります。
これを行っていないので、どれだけうまく機能するかはわかりませんが、現在の 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 のような大きなリポジトリにないため、最新かどうかはわかりません。
他のアプリケーションが自分自身を win32 ウィンドウ ハンドルにアタッチできる場合、これが可能であることはわかっています。たとえば、あるウィンドウ内で DirectX アプリケーションをホストする別の C# アプリケーションがあるとします。これがどのように実装されているかの正確な詳細はよくわかりませんが、パネルの win32Handle
を他のアプリケーションに渡すだけで、そのアプリケーションが DirectX サーフェスをアタッチするのに十分だと思います。
アプリ内でメモ帳を実行したい場合は、おそらくテキスト エディター コンポーネントを使用した方がよいでしょう。WinForms には基本的なテキスト ボックスが付属していることは明らかですが、メモ帳機能 (またはそれ以上) を提供するより高度なコンポーネントがインターウェブで見つかると思います。
いいえ
短い答え:自分のアプリケーションに追加するコンポーネントを提供することにより、他のアプリケーションがそれを許可するように設計されている場合のみ。