Showing a C# WinForms Panel on a Delphi VCL Frame

Viewed 262

I'm trying to show a panel which is created in a C# WinForms application inside of a Delphi VCL application. I figured it out so that the panel is getting visible inside of the Delphi application. But I also want to get the feature that the C# panel gets automatically resized on size change on the Delphi side(Delphi: alClient, C#-Winform: Dock->Fill). Currently I don't have found a solution to get that working. I have one workaround which I will try but my primary goal is to get the Winforms Panel as a first calss citizen inside of the delphi form.

What I found is that when I use my code the C# panel is shown in the Delphi application but it is not getting registered in the Delphi Components Array therefore Delphi don't know that there is something getting drawn on it.

I'm open for any suggestions and ideas.

C# Code:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

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

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SetParent(panel1.Handle, (IntPtr)919640);  // the second parameter is the Handle from the delphi form
        }
    }
}

Delphi:

unit FrmParent;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TForm5 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form5: TForm5;

implementation

{$R *.dfm}

procedure TForm5.FormCreate(Sender: TObject);
begin
Caption:=IntToStr(Handle);
end;
1 Answers

It seems there is no way to get Delphi handling the foreign handle directly. So I reworked the sample code from the question as following: I give the handle from C# to Delphi and "adopt" it in Delphi

oldParent := Winapi.Windows.SetParent(CHILD, Panel1.Handle);

note the oldParent variable. In this I store the parent which owns the Child at first. So when the Delphi application is shutting down I can give the control back to his previous owner. If I don't do this the control will be lost after shutting down the Delphi application.

  if(oldParent>0) then begin
    Winapi.Windows.SetParent(CHILD, oldParent);
  end;

And I created a event handler for the OnResize event

procedure TForm5.Panel1Resize(Sender: TObject);
begin
  Winapi.Windows.MoveWindow(CHILD, 0, 0, Panel1.Width, Panel1.Height, true);
end;

this "emulates" the behavior of a Delphi component set to alClient.

Worthy to note is indeed, that in the moment when a application "adopt" a foreign handle the event message queues of both applications get chained together. So when your C# application is stuck in the event loop (blocking operation on a button handler for example) your Delphi application is also stuck and vice versa.

Related