L'hébergement d'application WPF, à l'intérieur de la non-application WPF utilisant WIn32 SetParent()

StackOverflow https://stackoverflow.com/questions/4135891

  •  30-09-2019
  •  | 
  •  

Question

J'ai une application WPF qui je veux ressembler, il est hébergé à l'intérieur d'un autre - non-WPF - application.Dans la vraie vie, cette non-application WPF est un ActiveX dans Internet Explorer, mais pour le plaisir d'illustrer le problème, j'utilise une simple application Windows Forms.

J'ai utiliser la fonction Windows API SetParent, dont il existe des dizaines de fils sur déjà.Cependant, je ne trouve rien écrit sur mon problème: Une petite région sur la droite et en bas de l'application WPF n'est pas peint l'intérieur de la non-application WPF de la fenêtre.

La fenêtre WPF en cours d'exécution par lui-même:
alt text

La fenêtre WPF avec WinForm application de la fenêtre en tant que parent:
alt text

Je n'ai pas l'expérience de la problème si un swap de l'application WPF, avec une application WinForms ou une plaine Win32 application (comme le bloc-notes).

Le WinForm code ressemble à ceci:

private void Form1_Load(object sender, EventArgs e)
    {
        // Start process
        var psi = new ProcessStartInfo("c:\\wpfapp\\wpfapp\\bin\\Debug\\wpfapp.exe");
        psi.WindowStyle = ProcessWindowStyle.Normal;
        _process = Process.Start(psi);

        // Sleep until new process is ready
        Thread.Sleep(1000);

        // Set new process's parent to this window
        SetParent(_process.MainWindowHandle, this.Handle);

        // Remove WS_POPUP and add WS_CHILD window style to child window
        const int GWL_STYLE = -16;
        const long WS_POPUP = 0x80000000;
        const long WS_CHILD = 0x40000000;
        long style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
        style = (style & ~(WS_POPUP)) | WS_CHILD;
        SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);

        // Move and resize child window to fit into parent's
        MoveWindow(_process.MainWindowHandle, 0, 0, this.Width, this.Height, true);
    }

Note:Je suis conscient que cette utilisation de l'SetParent n'est pas nécessairement une pratique recommandée, mais je veux et il faut trouver comment le faire de cette façon, de sorte s'il vous plaît laissez-moi :)

Était-ce utile?

La solution

J'ai trouvé une solution qui fonctionne assez bien:Appel MoveWindow avant SetParent:

private void Form1_Load(object sender, EventArgs e)
{
     // Start process            
     var psi = new ProcessStartInfo("C:\\WpfApp\\WpfApp.exe");
     psi.WindowStyle = ProcessWindowStyle.Normal;
     _process = Process.Start(psi);

     // Sleep until new process is ready
     Thread.Sleep(3000);

     // Move and resize child window to fit into parent's
     Rectangle rect;
     GetClientRect(this.Handle, out rect);
     MoveWindow(_process.MainWindowHandle, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top, true);

     // Set new process's parent to this window
     SetParent(_process.MainWindowHandle, this.Handle);

     // Remove WS_POPUP and add WS_CHILD window style to child window
     long style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
     style = (style & ~(WS_POPUP) & ~(WS_CAPTION)) & ~(WS_THICKFRAME) | WS_CHILD;
     SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);
}           

Dans le gestionnaire d'événement SizeChanged, je prends l'enfant de la mère, appel MoveWindow et le replacer dans le parent.Pour réduire le scintillement, je masquer la fenêtre tout en faisant ces opérations:

private void Form1_SizeChanged(object sender, EventArgs e)
{
     ShowWindow(_process.MainWindowHandle, SW_HIDE);

     var ptr = new IntPtr();
     SetParent(_process.MainWindowHandle, ptr);

     Rectangle rect;
     GetClientRect(this.Handle, out rect);

     MoveWindow(_process.MainWindowHandle, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top, true);            
     SetParent(_process.MainWindowHandle, this.Handle);
     ShowWindow(_process.MainWindowHandle, SW_SHOW);
}

il n'explique pas pourquoi MoveWindow ne fonctionne pas après SetParent, mais elle n'en résout mon problème, donc je vais donner la réponse, à moins que quelque chose de mieux se présente.

Autres conseils

Vous devriez probablement redimensionner votre fenêtre WPF afin qu'elle s'insère dans le espace client de son nouveau parent de la fenêtre:

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

// Move and resize child window to fit into parent's client area.
RECT rc = new RECT();
GetClientRect(this.Handle, out rc);
MoveWindow(_process.MainWindowHandle, 0, 0, rc.Right - rc.Left,
    rc.Bottom - rc.Top, true)

J'ai utilisé un Formulaire / UserControl avec un Panneau.Ensuite, j'ai utilisé le Panneau de la nouvelle société mère et de définir la nouvelle position et la taille du panneau avec SetWindowPos à la fenêtre enfant.

NOTE:MS recommande d'utiliser SetWindowPos après l'utilisation de SetWindowLong (ou SetWindowLongPtr) pour activer les nouveaux styles.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top