Reducing all sound volumes except for my own app - vb.net

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

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.

VB.Net Hidden Program Hotkeys

Is there a way to register hotkeys to toggle a form from an invisible(hidden) program? I’ve tired normal methods and they only work when the form is either visible, or the active window. Thank you in advance for any help!
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.KeyPreview = True
Me.ShowInTaskbar = False
Me.ShowIcon = False
Me.Visible = False
End Sub
This is the code that hides the program.
You want to use Global Hotkeys. Just make sure you unregister when the program closes.
From a MSDN article that helped me in the past:
Firstly, you need to know the Virtual-Key Codes.
http://msdn2.microsoft.com/en-us/library/ms927178.aspx You can then
P/Invoke RegisterHotKey/UnregisterHotKey APIs to register/Unregister
the hotkey. Code sample: Register multiple hotkeys such as Alt+D,
Alt+C, etc.
Imports System.Runtime.InteropServices
Public Class Form1
Public Const MOD_ALT As Integer = &H1 'Alt key
Public Const WM_HOTKEY As Integer = &H312
<DllImport("User32.dll")> _
Public Shared Function RegisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer, ByVal fsModifiers As Integer, _
ByVal vk As Integer) As Integer
End Function
<DllImport("User32.dll")> _
Public Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, _
ByVal id As Integer) As Integer
End Function
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
RegisterHotKey(Me.Handle, 100, MOD_ALT, Keys.D)
RegisterHotKey(Me.Handle, 200, MOD_ALT, Keys.C)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_HOTKEY Then
Dim id As IntPtr = m.WParam
Select Case (id.ToString)
Case "100"
MessageBox.Show("You pressed ALT+D key combination")
Case "200"
MessageBox.Show("You pressed ALT+C key combination")
End Select
End If
MyBase.WndProc(m)
End Sub
Private Sub Form1_FormClosing(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) _
Handles MyBase.FormClosing
UnregisterHotKey(Me.Handle, 100)
UnregisterHotKey(Me.Handle, 200)
End Sub
End Class

Topmost window over everything, except child processes

My program is full screen and topmost, and I would like all the child processes of that window to be above my program's main window. The processes are unknown, and external.
I can launch the process using System.Diagnostics.Process.Start(exeName,procArgs).WaitForExit(), but from there I am stuck.
Basically you use the SetParent() API to make the external app a child of yours. Here I'm also using the GetWindowRect() and SetWindowPos() APIs to keep the window in the same launch position after its parent is changed. Finally, you need to keep track of the processes and close them manually so they do not become orphaned when the form is closed:
Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Public Class Form1
Private Const SWP_NOSIZE As Integer = &H0001
<StructLayout(LayoutKind.Sequential)>
Public Structure RECT
Public Left As Integer, Top As Integer, Right As Integer, Bottom As Integer
End Structure
<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")>
Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)>
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 Integer) As Boolean
End Function
Private Ps As New List(Of Process)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim exeName As String = "Notepad"
Dim procArgs As String = ""
LaunchExe(exeName, procArgs)
End Sub
Private Sub LaunchExe(ByVal exeName As String, ByVal procArgs As String)
Try
Dim p As Process = System.Diagnostics.Process.Start(exeName, procArgs)
If Not IsNothing(p) Then
p.WaitForInputIdle()
Dim rc As RECT
GetWindowRect(p.MainWindowHandle, rc)
Dim pt As New Point(rc.Left, rc.Top)
pt = Me.PointToClient(pt)
SetParent(p.MainWindowHandle, Me.Handle)
SetWindowPos(p.MainWindowHandle, 0, pt.X, pt.Y, 0, 0, SWP_NOSIZE)
Ps.Add(p)
End If
Catch ex As Exception
MessageBox.Show(exeName & vbCrLf & procArgs, "Error Starting Application")
End Try
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Me.Close()
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
For Each P As Process In Ps
If Not P.HasExited Then
P.CloseMainWindow()
End If
Next
End Sub
End Class

GetWindowText is returning nothing

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

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