GetWindowText is returning nothing - vb.net

In one of my project I have to get the title of foreground window so I called GetForegroundWindow() Entry Point form User32.dll for getting the windows Handle then I called GetWindowText() for the title everything goes error less but the output comes nothing, here is the code I am using in my VB.NET program.
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("user32.dll")> _
Private Shared Function GetForegroundWindow() As IntPtr
End Function
<DllImport("user32.dll")> _
Private Shared Function GetWindowText(ByVal hwnd As Long, ByVal lpString As System.Text.StringBuilder, ByVal cch As Long) As Integer
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim hWnd As IntPtr
hWnd = GetForegroundWindow()
Dim title As New System.Text.StringBuilder(256)
GetWindowText(hWnd, title, title.Capacity)
Me.Text = title.ToString
End Sub
End Class

I found the solution myself, It was the fault in the hWnd parameter as Long value for proper functioning of the program it has to be IntPtr. The new correct code looks something like this.
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("user32.dll")> _
Private Shared Function GetForegroundWindow() As IntPtr
End Function
<DllImport("user32.dll")> _
Private Shared Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As System.Text.StringBuilder, ByVal cch As Long) As Integer
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim hWnd As IntPtr
hWnd = GetForegroundWindow()
Dim title As New System.Text.StringBuilder(256)
GetWindowText(hWnd, title, title.Capacity)
Me.Text = title.ToString
End Sub
End Class

Related

How to resize a parent form and panel to fit a child window

