Wie kann ich eine andere Anwendung in einem Bereich meines C # -Programms ausführen?

73

Ich habe viel darüber gelesen, wie eine Anwendung in einem C # -Programm (Process.Start ()) ausgelöst wird, aber ich konnte keine Informationen darüber finden, wie diese neue Anwendung in einem Bereich meines C # -Programms ausgeführt werden kann . Zum Beispiel möchte ich einen Klick auf eine Schaltfläche, um eine notepad.exe INNERHALB meiner Anwendung zu öffnen, nicht extern.

Alex
quelle

Antworten:

17

Ich weiß nicht, ob dies immer noch empfohlen wird, aber mit dem Framework "Objektverknüpfung und -einbettung" können Sie bestimmte Objekte / Steuerelemente direkt in Ihre Anwendung einbetten. Dies wird wahrscheinlich nur für bestimmte Anwendungen funktionieren. Ich bin mir nicht sicher, ob Notepad eine davon ist. Für wirklich einfache Dinge wie den Editor fällt es Ihnen wahrscheinlich leichter, nur mit den Textfeldsteuerelementen zu arbeiten, die von dem von Ihnen verwendeten Medium (z. B. WinForms) bereitgestellt werden.

Hier ist ein Link zu OLE-Informationen, um loszulegen:

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

Andy White
quelle
106

Mit der win32-API ist es möglich, eine andere Anwendung zu "essen". Grundsätzlich erhalten Sie das oberste Fenster für diese Anwendung und legen fest, dass das übergeordnete Fenster das Handle des Bedienfelds ist, in dem Sie es platzieren möchten. Wenn Sie den MDI-Stileffekt nicht möchten, müssen Sie auch den Fensterstil anpassen, um ihn zu maximieren und zu maximieren Entfernen Sie die Titelleiste.

Hier ist ein einfacher Beispielcode, in dem ich ein Formular mit einer Schaltfläche und einem Bedienfeld habe:

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

Ich habe gerade ein anderes Beispiel gesehen, in dem WaitForInputIdle aufgerufen wurde, anstatt zu schlafen. Der Code würde also so aussehen:

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

Das Code-Projekt enthält einen guten Artikel über den gesamten Prozess: Hosten von EXE-Anwendungen in einem WinForm-Projekt

Luke Quinane
quelle
17
Super hilfreich! Der Link zeigte die DLL-Importe für ihre Funktionen nicht an, daher dachte ich, ich würde sie hier teilen. [DllImport ("user32.dll")] statisch extern IntPtr SetParent (IntPtr hWndChild, IntPtr hWndNewParent); [DllImport ("user32.dll")] statisch extern int SetWindowLong (IntPtr hWnd, int nIndex, int dwNewLong); [DllImport ("user32.dll")] statisches externes Bool MoveWindow (IntPtr-Handle, int x, int y, int w, int h, bool repaint);
Stunde
Wenn ich dies mit IE oder Chrome verwende, wird der obere Teil des Browsers schwarz angezeigt. Gibt es eine Möglichkeit, dies in transparent zu ändern, damit die Farbe meines Hauptfensters angezeigt wird?
user21479
Die referenzierte Artikel- / Code-Wohnung funktioniert bei mir nicht (möglicherweise, weil ich WPF verwende?). Muss verwendet werden: stackoverflow.com/questions/5836176/… . Auch für Pinvoke-Importe ist pinvoke.net immer nützlich.
dudeNumber4
1
Ja, erfahrene Windows-Programmierer verwenden WaitForInputIdle. Windows-Programmierer sollten sich Code, der Sleep verwendet, immer zweimal oder öfter ansehen.
user34660
Wenn Sie das Fenster maximieren möchten: [DllImport ("user32.dll")] privates statisches externes Bool ShowWindowAsync (IntPtr hWnd, int nCmdShow); social.msdn.microsoft.com/Forums/vstudio/en-US/…
camino
6
  • Hinzufügen einer Lösung in Antwort .. **

Dieser Code hat mir geholfen, einige ausführbare Dateien in Windows-Form anzudocken. wie NotePad, Excel, Word, Acrobat Reader n viele mehr ...

Bei einigen Anwendungen funktioniert dies jedoch nicht. Wie manchmal, wenn Sie den Prozess einer Anwendung starten ... warten Sie auf die Leerlaufzeit ... und versuchen Sie, das mainWindowHandle abzurufen ... bis das Handle des Hauptfensters null wird .....

Also habe ich einen Trick gemacht, um das zu lösen

