-2

To explain my issue, I will try to screenshot this instead so that I can relay my message to everyone. Here on the picture, I have main project namely MainWinForm and and Solution Folder which contains two Windows Project namely FirstWinFormApp and SecondWinFormApp.

Here is the screenshot:

enter image description here

The MainWinForm project contains a Form1.cs which is an MDI Container set to true. I am trying to launch the form (First.cs) from FirstWinFormApp project using the button click event handler.

enter image description here

Everything should be working fine. I can launch the First.cs form inside the MDI Container of Form1.

Now here is the tricky part, I want to run the Program.cs of FirstWinFormApp instead the Program.cs of MainWinForm. The reason behind this is my requirement on my project (assemblies, connections, etc).

When I launch the application, the Program.cs of MainWinForm project is triggered. When I call the child app, its Program.cs is not called anymore. Is it possible that I can call the Program.cs of the child application (FirstWinFormApp) even though the Program.cs of the MainWinForm project was already called?

Willy David Jr
  • 8,604
  • 6
  • 46
  • 57

1 Answers1

5

I suppose the MDI container and the child window would belong to different executables (different projects and all). This is not recommended in the first place, but it can be done. Basically you would need to mess with Windows API and not use Framework managed methods.

You would definitely need the SetParent API - which can put your window inside another even if the parent window is not a MDI container. You need some way to communicate the Handle property of the parent window, though, and the methods are either shaky (write the pointer down somewhere that both processes can access) or needlessly complicated (requiring inter-process communication).

The easiest, you can find the main window from the child by the title using FindWindow. This would fail if another program have the same title as your MDI window.

The code below is untested, but you would need it inside your child window's Program.cs:

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindow(IntPtr className, string lpWindowName);

and in your child program's Main()

var hwnd = FindWindow(IntPtr.Zero, "My MDI Title");
SetParent(childWindow.Handle, hwnd);

In your case this would be something like

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

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

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    var formObj = new First();

    var hwnd = FindWindow(IntPtr.Zero, "My MDI Title");
    SetParent(formObj.Handle, hwnd);

    Application.Run(formObj);
}

Be sure to change the MDI form's title to "My MDI Title" as well. In the test app below I'm doing it in reverse - putting a Notepad window inside Form1, but you can do it any way you like.

Screenshot

luungoc2005
  • 282
  • 2
  • 10
  • Thanks for assistance. I am having a hard time on your SetParent method (SetParent(childWindow.Handle, hwnd), what should I put on childWindow? The name of the form? – Willy David Jr Jan 31 '17 at 03:53
  • that would be your `Form1` object. See my edited answer – luungoc2005 Jan 31 '17 at 06:47
  • Its not possible since I cannot reference Form1 since Form1 project is already reference to child winform. This will cause a circular dependency. I need to reference the child winform in order to call this code: First x = new First(); x.MdiParent = this; x.Show(); – Willy David Jr Jan 31 '17 at 06:58
  • My bad, I have your `Form1` and `First` mixed up. See my edited answer & screenshot for an example, you should modify it to your need. – luungoc2005 Jan 31 '17 at 07:18
  • I am not sure it's working. I tried to debug it but its not going on breakpoint on my child's program.cs, is that totally fine? How can I be sure that the program.cs of child is the one working now? – Willy David Jr Jan 31 '17 at 08:01
  • 1
    Your solution has 2 projects, therefore should generate 2 executables. If your startup project is only MainWinForm then only that is running. See [this question](http://stackoverflow.com/questions/3850019/running-two-projects-at-once-in-visual-studio) for how to debug with multiple projects, but on production you should use Process.Start() to start your child executable. – luungoc2005 Jan 31 '17 at 08:10