2015-04-16 13 views
19

Ich muss ein Win32-Fenster in einem Windows Form-Steuerelement hosten. Ich hatte das gleiche Problem mit WPF und löste dieses Problem, indem ich die Steuerung verwendete.HwndHost für Windows Form - Win32/WinForm Interoperabilität

ich dieses Tutorial gefolgt:

Walkthrough: Hosting a Win32 Control in WPF

Gibt es eine gleichwertige Kontrolle in Windows Form?

Ich habe eine Panel und seine Handle Eigenschaft, verwende ich diesen Griff als Eltern meines Direct2D Zielfenster machen:

// Register the window class. 
     WNDCLASSEX wcex = { sizeof(WNDCLASSEX) }; 

     // Redraws the entire window if a movement or size adjustment changes the height 
     // or the width of the client area. 
     wcex.style   = CS_HREDRAW | CS_VREDRAW; 
     wcex.lpfnWndProc = Core::WndProc; 
     wcex.cbClsExtra = 0; 
     wcex.cbWndExtra = sizeof(LONG_PTR); 
     wcex.hInstance  = HINST_THISCOMPONENT; 
     wcex.hbrBackground = nullptr; 
     wcex.lpszMenuName = nullptr; 
     wcex.hCursor  = LoadCursor(nullptr, IDI_APPLICATION); 
     wcex.lpszClassName = L"SVGCoreClassName"; 

     RegisterClassEx(&wcex); 

hwnd = CreateWindow(
      L"SVGCoreClassName",  // class name 
      L"",      // window name 
      WS_CHILD | WS_VISIBLE,  // style 
      CW_USEDEFAULT,    // x 
      CW_USEDEFAULT,    // y 
      CW_USEDEFAULT,    // width 
      CW_USEDEFAULT,    // height 
      parent,      // parent window 
      nullptr,     // window menu 
      HINST_THISCOMPONENT,  // instance of the module to be associated with the window 
      this);      // pointer passed to the WM_CREATE message 

... 

hr = d2dFactory->CreateHwndRenderTarget(
     D2D1::RenderTargetProperties(), 
     D2D1::HwndRenderTargetProperties(hwnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY), 
     &renderTarget); 

Der Code funktioniert, wenn ich den HwndHost Muttergriff mit WPF verwenden. Aber es macht nichts, wenn ich den System.Windows.Forms.Panel Handle benutze.

+0

Sie könnten daran interessiert sein, ['NativeWindow'] (https://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow.aspx). –

+0

Alle Winforms-Steuerelemente sind bereits Win32-Fenster, so dass "Hosting" nicht viel Sinn macht. Sie müssen die Art dieses Fensters besser beschreiben. Wem gehört es? Wie erstellst du es? –

+0

@HansPassant siehe meine Bearbeitung. – Nick

Antwort

7

Was Sie in WPF tun mussten, um ein gültiges D2D1-Zielfenster zu erstellen, ist in Winforms nicht erforderlich. Dies war in WPF erforderlich, da Steuerelemente nicht selbst Windows sind und keine Handle-Eigenschaft besitzen, die CreateHwndRenderTarget() benötigt.

In WinForms ist die Panel-Klasse bereits ein perfektes Renderziel, Sie können die Handle-Eigenschaft verwenden, um D2D1 mitzuteilen, wo gerendert werden soll. Sie müssen ihm nur sagen, dass er aufhören soll, sich selbst zu malen. Fügen Sie Ihrem Projekt eine neue Klasse hinzu und fügen Sie diesen Code ein:

using System; 
using System.Windows.Forms; 

class D2D1RenderTarget : Control { 
    protected override void OnHandleCreated(EventArgs e) { 
     base.OnHandleCreated(e); 
     if (!this.DesignMode) { 
      this.SetStyle(ControlStyles.UserPaint, false); 
      // Initialize D2D1 here, use this.Handle 
      //... 
     } 
    } 
} 

Kompilieren. Legen Sie das neue Steuerelement in Ihr Formular und ersetzen Sie das vorhandene Bedienfeld.

+0

Ich habe nicht verstanden, welchen Handle ich als übergeordnetes Argument der CreateWindow-Funktion übergeben muss. Ich habe versucht, indem Sie die Control.Handle-Eigenschaft in der OnHandleCreated-Methode verwenden, aber es funktioniert nicht. Bitte sehen Sie meine Bearbeitung auch. – Nick

+0

Darüber hinaus habe ich festgestellt, dass die CreateParams-Eigenschaft nicht aufgerufen wird (wenn ich einen Haltepunkt in ihm festlegen). – Nick

+0

Nicht, es ist völlig automatisch, wenn Sie das Steuerelement auf dem Panel fallen lassen. Wenn Sie dies in Code tun, müssen Sie die Controls.Add() - Methode des Formulars verwenden, um das Steuerelement dem Panel hinzuzufügen. Nachdem Sie etwas Code hinzugefügt haben, sieht das ** komplett ** unnötig aus. Alles, was CreateHwndRenderTarget() benötigt, ist ein gültiges Fensterhandle. Die Handle-Eigenschaft des Panels ist bereits ziemlich gut genug, es gibt keinen Sinn mehr zu helfen. Was dieser C++ - Code getan hat, ist der gleiche wie bei Panel. Schade, dass du so ein kleines Schnippchen geschrieben hast. –

0

Klingt wie eine MDI-Anwendung. Etwas wie das?

[DllImport("user32.dll")] 
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 

[DllImport("user32.dll")] 
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); 

Form f = new Form(); 
Button b1 = new Button { Text = "Notepad" }; 
b1.Click += delegate { 
    using (var p = Process.Start("notepad.exe")) { 
     p.WaitForInputIdle(); 
     SetParent(p.MainWindowHandle, f.Handle); 
     MoveWindow(p.MainWindowHandle, 50, 50, 300, 300, true); 
    } 
}; 
f.Controls.Add(b1); 
Application.Run(f);