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
Related
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
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
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.
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.
I have an Vb.net application made by a third party , that I need to control using outside resources from a simulated environment and must not interact with the desktop. To simulate inputs that a user would normally input from a special screen with specific keys around it, I've built a test control library to control it and send the form image to a .bmp. The form cannot be visible and showed in taskbar , the bmp output will be displayed by the simulated environment.
Using PostMessage and sendKeys work well as long as I don't but ShowInTaskbar = False for the main form. After many read & testing, I have learned enough to try what seems to be the only thing that would work. I've created a form that I setparent using HWND_MESSAGE parameter, this should create a Message-Only Windows, that are supposed to received postMessage, and subclass it's events.msdn.
StackOverflow already about this
Unfortunately , I can't seem to get it to work, and I was hoping someone could tell me what I'm doing wrong.I have been testing several different ways found through out the web about .net , and short of going into message thread peek and feed(maybe(may be)my last hope), they all seem to work until I take the forms out of the taskbar.
Ok, here are the code:
The MsgOnly.vb
Public Class MsgHandling
DllImport("user32.dll", SetLastError:=True,CharSet:=CharSet.Auto)> _
Public Shared Function SetParent(ByVal hWndChild As IntPtr,
ByVal hWndNewParent As IntPtr) As
IntPtr
End Function
Private Shared HWND_MESSAGE As IntPtr = New IntPtr(-3)
Public Event CallBackProc(ByRef m As Message)
Public Sub setParent()
SetParent(Me.Handle, HWND_MESSAGE)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
RaiseEvent CallBackProc(m) 'then RaiseEvent
MyBase.WndProc(m)
End Sub
End Class
Part subclassing in the form(Can't show more than what handles the sub classing, privacy issues. Hopefully this will suffice )
Public WithEvents Msg As New MsgHandling
Private Sub XXXXX_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'----snips
Msg.setParent()
'----snips
end sub
Private Sub CallBackProc(ByRef m As System.Windows.Forms.Message) Handles Msg.CallBackProc
Me.Text = "Rx events " & m.LParam.ToString() & " " & m.WParam.ToString()
WndProc(m)
End Sub
Test form
Public Class Form1
<DllImport("user32.dll")> _
Private Shared Function SetForegroundWindow(ByVal hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Private Shared Function FindWindow( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
End Function
Public Shared Function SetWindowPos( _
ByVal hWnd As IntPtr, _
ByVal hWndInsertAfter As IntPtr, _
ByVal X As Int32, _
ByVal Y As Int32, _
ByVal cy As Int32, _
ByVal uFlags As Int32) _
As Boolean
End Function
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Private Declare Function AllowSetForegroundWindow Lib "user32" Alias "AllowSetForegroundWindow" (ByVal dwProcessId As Integer) As Boolean
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
Public myProcess As Process = New Process()
Private Const WM_KEYDOWN As Long = 100
Private Const WM_RBUTTONDOWN As Long = 204
Public Shared HWND_MESSAGE As IntPtr = New IntPtr(-3)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
myProcess.StartInfo.FileName = "...\XXXXXX.exe" 'Not real name
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal
myProcess.EnableRaisingEvents = True
AddHandler myProcess.Exited, AddressOf Me.SendKeysTestExited
myProcess.Start()
End Sub
Friend Sub SendKeysTestExited(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim myRxProcess As Process = DirectCast(sender, Process)
myRxProcess.Close()
End Sub
Private Sub Form1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
Dim tHwnd As Long
Dim rslt As Boolean
If myProcess.Responding Then
tHwnd = FindWindowEx(HWND_MESSAGE, 0, 0, 0)
PostMessage(HWND_MESSAGE, WM_RBUTTONDOWN, 0, "TEXT TO SEND")
Else
myProcess.Kill()
End If
End Sub
Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
myProcess.Close()
End Sub
End Class
Not really sure what other details I can provide for now. Anyone as any idea or ways I haven't found?
Thanks for any input
I've found a work around. It seems like the problem comes from the fact that the windows handle is not find with the search functions. I have tried several ways, but since message-only are not enumerated, I can't loop, or at least I wasn't successful.
So I create a file with the handle, that the external program reads and the use that handle to make the PostMessage. This works well for now. I wish I could find a better way, but at least I have something to propose as a solution.
I'm still open to suggestion or other possible workaround:).