Click here to Skip to main content
16,016,925 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I haven't been able to figure out why the external process doesn't show inside the panel. I have the following declarations in ther form1 class:

Dim myProcess As Process = New Process()
    Public WithEvents thb As Button = New System.Windows.Forms.Button
    Public Declare Function SetParent Lib "user32" Alias "SetParent" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As System.IntPtr


Then for the form1 load:

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        WindowState = FormWindowState.Maximized
        MaximizeBox = False
        ShowIcon = False
        Text = "TLT Opener"
        thb.Location = New System.Drawing.Point(20, 20)
        thb.Name = "thb"
        thb.Size = New System.Drawing.Size(200, 23)
        thb.TabIndex = 1
        thb.Text = "Open TLT"
        thb.UseVisualStyleBackColor = True
        Controls.Add(Me.thb)
        IsMdiContainer = True
        myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal
        myProcess.StartInfo.FileName = "C:\Program Files (x86)\Transformation LogicTree\TLT.exe"

    End Sub


That works fine and the form1 shows up with the "Open TLT" button and when the button is clicked...

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles thb.Click
        Dim listProc() As System.Diagnostics.Process
        listProc = System.Diagnostics.Process.GetProcessesByName("TLT")
        If listProc.Length > 0 Then
            SetParent(myProcess.MainWindowHandle, Me.Panel1.Handle)
            Exit Sub
        End If
        myProcess.Start()
        myProcess.EnableRaisingEvents = True            
        AddHandler myProcess.Exited, AddressOf ProcessExited    
        myProcess.WaitForInputIdle()
        SetParent(myProcess.MainWindowHandle, Me.Panel1.Handle)
        
        Me.BringToFront()  'don't know is needed
    End Sub


The external process gets called and it shows correctly but NOT inside the panel1.

What I have tried:

Tried all suggested available hints from other threads... but the only way I am able to get the external app inside the panel1 is if I click the "Open TLT" button once the external app is running. Tried to force a click to the button but programmatically it does nothing, only if done with a mouse click.

Does someone knows why is this and how to resolve it?
Posted
Updated 12-Nov-18 8:57am
Comments
Dave Kreskowiak 12-Nov-18 11:47am    
Why are you setting IsMdiContainer = true and adding Me.thb to the controls collection?

Oh, and re-parenting a top level window isn't supported by all applications, and your app because the new Desktop for the app you launch.
Member 12855127 12-Nov-18 13:53pm    
The isMDiContainer = true is because the button is defined in code and not from the design. This makes the main form (form1) show up different than if not used.

The re-painting when pressing for a second time the button does the trick of bringing the app inside the panel1 and behaving as part of panel1. Without clicking the button again when the app is shown the app runs as an independent app. My objective is to have the external app inside panel1 without having to click again the button.

Curiously, if the external app is (for example) notepad.exe then it works fine without having to click the button again and behaves as part of panel1, but not for the TLT app.
Dave Kreskowiak 12-Nov-18 19:55pm    
Yeah, IsMdiContainer automatically adds a control to the form, called an MdiClient. It looks like a gray panel, but it's not an actual panel control. It's an area that manages MdiChild forms. It's completely useless in your app if you're not using Mdi at all.

If you've got a panel on the form, called "panel1", you're not using the MdiClient control at all and can just turn off IsMdiContainer.

1 solution

I have been able to make it work but not in an elegant way. Therefore I will share what I did.

Apparently the issue is that the external app needs some time to load completely eventhough the code processes all without waiting. Therefore I included a system thread delay and tried different timings until a good one was obatined.

This is the code to start the process from button2_click:

myProcess.Start()
        myProcess.EnableRaisingEvents = True            
        AddHandler myProcess.Exited, AddressOf ProcessExited    
        myProcess.WaitForInputIdle()
        System.Threading.Thread.Sleep(350)
        SetParent(myProcess.MainWindowHandle, Panel1.Handle)


If the system threading sleep time is less than 350 it will not bring the external app inside panel1. If it is greater than 350 then a flickering effect is noticeable to the user and not very nice.

There should be a way to capture if the external app has loaded completely instead of using the delay, because I am not sure if the timing depends on the user's PC or not.

The point is that the problem was due to the external app needing time to load completely before setting panel1 as the parent. I am sure a more elegant solution is possible and will appreciate suggestions on how to capture when the external app has loaded completely.
 
Share this answer
 
Comments
Dave Kreskowiak 12-Nov-18 19:52pm    
There isn't any way for your code to determine what "completely loaded" means. That concept just doesn't exist and, if it did, isn't consistent across all applications.

The 350 millisecond wait time you put in there is completely arbitrary and will fail on slower environments, like virtual desktops.

You'd have to dig into what it means for the other app to be "completely loaded" and how you'd be able to figure that out somehow, by hand. Once you have that, you can then write code to figure it out the same way.

This is going to be entirely up to you. There isn't anyone that's going to be able to tell you what "complete loaded" means in the context of your second application.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900