Laden...

Externe Exe einbinden

Erstellt von wiesi vor 16 Jahren Letzter Beitrag vor 13 Jahren 10.888 Views
wiesi Themenstarter:in
89 Beiträge seit 2005
vor 16 Jahren
Externe Exe einbinden

Hi,

ich würde gerne eine externe Exe (z.B. Notepad) in meine Applikation einbinden, die
Darstellung aber innerhalb meiner Applikation machen. Geht das?

Grüße,
wiesi

D
5 Beiträge seit 2007
vor 16 Jahren

soweit ich dass weis geht das nicht.
Ist auch besser so. Sonst könnte jeder deine tolle Anwendung in seine eigene implementieren und dann sagen er hat ne bessere!!

p.s.:Notepad ist nich soooo kompliziert dass man dass nich selber schreiben könnte!

mfg
darkdevil

2.921 Beiträge seit 2005
vor 16 Jahren

Je nach Anwendung ginge das schon... wäre sogar ein interessantes Projekt.

Aber @DarkDevil wie Du sagst, genau das wäre das Problem.

s. dazu auch alle Texte bezgl. Plugin...

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

D
5 Beiträge seit 2007
vor 16 Jahren

plugin: ja man kann etwas einbinden... jedoch nur die Funktionen (welche man wissen muss)
aber das GUI kann man (glaub ich) nicht einbinden...

3.971 Beiträge seit 2006
vor 16 Jahren

Ich denke schon. Es lässt sich doch mittels Windows API alle Controls einer Anwendungung zurück geben. Diese müssten dann nur in .NET Controls gewrappt werden. bzw. mit den selben Windows APIs diese in meine Form kopieren.

Es ist ja möglich, mit Global Hooks oder wie das heißt, auch auf die GUI-Funktionianlitäten anderer Programme zuzugreifen.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

D
5 Beiträge seit 2007
vor 16 Jahren

dann schreibe ich ab jetzt keine Programme mehr selber sondern binde sie nur ein gg....
Ich finde das nicht in Ordnung dass das so ohne weiteres möglich ist...

2.921 Beiträge seit 2005
vor 16 Jahren

Keine Sorge Leute, es ist möglich. Je nach Anwendung, nur ob das so sinnvoll ist...

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

3.971 Beiträge seit 2006
vor 16 Jahren

Original von darkdevil
dann schreibe ich ab jetzt keine Programme mehr selber sondern binde sie nur ein gg....
Ich finde das nicht in Ordnung dass das so ohne weiteres möglich ist...

Ich denke wenn du dir den Aufwand anguckst, nur um zum Beispiel Notepad.exe zu verwenden in deinem Programm, schreibst du in der selben Zeit die du dafür brauchst 5 mal komplett Notepad. Deswege sehe ich das nich so😉 😁

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

D
5 Beiträge seit 2007
vor 16 Jahren

ok....überredet

p.s.:notepad ist ein schlechtes beispiel denn es gibt mittlerweile auch schon etwas kompliziertere anwendungen

2.921 Beiträge seit 2005
vor 16 Jahren

@kleines_eichhörnchen: SetParent APi-benutzen und dann weitersehen. gg

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

871 Beiträge seit 2005
vor 16 Jahren

Hallo,

wie schon dr4g0n76 sagte gehts mit der SetParent Funktion. Anschliessend noch mit SetWindowLong den Fensterrahmen entfernen und gut is.

Es gibt bestimmte Anwendungsfälle bei denen man das wirklich brauchen kann. Als beispiel fällt mir jetzt ein wenn man ein SDL Window (SDLlibrary) mit einer Windows Menüleiste versehen will (da SDL nur simple Fenster erzeugen kann ohne irgendwelchen Schnick-Schnack)

Grüsse,
Egon

2.921 Beiträge seit 2005
vor 16 Jahren

Genau Egrath. Wenn man aber nur sehen, will dass eine exe darin läuft, dann reicht das hier:


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

namespace IntegrateNotepad
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        public Form1()
        {
            InitializeComponent();          
        }

        private void notepadHostenToolStripMenuItem_Click(object sender, EventArgs e)
        {

            //Process proc = Process.Start("notepad.exe");
            //IntPtr ptrNotepad = proc.MainWindowHandle;

            IntPtr ptrNotepad = IntPtr.Zero;
            if (ptrNotepad == IntPtr.Zero)
            {
                ptrNotepad = FindWindow(null, "Unbenannt - Editor");
            }

            Control mdiClientControl = null;
            foreach (Control control in this.Controls)
            {
                if (control is MdiClient)
                {
                    mdiClientControl = (MdiClient)control;
                    break;
                }
            }

            for (int i = 0; i < 10; i++)
            {
                IntPtr ptr = SetParent(ptrNotepad, mdiClientControl.Handle);

                if (ptr == IntPtr.Zero)
                {
                    this.Text = "Tja, hat leider nicht funktioniert!";
                }
            }
        }     
    }
}

EDIT: Das ist natürlich kein 100% korrektes Beispiel. Eigentlich sollten Anwendungen ja auch nicht so vergewaltigt werden. 😉

EDIT: So jetzt kann jederzeit probiert werden. Dazu notepad starten und dann
notepadHostenToolStripMenuItem_Click ausführen. 🙂

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

103 Beiträge seit 2006
vor 16 Jahren

Also bei mir kommt immer nur:
Tja, das hat leider nicht funktioniert. Aber auch erst seit dem ich die Zeile:

this.IsMdiContainer = true;

eingefügt habe.

Wie muss der Designer Entwurf dazu aussehen?

