Hello everyone, im currently stuck because i'm not sure how to start on this part of my program.
What i'll need help is controlling another application, my program is suppose to run another application, and be able to hide it, show it, verify that is running, it also needs to be able to add a button to a form of the program that im trying to control.

There's this tool that does exactly the same but it has many spell errors and its a little buggy so im trying to do one.

I don't have an actual code for this because i don't know how to start with it, this program will be able to run the same application infinite times (Depends on the user, but normally the application is being opened 1~10 Times), so i was concerned if the applications are being opened and it glitches by getting another process id or w.e.

So any help ?

Recommended Answers

All 12 Replies

O.o ??

Have you looked at autoit. There is a component, AutoitX, that can be created and used from within vb.

Does it requires a .dll ?

The scriptable component, autoitx, uses a dll named AutoItX3.dll (or AutoItX_x64.dll).

I don't want my program using .dlls, and there has to be some way because i have a program that does it and its in vb.net too, i tried .net reflector to see the codes or w.e but its encrypted a bit.

Most of your needs are pretty straight forward. The adding a button one is the stickler. I've hosted other apps in a winform before, so I thought why not follow the same method to host a winform button in another app? It sort of works ok.

You need to control force repainting of the control as the other app will not do it for you. I used a timer to do this. Also, once the button is on the other app, if you click it, it gains focus and you need to send the focus back to the form from which it originated in its click event handler.

Start a new winform project:
Form1.vb code

Imports System.Runtime.InteropServices

