Can I embed another running exe inside my visual basic form? - vb.net

I started experimenting with embeding another .exe in my form. I managed to run another program and use it inside a forms panel. Is there a way to put inside this panel an already running exe?
Public Class Form1
Declare Auto Function SetParent Lib "user32.dll" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As Integer
Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Dim proc As Process
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
proc = Process.Start("C:\WINDOWS\notepad.exe")
proc.WaitForInputIdle()
SetParent(proc.MainWindowHandle, Panel1.Handle)
End Sub
End Class

The code becomes like this. The notepad.exe needs to be running , on startup it embeds the notepad.exe on the main form. Thanks a lot.
Public Class Form1
Declare Auto Function SetParent Lib "user32.dll" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As Integer
Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim proc = Process.GetProcessesByName("notepad").FirstOrDefault()
If proc IsNot Nothing Then
SetParent(proc.MainWindowHandle, Panel1.Handle)
End If
End Sub
End Class

Related

How to use handle in multiple subs

I'm certainly no expert on VB, so hopefully someone is willing to help me out here.
When I use the code down below, the msgbox in mybase.shown properly shows the handle number, but the one in button1.click throws the exception "No process is associated with this object". So apparently the handle is only available during the mybase.shown sub? How do I make it available for other subs too?
Thanks for any help in advance!
Kind regards, Eric
Option Strict On
Public Class Form1
Private WithEvents proc As New Process
Private Const WM_SYSCOMMAND As Integer = &H112
Private Const SC_MAXIMIZE As Integer = &HF030
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Declare Auto Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndParent As IntPtr) As Integer
Declare Auto Function SendMessage Lib "user32" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Public Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
Dim proc As Process = Process.Start("notepad")
Threading.Thread.Sleep(200)
SetParent(proc.MainWindowHandle, Panel1.Handle)
SendMessage(proc.MainWindowHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0)
MsgBox(proc.MainWindowHandle)
End Sub
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MsgBox(proc.MainWindowHandle)
SetParent(proc.MainWindowHandle, IntPtr.Zero)
End Sub
End Class
Thank you very much everybody! With your help, I finally managed to make it work. I really appreciate your efforts!
Kind regards,
Eric
Options Strict On
Public Class Form1
Private WithEvents proc As Process
Private Const WM_SYSCOMMAND As Integer = &H112
Private Const SC_MAXIMIZE As Integer = &HF030
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Declare Auto Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndParent As IntPtr) As Integer
Declare Auto Function SendMessage Lib "user32" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Dim testje As Long
Public Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
proc = Process.Start("notepad")
Threading.Thread.Sleep(200)
SetParent(proc.MainWindowHandle, Panel1.Handle)
SendMessage(proc.MainWindowHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0)
End Sub
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SetParent(proc.MainWindowHandle, IntPtr.Zero)
End Sub
End Class

Move a child out of panel