I use the code below to start a cmd.exe windows and move it into a panel after execution. At this moment, the child window is resized to fit into Panel1 on my Form1. I would like it to be the other way around: my Form1 (and thus Panel1) should resize to fit the size of the child window, so no matter what the size of the default cmd.exe window is on the local computer.
Does anybody know how I should do that?
Thanks for any help in advance!
Kind regards,
Eric
Imports System.Runtime.InteropServices
Public Class Form1
Private WithEvents Tmr As New Timer With {.Interval = 100}
Private Const HWND_BOTTOM As Integer = &H1
Private WithEvents proc As New Process
<DllImport("user32.dll", EntryPoint:="SetParent")>
Private Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="SetWindowPos")>
Private Shared Function SetWindowPos(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
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Text = "My title"
proc.EnableRaisingEvents = True
proc.StartInfo.FileName = "cmd"
proc.Start()
Tmr.Start()
End Sub
Private Sub Tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Tmr.Tick
If SetParent(proc.MainWindowHandle, Panel1.Handle) <> IntPtr.Zero Then
Tmr.Stop()
SetWindowPos(proc.MainWindowHandle, New IntPtr(HWND_BOTTOM), 0, 0, Panel1.ClientSize.Width, Panel1.ClientSize.Height, 0)
End If
End Sub
Private Sub Proc_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles proc.Exited
Invoke(Sub() Close())
End Sub
End Class
As suggested by #Jimi, I used DwmGetWindowAttribute to retrieve the size of the child, before moving it into the panel. Afterwards I use ShowWindow to maximize it, to get rid of the borders.
The changed code can be found in a different post of mine.

Unable to find RECT size with DwmGetWindowAttribute

I'm trying to find to find the size of the cmd.exe window which is started as a child. I like to use this size to resize my form accordingly. For some reason the size returned by DwmGetWindowAttribute is always zero, so I must be doing something wrong here, but I can't find it. Any help will be greatly appreciated.
Kind regards,
Eric
Imports System.Runtime.InteropServices
Public Class Form1
Private WithEvents Tmr As New Timer With {.Interval = 100}
Private Const HWND_BOTTOM As Integer = &H1
Private WithEvents proc As New Process
Public Const DWMWA_EXTENDED_FRAME_BOUNDS As Integer = 9
<DllImport("user32.dll", EntryPoint:="SetParent")>
Private Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="SetWindowPos")>
Private Shared Function SetWindowPos(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
End Function
<DllImport("dwmapi.dll")>
Shared Function DwmGetWindowAttribute(ByVal hwnd As IntPtr, ByVal dwAttribute As Integer, ByRef pvAttribute As RECT, ByVal cbAttribute As Integer) As Integer
End Function
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
Me.Text = "My title"
proc.EnableRaisingEvents = True
proc.StartInfo.FileName = "cmd"
proc.Start()
Tmr.Start()
End Sub
Private Sub Tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Tmr.Tick
If SetParent(proc.MainWindowHandle, Panel1.Handle) <> IntPtr.Zero Then
Tmr.Stop()
Dim Width As Integer
Dim Hight As Integer
Dim WindowRect As New RECT
DwmGetWindowAttribute(proc.MainWindowHandle, DWMWA_EXTENDED_FRAME_BOUNDS, WindowRect, Marshal.SizeOf(WindowRect))
Width = WindowRect.right - WindowRect.left
Hight = WindowRect.bottom - WindowRect.top
MessageBox.Show("Hight: " & Hight & " Width: " & Width)
'Me.Size = New Size(Width, Hight)
SetWindowPos(proc.MainWindowHandle, New IntPtr(HWND_BOTTOM), 0, 0, Panel1.ClientSize.Width, Panel1.ClientSize.Height, 0)
End If
End Sub
Private Sub Proc_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles proc.Exited
Invoke(Sub() Close())
End Sub
End Class
After implementing all valuable additions of #Jimi, this is the code that works:
Imports System.Runtime.InteropServices
Public Class Form1
Private WithEvents proc As New Process
Public Const WM_NCLBUTTONDOWN As Long = &HA1
Public Const SW_SHOWMAXIMIZED As UInt32 = 3
Public Const WM_CLOSE = &H10
Public Const DWMWA_EXTENDED_FRAME_BOUNDS As Integer = 9
'Function to set the parent window
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
'Function to set the child window position
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
'Function to allow the child to be maximized
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal nCmdShow As Int32) As Boolean
'Function to retrieve the initail child size
Private Declare Function DwmGetWindowAttribute Lib "dwmapi" (ByVal hwnd As IntPtr, ByVal dwAttribute As Integer, ByRef pvAttribute As RECT, ByVal cbAttribute As Integer) As Integer
'Function to set focus to the child window
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As IntPtr) As Long
'Function used to set terminate child window
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
'Rectangle size, used later to resize the form
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
Me.Text = "My title"
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
'Wait for 200 ms for the form to load
proc.WaitForExit(200)
Dim WindowRect As New RECT
Dim Width, Hight As Integer
'Retrieve the initial size of the child window
DwmGetWindowAttribute(proc.MainWindowHandle, DWMWA_EXTENDED_FRAME_BOUNDS, WindowRect, Marshal.SizeOf(WindowRect))
Width = WindowRect.right - WindowRect.left
Hight = WindowRect.bottom - WindowRect.top + 23
'Set the form size to the initial size of the child window
Me.Size = New Size(Width, Hight)
'When the child is started, move the child into the panel and maximize it
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
'Exit form when child terminates
Private Sub Proc_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles proc.Exited
Invoke(Sub() Close())
End Sub
'Set focus on child when the form is activated
Private Sub Form1_UnFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Activated
SetForegroundWindow(proc.MainWindowHandle)
End Sub
'Set focus on child when the parent titlebar is clicked
Protected Overrides Sub DefWndProc(ByRef m As System.Windows.Forms.Message)
If CLng(m.Msg) = WM_NCLBUTTONDOWN Then
SetForegroundWindow(proc.MainWindowHandle)
End If
MyBase.DefWndProc(m)
End Sub
'Properly terminate child when the form is closed by the user
Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Closed
SendMessage(proc.MainWindowHandle, WM_CLOSE, 0, 0)
End Sub
End Class
Kind regards,
Eric

The lparam and wparam parameters in this specific sendmessage function?