Wenn Sie das Hauptfenster-Handle als null erhalten ... dann durchsuchen Sie alle laufenden Prozesse auf dem System und finden Sie Ihren Prozess ... dann erhalten Sie die Haupt-Hadle des Prozesses und das Set-Panel als übergeordnetes Element.

        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);
     }
Saurabh Raoot
quelle
5

Eine weitere interessante Lösung für eine externe Anwendung mit einem WinForm-Container ist die folgende:

[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;
}

Der Schritt ProcessWindowStyle.Minimizedvon ProcessWindowStyle.Normal entfernt die störende Verzögerung.

Geben Sie hier die Bildbeschreibung ein

daniele3004
quelle
Schlafen Sie nicht, um auf Ereignisse zu warten, die nicht in der garantierten erwarteten Zeit auf einer Echtzeitplattform ausgeführt werden
Lodewijk
2

Ich stelle fest, dass alle vorherigen Antworten ältere Funktionen der Win32-Benutzerbibliothek verwenden, um dies zu erreichen. Ich denke, dass dies in den meisten Fällen funktionieren wird, aber im Laufe der Zeit weniger zuverlässig.

Nachdem ich dies nicht getan habe, kann ich Ihnen nicht sagen, wie gut es funktionieren wird, aber ich weiß, dass eine aktuelle Windows-Technologie eine bessere Lösung sein könnte: die Desktop Windows Manager-API .

DWM ist dieselbe Technologie, mit der Sie mithilfe der Taskleiste und der Task-Switcher-Benutzeroberfläche eine Live-Vorschau von Apps anzeigen können. Ich glaube, es hängt eng mit den Diensten des Remote-Terminals zusammen.

Ich denke, dass ein wahrscheinliches Problem, das auftreten kann, wenn Sie eine App dazu zwingen, ein untergeordnetes Element eines übergeordneten Fensters zu sein, das nicht das Desktop-Fenster ist, darin besteht, dass einige Anwendungsentwickler Annahmen über den Gerätekontext (DC), die Zeigerposition (Maus) treffen. Bildschirmbreiten usw., die zu unregelmäßigem oder problematischem Verhalten führen können, wenn sie in das Hauptfenster "eingebettet" werden.

Ich vermute, dass Sie diese Probleme weitgehend beseitigen können, indem Sie sich auf DWM verlassen, um die Übersetzungen zu verwalten, die erforderlich sind, damit die Fenster einer Anwendung zuverlässig im Containerfenster einer anderen Anwendung dargestellt und mit ihnen interagiert werden.

Die Dokumentation geht von C ++ - Programmierung aus, aber ich habe eine Person gefunden, die eine Open-Source-C # -Wrapper-Bibliothek erstellt hat: https://bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper . Der Beitrag ist alt und die Quelle befindet sich nicht in einem großen Repository wie GitHub, Bitbucket oder Sourceforge. Daher weiß ich nicht, wie aktuell sie ist.

Alan McBee - MSFT
quelle
1

Wenn Sie den Editor in Ihrer App ausführen möchten, ist eine Texteditor-Komponente wahrscheinlich besser geeignet. Es gibt natürlich ein grundlegendes Textfeld, das mit WinForms geliefert wird, aber ich vermute, dass im Internet erweiterte Komponenten mit Notepad-Funktionalität (oder besser) zu finden sind.

Steve
quelle
Notepad war nur ein Beispiel für Testzwecke!
Fernando Vieira
1

Ich weiß, dass dies möglich ist, wenn sich die andere Anwendung an ein Win32-Fensterhandle anhängen kann. Zum Beispiel haben wir eine separate C # -Anwendung, die eine DirectX-Anwendung in einem ihrer Fenster hostet. Ich bin nicht mit den genauen Details der Implementierung vertraut, aber ich denke, Handledass es ausreicht , nur die win32 Ihres Panels an die andere Anwendung zu übergeben, damit diese Anwendung ihre DirectX-Oberfläche anbringt.

Anthony Brien
quelle
-1
Kurze Antwort:

Nein

Kurze Antwort:

Nur wenn die andere Anwendung dies zulässt, indem Sie Komponenten bereitstellen, die Sie zu Ihrer eigenen Anwendung hinzufügen können.

Samuel
quelle
3
@PaulSonier - auch wenn die kurze Antwort völlig falsch ist? ;-) Die kurze Antwort ist Ja
Chris Rogers
In der realen Welt müssen wir oft etwas anpassen, das nicht dafür gemacht wurde.
Vinicius Gonçalves