I use the code down below to start a cmd.exe window and move it into panel1 on my form. I added button1 to it and I like to use that button to move the child out of panel1, back "to the desktop". Does anybody know how to do that? I did some Googling and I can find a lot of examples on how to move a child into a panel or how to move it from one panel to another, but not how to move it out of a panel...
Thanks for any help in advance!
Kind regards,
Eric
Imports System.Runtime.InteropServices
Public Class Form1
Private WithEvents proc As New Process
Public Const SW_SHOWMAXIMIZED As UInt32 = 3
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Int32) As Int32
Private Declare Function DwmGetWindowAttribute Lib "dwmapi" (ByVal hwnd As IntPtr, ByVal dwAttribute As Integer, ByRef pvAttribute As RECT, ByVal cbAttribute As Integer) As Integer
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal nCmdShow As Int32) As Boolean
Public Structure RECT
Public left, top, right, bottom As Integer
End Structure
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
proc.EnableRaisingEvents = True
proc.StartInfo.FileName = "cmd"
proc.Start()
End Sub
Private Sub Tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Shown
proc.WaitForExit(200)
If SetParent(proc.MainWindowHandle, Panel1.Handle) <> IntPtr.Zero Then
SetWindowPos(proc.MainWindowHandle, IntPtr.Zero, 0, 0, Width, Height, 0)
ShowWindow(proc.MainWindowHandle, SW_SHOWMAXIMIZED)
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Code to move the child out of panel1
End Sub
End Class
Thank you #john for your help, I have been able to get it working now.
Kind regards,
Eric
Imports System.Runtime.InteropServices
Public Class Form1
Private WithEvents proc As Process
Public Const SW_SHOWMAXIMIZED As UInt32 = 3
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function DwmGetWindowAttribute Lib "dwmapi" (ByVal hwnd As IntPtr, ByVal dwAttribute As Integer, ByRef pvAttribute As RECT, ByVal cbAttribute As Integer) As Integer
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal nCmdShow As Int32) As Boolean
Public Structure RECT
Public left, top, right, bottom As Integer
End Structure
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
proc.EnableRaisingEvents = True
proc.StartInfo.FileName = "cmd"
proc.Start()
End Sub
Private Sub Tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Shown
proc.WaitForExit(200)
If SetParent(proc.MainWindowHandle, Panel1.Handle) <> IntPtr.Zero Then
SetWindowPos(proc.MainWindowHandle, IntPtr.Zero, 0, 0, Width, Height, 0)
ShowWindow(proc.MainWindowHandle, SW_SHOWMAXIMIZED)
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SetParent(proc.MainWindowHandle, IntPtr.Zero)
End Sub
End Class

Autotyper only types on selected window