Public Class Form1

   Private WithEvents Slave As Process
   Private Slave_SI As New ProcessStartInfo
   Private OldButtonLoc As Point
   Private WithEvents btn2Refresher As New Timer With {.Interval = 500}

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      Button1.Enabled = False
      With Slave_SI
         .FileName = "notepad.exe"
         .Arguments = ""
         .WindowStyle = ProcessWindowStyle.Normal
      End With
      Slave = Process.Start(Slave_SI)
      Slave.EnableRaisingEvents = True

      Slave.WaitForInputIdle(5000) ' give it 5 seconds to startup
      'add the button you wanted
      'will steal a button from this form
      SetParent(Button2.Handle, Slave.MainWindowHandle)
      'position the button
      OldButtonLoc = Button2.Location
      Button2.Location = New Point(50, 0)
      Button2.Visible = True
      btn2Refresher.Start() 'hack to repaint button on host window
      Me.ActiveControl = Me.Button3 'need to force focus back to a current form window
                                    'It jumped to button2 when I disabled Button1

   End Sub

   Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
      MsgBox("Hi")
      Me.ActiveControl = Me.Button1 'need to force focus back to a current form window
   End Sub

   Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
      'Hide notepad
      If Slave Is Nothing Then Exit Sub
      ShowWindow(Slave.MainWindowHandle, ShowWindowCommands.Hide)
   End Sub

   Private Sub btn2Refresher_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles btn2Refresher.Tick
      Button2.Refresh()
   End Sub

   Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
      'Show NP
      If Slave Is Nothing Then Button1_Click(Nothing, Nothing)
      ShowWindow(Slave.MainWindowHandle, ShowWindowCommands.ShowDefault)
   End Sub

   Delegate Sub ForReturnButton()
   Sub ReturnButton()
      btn2Refresher.Stop()
      SetParent(Button2.Handle, Me.Handle)
      Button2.Location = OldButtonLoc
      Slave = Nothing
      Button1.Enabled = True
   End Sub

   Private Sub Slave_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles Slave.Exited
      'here you know if the process has terminated
      If InvokeRequired Then Beep()
      Me.Invoke(New ForReturnButton(AddressOf ReturnButton)) 'need invoke because of cross threading
   End Sub

   Private Const WM_Close As Int32 = &H10
   Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
      If Slave IsNot Nothing Then
         'optional, but I like to cleanup
         Dim bogus As New IntPtr
         SendMessageTimeout(Slave.MainWindowHandle, _
                            WM_Close, _
                            IntPtr.Zero, _
                            IntPtr.Zero, _
                            SendMessageTimeoutFlags.SMTO_NORMAL, _
                            1, _
                            bogus)

      End If
   End Sub


    <DllImport("user32.dll")> _
    Public Shared Function MoveWindow(ByVal hWnd As IntPtr, ByVal x As Int32, ByVal y As Int32, ByVal nWidth As Int32, ByVal nHeight As Int32, ByVal bRepaint As Boolean) As Boolean
    End Function

    <DllImport("user32.dll")> _
    Public Shared Function SetFocus(ByVal hWnd As IntPtr) As IntPtr
    End Function

   <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
   Public Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
   End Function

   <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
   Private Shared Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As ShowWindowCommands) As Boolean
   End Function

   Enum ShowWindowCommands As Integer
      ''' <summary>
      ''' Hides the window and activates another window.
      ''' </summary>
      Hide = 0
      ''' <summary>
      ''' Activates and displays a window. If the window is minimized or
      ''' maximized, the system restores it to its original size and position.
      ''' An application should specify this flag when displaying the window
      ''' for the first time.
      ''' </summary>
      Normal = 1
      ''' <summary>
      ''' Activates the window and displays it as a minimized window.
      ''' </summary>
      ShowMinimized = 2
      ''' <summary>
      ''' Maximizes the specified window.
      ''' </summary>
      Maximize = 3
      ' is this the right value?
      ''' <summary>
      ''' Activates the window and displays it as a maximized window.
      ''' </summary>      
      ShowMaximized = 3
      ''' <summary>
      ''' Displays a window in its most recent size and position. This value
      ''' is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except
      ''' the window is not actived.
      ''' </summary>
      ShowNoActivate = 4
      ''' <summary>
      ''' Activates the window and displays it in its current size and position.
      ''' </summary>
      Show = 5
      ''' <summary>
      ''' Minimizes the specified window and activates the next top-level
      ''' window in the Z order.
      ''' </summary>
      Minimize = 6
      ''' <summary>
      ''' Displays the window as a minimized window. This value is similar to
      ''' <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the
      ''' window is not activated.
      ''' </summary>
      ShowMinNoActive = 7
      ''' <summary>
      ''' Displays the window in its current size and position. This value is
      ''' similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the
      ''' window is not activated.
      ''' </summary>
      ShowNA = 8
      ''' <summary>
      ''' Activates and displays the window. If the window is minimized or
      ''' maximized, the system restores it to its original size and position.
      ''' An application should specify this flag when restoring a minimized window.
      ''' </summary>
      Restore = 9
      ''' <summary>
      ''' Sets the show state based on the SW_* value specified in the
      ''' STARTUPINFO structure passed to the CreateProcess function by the
      ''' program that started the application.
      ''' </summary>
      ShowDefault = 10
      ''' <summary>
      '''  <b>Windows 2000/XP:</b> Minimizes a window, even if the thread
      ''' that owns the window is not responding. This flag should only be
      ''' used when minimizing windows from a different thread.
      ''' </summary>
      ForceMinimize = 11
   End Enum


   <DllImport("user32.dll", SetLastError:=True)> _
   Public Shared Function SendMessageTimeout(ByVal windowHandle As IntPtr, _
                                             ByVal Msg As Int32, _
                                             ByVal wParam As IntPtr, _
                                             ByVal lParam As IntPtr, _
                                             ByVal flags As SendMessageTimeoutFlags, _
                                             ByVal timeout As UInt32, _
                                             ByRef result As IntPtr) As IntPtr
   End Function

   <Flags()> _
   Public Enum SendMessageTimeoutFlags As UInt32
       SMTO_NORMAL = 0
       SMTO_BLOCK = 1
       SMTO_ABORTIFHUNG = 2
       SMTO_NOTIMEOUTIFNOTHUNG = 8
   End Enum

End Class

The code for Form1.designer.vb:

<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button
Me.Button2 = New System.Windows.Forms.Button
Me.Button3 = New System.Windows.Forms.Button
Me.Button4 = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(31, 28)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(75, 23)
Me.Button1.TabIndex = 0
Me.Button1.Text = "Start NP"
Me.Button1.UseVisualStyleBackColor = True
'
'Button2
'
Me.Button2.Location = New System.Drawing.Point(157, 28)
Me.Button2.Name = "Button2"
Me.Button2.Size = New System.Drawing.Size(123, 23)
Me.Button2.TabIndex = 1
Me.Button2.Text = "I don't get no respect"
Me.Button2.UseVisualStyleBackColor = True
Me.Button2.Visible = False
'
'Button3
'
Me.Button3.Location = New System.Drawing.Point(31, 80)
Me.Button3.Name = "Button3"
Me.Button3.Size = New System.Drawing.Size(75, 23)
Me.Button3.TabIndex = 2
Me.Button3.Text = "Hide Np"
Me.Button3.UseVisualStyleBackColor = True
'
'Button4
'
Me.Button4.Location = New System.Drawing.Point(31, 131)
Me.Button4.Name = "Button4"
Me.Button4.Size = New System.Drawing.Size(75, 23)
Me.Button4.TabIndex = 3
Me.Button4.Text = "Show NP"
Me.Button4.UseVisualStyleBackColor = True
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(Me.Button4)
Me.Controls.Add(Me.Button3)
Me.Controls.Add(Me.Button2)
Me.Controls.Add(Me.Button1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)

End Sub
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents Button2 As System.Windows.Forms.Button
    Friend WithEvents Button3 As System.Windows.Forms.Button
    Friend WithEvents Button4 As System.Windows.Forms.Button

End Class
commented: Useful post :) +1
commented: good stuff here +9

Thank you :) ill test that later since im in other part. i will pm you right now, im stuck with a little thing that i thing is easy to fix but i can't see the logic

OMG, i just tested that a litte on a blank project apprently thats what i wanted :D THANK YOU SOO MUCH :)))))
Ill mark it as solve for now and maybe if i need something else in the future ill change it, thx :)

Ok, im implementing this now to the project, is there a way to add the button to another form ?

Bump

I have done some testing on this method. If the program that you want to append the button to is a .Net application it will not work. It crashes on SetParent. It appears as if there is something built in to prevent this. It is probably a good thing as this type of thing could be used for mischief. If it is another type of program, then you may need to use the API function FindWindowEX to seek the window based on its class and/or caption and use the result instead of Slave.MainWindowHandle.

These types of manipulations typically take a lot of trial and error to get working correctly. There used to be a control from MS to host office applications in a WinForm, but MS withdrew it due too to many problems with it.

So all I can suggest is use what I have shown as starting point and experiment. You may not be successful in the end though.

Well the other application is not .Net application, aslo is it possible to manage more than 1 instance ?

Example with the notepad if i open 1 notepad with it works, but then if i open another the application wont control the first notepad anymore.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.