Public Class frm_main
Private Const APPCOMMAND_MICROPHONE_VOLUME_MUTE As Integer = &H180000
Private Const WM_APPCOMMAND As Integer = &H319
Declare Function SendMessageW Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Private Sub btn_mute_Click(sender As Object, e As EventArgs) Handles btn_mute.Click
SendMessageW(Me.Handle, WM_APPCOMMAND, Me.Handle, CType(APPCOMMAND_MICROPHONE_VOLUME_MUTE, IntPtr))
End Sub
End Class
It doesn't work, but I can mute the speaker.
Related
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
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 have this code but I don't know why it doesn't work, can anyone help me? I need to send ctrl + f to another application in the background
Imports System.Runtime.InteropServices
Public Class Form2
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Const WM_CHAR = &H102
Private Const WM_SYSKEYDOWN = &H104
Private Const WM_SYSKEYUP = &H105
Private Const VK_SHIFT = &H10
Private Const VK_CONTROL = &H11
Private Const KEYEVENTF_EXTENDEDKEY = &H1
Private Const KEYEVENTF_KEYUP = &H2
Private Const KEYEVENTF_KEYDOWN = &H0
Private Const VK_F = &H46
Private Const WM_SETTEXT = &HC
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Shared Function FindWindowEx(ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal lclassName As String, ByVal windowTitle As String) As IntPtr
End Function
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)
Public Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Integer, ByVal wMapType As Integer) As Byte
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim hPadre As IntPtr = FindWindowEx(IntPtr.Zero, hPadre, "Notepad", "Sin título: Bloc de notas")
Dim hCarpetas As IntPtr = FindWindowEx(hPadre, hCarpetas, "Edit", vbNullString)
keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYDOWN, 0)
PostMessage(hPadre, WM_KEYDOWN, VK_F, 0)
keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYUP, 0)
End Sub
I also have this example, but it doesn't work :(
Imports System.Runtime.InteropServices
Public Class Form1
Private Const VK_CONTROL As Integer = 17
Private Const KEYEVENTF_KEYUP As Integer = &H2
Private Const INPUT_MOUSE As Integer = 0
Private Const INPUT_KEYBOARD As Integer = 1
Private Const INPUT_HARDWARE As Integer = 2
Private Const WM_KEYDOWN As Integer = &H100
Private Structure MOUSEINPUT
Public dx As Integer
Public dy As Integer
Public mouseData As Integer
Public dwFlags As Integer
Public time As Integer
Public dwExtraInfo As IntPtr
End Structure
Private Structure KEYBDINPUT
Public wVk As Integer
Public wScan As Integer
Public dwFlags As Integer
Public time As Integer
Public dwExtraInfo As IntPtr
End Structure
Private Structure HARDWAREINPUT
Public uMsg As Integer
Public wParamL As Integer
Public wParamH As Integer
End Structure
<StructLayout(LayoutKind.Explicit)>
Private Structure INPUT
<FieldOffset(0)>
Public type As Integer
<FieldOffset(4)>
Public mi As MOUSEINPUT
<FieldOffset(4)>
Public ki As KEYBDINPUT
<FieldOffset(4)>
Public hi As HARDWAREINPUT
End Structure
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Shared Function FindWindowEx(ByVal parentHandle As IntPtr, ByVal childAfter As IntPtr, ByVal lclassName As String, ByVal windowTitle As String) As IntPtr
End Function ' Dany
Private Declare Function SendInput Lib "user32" (ByVal nInputs As Integer, ByVal pInputs() As INPUT, ByVal cbSize As Integer) As Integer
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As IntPtr, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Integer, ByVal bScan As Byte, ByVal dwFlags As IntPtr, ByVal dwExtraInfo As IntPtr)
Private Sub wait(ByVal interval As Integer)
Dim sw As New Stopwatch
sw.Start()
Do While sw.ElapsedMilliseconds < interval
' Allows UI to remain responsive
Application.DoEvents()
Loop
sw.Stop()
End Sub
Private Sub SendKey(ByVal bKey As Integer)
Dim GInput(0) As INPUT
' press the key
GInput(0).type = INPUT_KEYBOARD
GInput(0).ki.wVk = bKey
GInput(0).ki.dwFlags = 0
SendInput(2, GInput, Marshal.SizeOf(GetType(INPUT)))
End Sub
Sub Press_Control()
wait(2000)
Dim b As Integer
b = VK_CONTROL
SendKey(b)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim hPadre As IntPtr = FindWindowEx(IntPtr.Zero, hPadre, "Notepad", "Sin título: Bloc de notas")
Dim hCarpetas As IntPtr = FindWindowEx(hPadre, hCarpetas, "Edit", vbNullString)
Press_Control()
SendMessage(hPadre, WM_KEYDOWN, 70, 0)
wait(1000)
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0)
End Sub
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 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