Muss man Process.Start verwenden um Notepad zu starten? Oder löst dieses Process.start immer einen externen aufruf auf. Kann man notepad intern aufrufen? also in einem Tab oder so?

915 Beiträge seit 2006
vor 16 Jahren

Du wirst imemr Process.Start dafür verwenden müssen wo das dann aufrufst ist egal. Dann müsstest via FindWindow / FindWindowEx oder GetActiveWindow das Handle dazu suchen müssen. Ob es dann auf einen TabControl oder einer Form darstellst ist egal du kannst mit SetParent das Handle vom Notepad auf ein X beliebiges Control setzen.

Das dumme an der Sache ist nur die Komunikation, denn die Notepad Anwendung läuft in einen anderen Prozess und anderen Thread. Du müsstest einen Hook schreiben um die WindowsNachrichten vom Notepad zu empfangen und via SendMessage an Notepad Nachrichten versenden um eine Komunikation hinzubekommen. Und müsstest beim beenden deines Programms vorher darauf achten das auch Notepad sich beendet - wüsste nicht was passiert wenn das nicht tust - glaube deine Anwendung würde dennoch weiterlaufen.

Achja, und man muss natürlich beachten das wenn dir wie gesagt das Handle von Notepad holst es zu dem Zeitpunkt ausgeschlossen ist, dass genau zeitgleich jemand manuell Notepad startet.

Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(

103 Beiträge seit 2006
vor 16 Jahren

Irgendwie komisch. Im Debug Modus, wenn ich einen Haltepunkt setze und dann im einzelschritt weiter gehe. kommt das das notepad fenster erst nach aussen und wird dann in meine anwendung reingezogen.

Lasse ich es schnell durchlaufen, bleibt es extern...

wenn ich jetzt eine andere anwendung starten will, wie finde ich dann den handle von dem prozess, wenn die anwendung öfters aufgerufen werden soll mit verschiedenen kommandozeilenargumenten?

funktioniert das nur über den WindowName?

ptrNotepad = FindWindow(null, "Unbenannt - Editor");

???

915 Beiträge seit 2006
vor 16 Jahren

Du hast folgende Problematik: Woher weist du welches Notepadfenster das von dir mit Process.Start erstellte ist?

Es gibt jetzt viele Ansätze ich nenne erstmal nur einen:

Wenn man über Start->CMD notepad lala eingibt startet Notepad mit dem Fenstertitel "lala - Editor". So jetzt läge es ja nahe zu sagen okay ich nehme einen eindeutigen Fenstertitel auf den kein Benutzer der Wellt kommen würde und weis daher über FindWindow(null, "lala - Editor"); das es nur mein Editorfenster sein kann. Dazu kommt nun folgendes Problem: Weshalb es auch bei dir nicht geklappt hat (wenn du es schnell durchlaufen hast). Die geschwindigkeit bis zum Start der Anwendung Notepad. Um dieses Problem zu umgehen startest einen Thread nachdem Process.Start("notepad lala") ausgelöst hast. In diesem Thread wird eine DoNothing Schleife (also while(true)) abgearbeitet und es wird versucht über FindWindow(null, "lala - Editor") != IntPtr.Zero abgefragt, wenn der Fall true wird, so kannst nen Break machen da dein Fensterhandle gefunden wird. Natürlich solltest das ganze auch mit nen Abbruchkreterium versehen z.B nach 10 Sekunden kein Fensterhandle gefunden -> Fehler ist aufgetreten.

/PS
Über FindWindow solltest das ganze nicht unbedingt machen, habe es aber mal im beispiel so belassen. FindWindowEx wäre da noch etwas besser da hier den Class Name "Notepad" zusätzlich mit angeben kannst (also noch ein kriterium mehr damit du weist das es auch wirklich das richtige Fenster ist)

Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(

R
1 Beiträge seit 2011
vor 13 Jahren

auch wenn es schon älter ist, hier noch ein paar Tips:

  1. wenn man den Process selber startet bekommt man das WindowHandle / den Ptr über Process.MainWindowHandle. Dieser ist u.U zunächst null bzw. IntPtr.Zero, da die Gui erst erstellt wird, hier per Zeitschleife warten (z.B. Thread.sleep(1000)).

  2. Manche Processe erstellen kein WindowHandle (MainWindowHandle) wenn sie iconified starten (z.B. der OfficeCommunicator). Win-Api findet diese über FindWindow totzdem. Caption (Titel) ist natürlich nicht immer eine gute Wahl, da sich dieser ändern kann (Lokalisierung oder dynamischer Titel). FindWindow bietet aber auch an, den Klassennamen anzugeben, somit kann man nach den einzelnen oder den kombinierten Infos suchen. (Klassennamen bekommt man z.B. mit dem Ms Tool Spy++ (spyxx.exe) aus dem VisualStudio Verzeichnis: FindWindow->Properties->Class->Class Name ; oder einem anderen win spy tool)

  3. Wenn man den Prozess gestartet hat oder über GetProcesses(...) gefunden hat, kann man sich über dessen Exit informieren lassen und entsprechend darauf reagieren, bzw. diesen auch selbst beenden. (Es bleibt aber das TaskIcon Problem im Infobereich)

  4. einige UI Probleme lassen sich vermeiden, wenn vor dem SetParent der Fokus auf das zu kapernde Fenster gesetzt wird

  5. neue Styles (z.B. keine Menüleiste, etc.) setzt man mit SetWindowLong bzw. SetWindowLongPtr. Achtung: Änderungen werden erst durch Nutzung von SetWindowPos aktiviert!

Hoffe das hilft 😉

Gruß
Ralf