I was going through this code here and:
Private Sub Button3_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button3.Click
SendMessage(Me.Handle, WM_APPCOMMAND, &H200EB0,
APPCOMMAND_VOLUME_MUTE * &H10000)
End Sub
I have no idea what the last two parameters of the sendmessage functions are and what is going on in these two parameters? the "&H200EB0" and "APPCOMMAND_VOLUME_MUTE * &H10000" Parameters?
Here's the full code:
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Private Shared Function SendMessage(ByVal hWnd As IntPtr,
ByVal Msg As UInteger, ByVal wParam As IntPtr,
ByVal lParam As IntPtr) As IntPtr
End Function
Const WM_APPCOMMAND As UInteger = &H319
Const APPCOMMAND_VOLUME_UP As UInteger = &HA
Const APPCOMMAND_VOLUME_DOWN As UInteger = &H9
Const APPCOMMAND_VOLUME_MUTE As UInteger = &H8
Private Sub Button1_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
SendMessage(Me.Handle, WM_APPCOMMAND, &H30292,
APPCOMMAND_VOLUME_UP * &H10000)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button2.Click
SendMessage(Me.Handle, WM_APPCOMMAND, &H30292,
APPCOMMAND_VOLUME_DOWN * &H10000)
End Sub
Private Sub Button3_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button3.Click
SendMessage(Me.Handle, WM_APPCOMMAND, &H200EB0,
APPCOMMAND_VOLUME_MUTE * &H10000)
End Sub
End Class
SendMessage is a method which can be used to send a specified message to a window or windows.
Documentation is here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644950%28v=vs.85%29.aspx
The first parameter is the "handle" (HWND) to which the message is send. The second parameter is a message id (see http://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx#system_defined for System-Defined Messages).
The last two parameters can be used to pass more data to the receiver. - Normally both parameters have message dependent meanings.
In your case the WM_APPCOMMAND message (http://msdn.microsoft.com/en-us/library/windows/desktop/ms646275%28v=vs.85%29.aspx) is passed (here it is a keyboard command). I think the first parameter could also be NULL (according to the link above it should be a handle to the window where the user clicked the button or pressed the key), but the second one has to specify the command which should be passed (as an APPCOMMAND). The second parameter is 8 (8=APPCOMMAND_VOLUME_MUTE according to the list on the linked page), however we have to do a bitshift, because the information has to be encoded in the high-order bits of the parameter (i.e., 0x80000 - that's APPCOMMAND_VOLUME_MUTE*&H10000; see lParam section on the page I linked).

Reducing all sound volumes except for my own app

I'm wondering if it would be possible to simulate iPhone notification sounds on VB.NET, in the sense of how they are handled.
For example, if you get a SMS message on iPhone, while listening to music, the music volume is lowered to about 25% while the alert is played, then the volume is restored.
Could this be done with vb.net?
I've seen ways to reduce the system volume, but wouldn't this reduce the volume for my app as well?
I found this which works great, but I'd like to know if I can separate my app from this
Imports System
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Namespace WindowsFormsApplication1
Partial Public Class Form1
Inherits Form
Private Const APPCOMMAND_VOLUME_MUTE As Integer = &H80000
Private Const APPCOMMAND_VOLUME_UP As Integer = &HA0000
Private Const APPCOMMAND_VOLUME_DOWN As Integer = &H90000
Private Const WM_APPCOMMAND As Integer = &H319
<DllImport("user32.dll")> _
Public Shared Function SendMessageW(ByVal hWnd As IntPtr, _
ByVal Msg As Integer, ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As IntPtr
End Function
Private Sub btnMute_Click(ByVal sender As Object, ByVal e As EventArgs)
SendMessageW(Me.Handle, WM_APPCOMMAND, _
Me.Handle, New IntPtr(APPCOMMAND_VOLUME_MUTE))
End Sub
Private Sub btnDecVol_Click(ByVal sender As Object, ByVal e As EventArgs)
SendMessageW(Me.Handle, WM_APPCOMMAND, _
Me.Handle, New IntPtr(APPCOMMAND_VOLUME_DOWN))
End Sub
Private Sub btnIncVol_Click(ByVal sender As Object, ByVal e As EventArgs)
SendMessageW(Me.Handle, WM_APPCOMMAND, _
Me.Handle, New IntPtr(APPCOMMAND_VOLUME_UP))
End Sub
End Class
End Namespace

Change Internet explorer volume programmatically. .net

With the following code you can change the volume on a Windows PC. But it changes the global volume.
I would like to change the slider value of Internet Explorer in the Mixer settings. can this be done?
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function
Const WM_APPCOMMAND As UInteger = &H319
Const APPCOMMAND_VOLUME_UP As UInteger = &HA
Const APPCOMMAND_VOLUME_DOWN As UInteger = &H9
Const APPCOMMAND_VOLUME_MUTE As UInteger = &H8
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
SendMessage(Me.Handle, WM_APPCOMMAND, &H30292, APPCOMMAND_VOLUME_UP * &H10000)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
SendMessage(Me.Handle, WM_APPCOMMAND, &H30292, APPCOMMAND_VOLUME_DOWN * &H10000)
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
SendMessage(Me.Handle, WM_APPCOMMAND, &H200EB0, APPCOMMAND_VOLUME_MUTE * &H10000)
End Sub
End Class
I found a similar answer somewhere else with a large C# example, you should be able to run this through a C# to vb.net converter and get what you're looking for (the person in this example is trying to control FireFox's volume, so essentially exactly what you're looking for).
Controling Volume Mixer