I am relatively new to VB. Honestly below is mainly from reading tutorials.
What I'm trying to create is an autotyper that can type on the selected window in my ComboBox.
Right now, it get's the windows title in the ComboBox and I can select one, but when I click start on my autotyper, it only types on the screen that is currently at the top. I want it to be able to only type on the screen that is selected, even if the program is in the background. My only problem is getting my program to type on the window that is selected in the ComboBox.
I've searched about SelectItem but can't find where to put the code, let alone know what to put there. I've literally searched different things for 2 days straight and couldn't figure anything out even with the help of a friend.
Imports System.Runtime.InteropServices
Imports System.Diagnostics
Public Class W1
Public Declare Function EnumWindows Lib "user32.dll" (ByVal lpEnumFunc As EnumWindowsProc, ByVal lParam As Int32) As Int32
Public Declare Function IsWindowVisible Lib "user32.dll" (ByVal hwnd As IntPtr) As Boolean
Public Delegate Function EnumWindowsProc(ByVal hwnd As IntPtr, ByVal lParam As Int32) As Boolean
Public Declare Function GetWindowText Lib "user32.dll" Alias "GetWindowTextA" (ByVal hwnd As IntPtr, ByVal lpString As String, ByVal cch As Int32) As Int32
Public Declare Function GetWindowTextLength Lib "user32.dll" Alias "GetWindowTextLengthA" (ByVal hwnd As IntPtr) As Int32
Public Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As IntPtr, ByVal nIndex As Int32) As Int32
Public Declare Function GetParent Lib "user32.dll" (ByVal intptr As IntPtr) As IntPtr
Private Declare Function GetWindowRect Lib "user32.dll" (ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
Public Property SelectedItem As Object
Public Const GWL_HWNDPARENT As Int32 = -8
Private newwindowlist As List(Of String)
Private newhandlelist As List(Of IntPtr)
Private Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
Public Sub New(ByVal _left As Integer, ByVal _top As Integer, ByVal _right As Integer, ByVal _bottom As Integer)
left = _left
top = _top
right = _right
bottom = _bottom
End Sub
End Structure
Private Function EnumWinProc(ByVal hwnd As IntPtr, ByVal lParam As Int32) As Boolean
If IsWindowVisible(hwnd) Then
If GetParent(hwnd) = IntPtr.Zero Then
If GetWindowLong(hwnd, GWL_HWNDPARENT) = 0 Then
Dim str As String = String.Empty.PadLeft(GetWindowTextLength(hwnd) + 1)
GetWindowText(hwnd, str, str.Length)
If Not String.IsNullOrEmpty(str.Substring(0, str.Length - 1)) Then
newwindowlist.Add(str.Substring(0, str.Length - 1))
End If
End If
End If
End If
EnumWinProc = True
End Function
Private Sub RefreshWindowList()
newwindowlist = New List(Of String)
EnumWindows(AddressOf EnumWinProc, CInt(True))
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
RefreshWindowList()
For Each item As String In newwindowlist
ComboBox1.Items.Add(item)
Next
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
SendKeys.Send(TextBox1.Text)
SendKeys.Send("{Enter}")
End Sub
Private Sub StartButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartButton.Click
Timer1.Interval = TextBox2.Text * 1000
Timer1.Start()
End Sub
Private Sub StopButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StopButton.Click
Timer1.Stop()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs)
End Sub
Private Sub ComboBox1_SelectedIndexChanged_1(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
ComboBox1.Text = ComboBox1.SelectedItem
End Sub
End Class
The problem is that when you click on the botton on your program, focus is there, not on the other window anymore. SendKeys always works against the window/control with focus, just like you were typing on a keyboard.
If you were typing a letter in MS Word, then clicked on Notepad, and continued to type, you wouldn't expect to be typing in MS Word. This is the same thing.
What you want to do is use something like AppActivate to activate the window you want first. This takes a window name or process id, and it looks like you know how to get those already.

VB.NET SendMessage to Another Form in Project

I have a 3 form project.
I want form3 to use sendmessage to form2 but i can't ever get it to work.
If it makes any difference form2 has a flash object on it (a game particularly) i want to send those keys to it.
here is a bit of what i have and i don't know why it doesn't work:
Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpwindowname As String) As IntPtr
Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As IntPtr
Const WM_KEYDOWN As Integer = &H100
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim destination As IntPtr = FindWindow(Nothing, Window)
SendMessage(destination, WM_KEYDOWN, Keys.Down, 0)
End Sub
To clarify window is a string which holds the form2.text.
Why not add a simple method in form2 and then when keydown is used in form3 call that method.
Let's say a key is press in form3 so you have the code:
Private Sub Form3_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
If (e.KeyCode = Keys.Down) Then
Form2.KeyIsPress()
End If
End Sub
So, in your Form2 you add the method KeyIsPress()
Public Sub KeyIsPress()
MessageBox.Show("Key Down is Press")
End Sub
I assume that both forms (i.e. Form2 and Form3) are running.

Error Getting Form Handler (Vb.net)

I have the current code:
Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function SendMessage(ByVal hWnd As HandleRef, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As String) As IntPtr
End Function
Declare Auto Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Public Function WindowHandle(ByVal sTitle As String) As Long
WindowHandle = FindWindow(vbNullString, sTitle)
End Function
Dim CurrentProcess As Process
Dim CurrentHandle As IntPtr
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
SendMessage(CurrentHandle, 256, Keys.A, 0)
SendMessage(CurrentHandle, 257, Keys.A, 65539)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
CurrentProcess = Process.GetProcessesByName(ListBox1.SelectedItem.ToString.Remove(0, ListBox1.SelectedItem.ToString.IndexOf("{") + 1).Replace("}", ""))(0)
CurrentHandle = New IntPtr(WindowHandle(CurrentProcess.MainWindowTitle))
Timer1.Start()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
If you take a look at the button sub, every time it runs, it errors with "Arithmetic overflow error!"
What is wrong here? This should work... right?
Sorry, this is a bit vague but it's as much as I know.
Your Declare statements are correct but the way you call them is not. The loose typing allowed by VB.NET is getting you in trouble, the kind you can't diagnose. The cure for that is letting the compiler tell you that you did it wrong. Put this at the top of your source code file:
Option Strict On