web-dev-qa-db-fra.com

Comment puis-je exécuter une autre application dans un panneau de mon programme C #?

J'ai lu beaucoup de choses sur la façon de déclencher une application à partir d'un programme C # (Process.Start ()), mais je n'ai pas pu trouver d'informations sur la façon d'exécuter cette nouvelle application dans un panneau de mon programme C # . Par exemple, j'aimerais qu'un bouton clique pour ouvrir un notepad.exe DANS mon application, pas en externe.

67
Alex

Je ne sais pas si c'est toujours la chose recommandée à utiliser mais le framework "Object Linking and Embedding" vous permet d'incorporer certains objets/contrôles directement dans votre application. Cela ne fonctionnera probablement que pour certaines applications, je ne sais pas si le Bloc-notes en fait partie. Pour des choses très simples comme le bloc-notes, vous aurez probablement plus de facilité à travailler avec les contrôles de zone de texte fournis par le support que vous utilisez (par exemple WinForms).

Voici un lien vers OLE info pour commencer:

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

14
Andy White

En utilisant l'API win32, il est possible de "manger" une autre application. Fondamentalement, vous obtenez la fenêtre supérieure de cette application et définissez son parent comme la poignée du panneau dans lequel vous souhaitez le placer. Si vous ne voulez pas l'effet de style MDI, vous devez également ajustez le style de la fenêtre pour l'agrandir et supprimez la barre de titre.

Voici un exemple de code simple où j'ai un formulaire avec un bouton et un panneau:

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

Je viens de voir un autre exemple où ils ont appelé WaitForInputIdle au lieu de dormir. Donc, le code serait comme ceci:

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

Le projet de code a un bon article sur tout le processus: Hébergement d'applications EXE dans un projet WinForm

99
Luke Quinane
  • Ajout d'une solution dans Answer .. **

Ce code m'a aidé à ancrer un exécutable sous forme Windows. comme NotePad, Excel, Word, Acrobat reader n bien d'autres ...

Mais cela ne fonctionnera pas pour certaines applications. Comme parfois lorsque vous démarrez le processus d'une application .... attendez le temps d'inactivité ... et essayez d'obtenir son mainWindowHandle .... jusqu'à ce que le handle de la fenêtre principale devienne nul .....

donc j'ai fait une astuce pour résoudre ce problème

Si vous obtenez la poignée de la fenêtre principale comme nulle ... alors recherchez tous les processus d'exécution sur sytem et trouvez votre processus ... puis obtenez le tracas principal du processus et le panneau d'ensemble comme parent.

        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

Une autre solution intéressante pour lancer une application externe avec un conteneur WinForm est la suivante:

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

L'étape pour ProcessWindowStyle.Minimized de ProcessWindowStyle.Normal supprime le délai gênant.

enter image description here

3
daniele3004

Si vous souhaitez exécuter le bloc-notes dans votre application, vous feriez probablement mieux avec un composant éditeur de texte. Il y a évidemment une zone de texte de base fournie avec WinForms, mais je soupçonne que des composants plus avancés qui offrent des fonctionnalités du Bloc-notes (ou mieux) peuvent être trouvés sur l'interweb.

1
Steve Haigh

Je sais que cela est possible si l'autre application peut se fixer à un handle de fenêtre win32. Par exemple, nous avons une application C # distincte qui héberge une application DirectX dans l'une de ses fenêtres. Je ne connais pas les détails exacts de la façon dont cela est implémenté, mais je pense que le simple fait de passer le win32 Handle de votre panneau à l'autre application suffit pour que cette application attache sa surface DirectX.

1
Anthony Brien

Je remarque que toutes les réponses précédentes utilisent des fonctions de bibliothèque utilisateur Win32 plus anciennes pour accomplir cela. Je pense que cela fonctionnera dans la plupart des cas, mais fonctionnera de manière moins fiable au fil du temps.

Maintenant, n'ayant pas fait cela, je ne peux pas vous dire comment cela fonctionnera, mais je sais qu'une technologie Windows actuelle pourrait être une meilleure solution: Desktop Windows Manager API .

DWM est la même technologie qui vous permet de voir des aperçus miniatures en direct des applications à l'aide de la barre des tâches et de l'interface utilisateur du sélecteur de tâches. Je crois qu'il est étroitement lié aux services de terminaux distants.

Je pense qu'un problème probable qui pourrait se produire lorsque vous forcez une application à être enfant d'une fenêtre parent qui n'est pas la fenêtre du bureau est que certains développeurs d'applications feront des hypothèses sur le contexte de l'appareil (DC), la position du pointeur (souris), des largeurs d'écran, etc., qui peuvent provoquer un comportement erratique ou problématique lorsqu'il est "intégré" dans la fenêtre principale.

Je soupçonne que vous pouvez largement éliminer ces problèmes en vous appuyant sur DWM pour vous aider à gérer les traductions nécessaires pour que les fenêtres d'une application soient présentées et interagies de manière fiable à l'intérieur de la fenêtre de conteneur d'une autre application.

La documentation suppose une programmation C++, mais j'ai trouvé une personne qui a produit ce qu'il prétend être une bibliothèque d'encapsuleur C # open source: https://bytes.com/topic/c-sharp/answers/823547-desktop-window -manager-wrapper . La publication est ancienne et la source n'est pas sur un grand référentiel comme GitHub, bitbucket ou sourceforge, donc je ne sais pas à quel point elle est actuelle.

1
Alan McBee - MSFT