Member 12855127 Ответов: 1

Размещение внешнего процесса внутри панели в VB 2010


Я так и не смог понять, почему внешний процесс не отображается внутри панели. У меня есть следующие объявления в классе form1:

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


Затем для загрузки формы 1:

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


Это прекрасно работает, и форма 1 появляется с помощью кнопки "Открыть TLT" и при нажатии на нее...

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


Вызывается внешний процесс, и он отображается правильно, но не внутри панели1.

Что я уже пробовал:

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?

Dave Kreskowiak

Почему вы устанавливаете IsMdiContainer = true и добавляете Me.thb в коллекцию элементов управления?

Да, и повторное воспитание окна верхнего уровня поддерживается не всеми приложениями, а вашим приложением, потому что новый рабочий стол для приложения, которое вы запускаете.

Member 12855127

IsMDiContainer = true-это потому, что кнопка определена в коде, а не в дизайне. Это приводит к тому, что основная форма (form1) отображается иначе, чем если бы она не использовалась.

Повторное рисование при повторном нажатии кнопки делает трюк приведения приложения внутрь панели 1 и ведет себя как часть панели 1. Без повторного нажатия кнопки при отображении приложения приложение работает как независимое приложение. Моя цель состоит в том, чтобы иметь внешнее приложение внутри panel1 без необходимости снова нажимать кнопку.

Любопытно, что если внешнее приложение (например) notepad.exe затем он прекрасно работает без необходимости снова нажимать кнопку и ведет себя как часть panel1, но не для приложения TLT.

Dave Kreskowiak

Да, IsMdiContainer автоматически добавляет в форму элемент управления, называемый MdiClient. Он выглядит как серая панель, но это не настоящий пульт управления. Это область, которая управляет формами MdiChild. Это совершенно бесполезно в вашем приложении, если вы вообще не используете Mdi.

Если у вас есть панель в форме, называемая "panel1", вы вообще не используете элемент управления MdiClient и можете просто отключить IsMdiContainer.

1 Ответов

Рейтинг:
2

Member 12855127

Я смог заставить его работать, но не очень элегантно. Поэтому я поделюсь тем, что сделал.

По-видимому, проблема заключается в том, что внешнему приложению требуется некоторое время для полной загрузки, хотя код обрабатывает все без ожидания. Поэтому я включил системную задержку потока и пробовал разные тайминги, пока не был получен хороший.

Это код для запуска процесса из button2_click:

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


Если время ожидания потоковой передачи системы меньше 350, то внешнее приложение не будет помещено в панель panel1. Если он больше 350, то эффект мерцания заметен пользователю и не очень приятен.

Должен быть способ захватить, если внешнее приложение загрузилось полностью, а не использовать задержку, потому что я не уверен, зависит ли время от компьютера пользователя или нет.

Дело в том, что проблема была вызвана тем, что внешнему приложению требовалось время для полной загрузки, прежде чем устанавливать panel1 в качестве родителя. Я уверен, что возможно более элегантное решение, и буду признателен за предложения о том, как захватить, когда внешнее приложение полностью загрузилось.


Dave Kreskowiak

Ваш код никак не может определить, что означает "полностью загруженный". Эта концепция просто не существует, а если и существует, то не согласована во всех приложениях.

Время ожидания в 350 миллисекунд, которое вы туда помещаете, совершенно произвольно и не будет работать в более медленных средах, таких как виртуальные рабочие столы.

Вам придется покопаться в том, что это значит для другого приложения, чтобы быть "полностью загруженным", и как вы сможете понять это каким-то образом, вручную. Как только у вас это есть, вы можете написать код, чтобы понять это таким же образом.

Это будет полностью зависеть от вас. Нет никого, кто мог бы сказать вам, что означает "полная загрузка" в контексте вашего второго приложения.