Compare commits
3 Commits
4c1ccd9025
...
d1df235af0
Author | SHA1 | Date | |
---|---|---|---|
d1df235af0 | |||
6aaa32cf92 | |||
4ca0ad021f |
@ -1,12 +1,8 @@
|
|||||||
using BarRaider.SdTools;
|
using FocusVolumeControl.AudioSessions;
|
||||||
using FocusVolumeControl.AudioSessions;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace FocusVolumeControl.AudioHelpers;
|
namespace FocusVolumeControl.AudioHelpers;
|
||||||
|
|
||||||
@ -27,6 +23,18 @@ public class AudioHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Process GetProcessById(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Process.GetProcessById(id);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IAudioSession FindSession(List<Process> processes)
|
public IAudioSession FindSession(List<Process> processes)
|
||||||
{
|
{
|
||||||
var results = new ActiveAudioSessionWrapper();
|
var results = new ActiveAudioSessionWrapper();
|
||||||
@ -55,7 +63,12 @@ public class AudioHelper
|
|||||||
sessionEnumerator.GetSession(i, out var session);
|
sessionEnumerator.GetSession(i, out var session);
|
||||||
|
|
||||||
session.GetProcessId(out var sessionProcessId);
|
session.GetProcessId(out var sessionProcessId);
|
||||||
var audioProcess = Process.GetProcessById(sessionProcessId);
|
var audioProcess = GetProcessById(sessionProcessId);
|
||||||
|
|
||||||
|
if(audioProcess == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var index = processes.FindIndex(x => x.Id == sessionProcessId || x.ProcessName == audioProcess?.ProcessName);
|
var index = processes.FindIndex(x => x.Id == sessionProcessId || x.ProcessName == audioProcess?.ProcessName);
|
||||||
|
|
||||||
@ -68,7 +81,14 @@ public class AudioHelper
|
|||||||
{
|
{
|
||||||
bestProcessMatch = audioProcess;
|
bestProcessMatch = audioProcess;
|
||||||
currentIndex = index;
|
currentIndex = index;
|
||||||
|
|
||||||
|
if(string.IsNullOrEmpty(results.DisplayName))
|
||||||
|
{
|
||||||
|
session.GetDisplayName(out var displayName);
|
||||||
|
results.DisplayName = displayName;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//some apps like discord have multiple volume processes.
|
//some apps like discord have multiple volume processes.
|
||||||
//and some apps will be on multiple devices
|
//and some apps will be on multiple devices
|
||||||
@ -92,7 +112,7 @@ public class AudioHelper
|
|||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
var processes = GetPossibleProcesses();
|
var processes = GetPossibleProcesses();
|
||||||
var processIds = processes.Select(x => x.Id).ToArray();
|
var processIds = processes?.Select(x => x.Id).ToArray();
|
||||||
|
|
||||||
if (_currentProcesses == null || !_currentProcesses.SequenceEqual(processIds))
|
if (_currentProcesses == null || !_currentProcesses.SequenceEqual(processIds))
|
||||||
{
|
{
|
||||||
@ -138,7 +158,7 @@ public class AudioHelper
|
|||||||
|
|
||||||
if (handle == IntPtr.Zero)
|
if (handle == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
return null;
|
return new List<Process>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var ids = Native.GetProcessesOfChildWindows(handle);
|
var ids = Native.GetProcessesOfChildWindows(handle);
|
||||||
@ -150,6 +170,11 @@ public class AudioHelper
|
|||||||
.Select(x => Process.GetProcessById(x))
|
.Select(x => Process.GetProcessById(x))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
if(processes.FirstOrDefault()?.ProcessName == "explorer")
|
||||||
|
{
|
||||||
|
return new List<Process>();
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//note. in instances where you launch a game from steam. this ends up mapping the process to both steam and to the game. which is unfortunate
|
//note. in instances where you launch a game from steam. this ends up mapping the process to both steam and to the game. which is unfortunate
|
||||||
|
@ -26,10 +26,13 @@ public class NameAndIconHelper
|
|||||||
var appx = AppxPackage.FromProcess(process);
|
var appx = AppxPackage.FromProcess(process);
|
||||||
if (appx == null)
|
if (appx == null)
|
||||||
{
|
{
|
||||||
//usingg process.MainModule.FileVersionInfo sometimes throws permission exceptions
|
//using process.MainModule.FileVersionInfo sometimes throws permission exceptions
|
||||||
//we get the file version info with a limited query flag to avoid that
|
//we get the file version info with a limited query flag to avoid that
|
||||||
var fileVersionInfo = GetFileVersionInfo(process);
|
var fileVersionInfo = GetFileVersionInfo(process);
|
||||||
|
|
||||||
|
//if the display name is already set, then it came from the display name of the audio session
|
||||||
|
if (string.IsNullOrEmpty(results.DisplayName))
|
||||||
|
{
|
||||||
results.DisplayName = process.MainWindowTitle;
|
results.DisplayName = process.MainWindowTitle;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(results.DisplayName))
|
if (string.IsNullOrEmpty(results.DisplayName))
|
||||||
@ -40,6 +43,7 @@ public class NameAndIconHelper
|
|||||||
results.DisplayName = process.ProcessName;
|
results.DisplayName = process.ProcessName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
results.ExecutablePath = fileVersionInfo?.FileName;
|
results.ExecutablePath = fileVersionInfo?.FileName;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using BarRaider.SdTools;
|
using BarRaider.SdTools;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using FocusVolumeControl.UI;
|
||||||
|
|
||||||
namespace FocusVolumeControl.AudioSessions;
|
namespace FocusVolumeControl.AudioSessions;
|
||||||
|
|
||||||
@ -31,8 +32,9 @@ public sealed class ActiveAudioSessionWrapper : IAudioSession
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var tmp = Icon.ExtractAssociatedIcon(ExecutablePath);
|
var tmp = IconExtraction.GetIcon(ExecutablePath);
|
||||||
_icon = Tools.ImageToBase64(tmp.ToBitmap(), true);
|
//var tmp = Icon.ExtractAssociatedIcon(ExecutablePath);
|
||||||
|
_icon = Tools.ImageToBase64(tmp, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
<Compile Include="AudioSessions\IAudioSession.cs" />
|
<Compile Include="AudioSessions\IAudioSession.cs" />
|
||||||
<Compile Include="FallbackBehavior.cs" />
|
<Compile Include="FallbackBehavior.cs" />
|
||||||
<Compile Include="AudioHelpers\NameAndIconHelper.cs" />
|
<Compile Include="AudioHelpers\NameAndIconHelper.cs" />
|
||||||
|
<Compile Include="UI\IconExtraction.cs" />
|
||||||
<Compile Include="UI\ISDConnectionExtensions.cs" />
|
<Compile Include="UI\ISDConnectionExtensions.cs" />
|
||||||
<Compile Include="Native.cs" />
|
<Compile Include="Native.cs" />
|
||||||
<Compile Include="AudioHelpers\ParentProcessUtilities.cs" />
|
<Compile Include="AudioHelpers\ParentProcessUtilities.cs" />
|
||||||
|
267
src/FocusVolumeControl/UI/IconExtraction.cs
Normal file
267
src/FocusVolumeControl/UI/IconExtraction.cs
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FocusVolumeControl.UI
|
||||||
|
{
|
||||||
|
internal class IconExtraction
|
||||||
|
{
|
||||||
|
public static Bitmap GetIcon(string path)
|
||||||
|
{
|
||||||
|
var index = GetIconIndex(path);
|
||||||
|
var handle = GetIconHandle(index);
|
||||||
|
|
||||||
|
using var icon = (Icon)Icon.FromHandle(handle).Clone();
|
||||||
|
|
||||||
|
Shell32.DestroyIcon(handle);
|
||||||
|
return icon.ToBitmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int GetIconIndex(string pszFile)
|
||||||
|
{
|
||||||
|
SHFILEINFO sfi = new SHFILEINFO();
|
||||||
|
Shell32.SHGetFileInfo(pszFile, 0, ref sfi, (uint)Marshal.SizeOf(sfi), (uint)(SHGFI.SysIconIndex | SHGFI.LargeIcon | SHGFI.UseFileAttributes));
|
||||||
|
return sfi.iIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 256*256
|
||||||
|
static IntPtr GetIconHandle(int iImage)
|
||||||
|
{
|
||||||
|
IImageList spiml = null;
|
||||||
|
Guid guil = new Guid(IID_IImageList2);//or IID_IImageList
|
||||||
|
|
||||||
|
Shell32.SHGetImageList(Shell32.SHIL_EXTRALARGE, ref guil, ref spiml);
|
||||||
|
IntPtr hIcon = IntPtr.Zero;
|
||||||
|
spiml.GetIcon(iImage, Shell32.ILD_TRANSPARENT | Shell32.ILD_IMAGE, ref hIcon);
|
||||||
|
|
||||||
|
return hIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string IID_IImageList = "46EB5926-582E-4017-9FDF-E8998DAA0950";
|
||||||
|
const string IID_IImageList2 = "192B9D83-50FC-457B-90A0-2B82A8B5DAE1";
|
||||||
|
|
||||||
|
public static class Shell32
|
||||||
|
{
|
||||||
|
|
||||||
|
public const int SHIL_LARGE = 0x0;
|
||||||
|
public const int SHIL_SMALL = 0x1;
|
||||||
|
public const int SHIL_EXTRALARGE = 0x2;
|
||||||
|
public const int SHIL_SYSSMALL = 0x3;
|
||||||
|
public const int SHIL_JUMBO = 0x4;
|
||||||
|
public const int SHIL_LAST = 0x4;
|
||||||
|
|
||||||
|
public const int ILD_TRANSPARENT = 0x00000001;
|
||||||
|
public const int ILD_IMAGE = 0x00000020;
|
||||||
|
|
||||||
|
[DllImport("shell32.dll", EntryPoint = "#727")]
|
||||||
|
public extern static int SHGetImageList(int iImageList, ref Guid riid, ref IImageList ppv);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "DestroyIcon", SetLastError = true)]
|
||||||
|
public static extern int DestroyIcon(IntPtr hIcon);
|
||||||
|
|
||||||
|
//[DllImport("shell32.dll")]
|
||||||
|
//public static extern uint SHGetIDListFromObject([MarshalAs(UnmanagedType.IUnknown)] object iUnknown, out IntPtr ppidl);
|
||||||
|
|
||||||
|
[DllImport("Shell32.dll")]
|
||||||
|
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum SHGFI : uint
|
||||||
|
{
|
||||||
|
/// <summary>get icon</summary>
|
||||||
|
Icon = 0x000000100,
|
||||||
|
/// <summary>get display name</summary>
|
||||||
|
DisplayName = 0x000000200,
|
||||||
|
/// <summary>get type name</summary>
|
||||||
|
TypeName = 0x000000400,
|
||||||
|
/// <summary>get attributes</summary>
|
||||||
|
Attributes = 0x000000800,
|
||||||
|
/// <summary>get icon location</summary>
|
||||||
|
IconLocation = 0x000001000,
|
||||||
|
/// <summary>return exe type</summary>
|
||||||
|
ExeType = 0x000002000,
|
||||||
|
/// <summary>get system icon index</summary>
|
||||||
|
SysIconIndex = 0x000004000,
|
||||||
|
/// <summary>put a link overlay on icon</summary>
|
||||||
|
LinkOverlay = 0x000008000,
|
||||||
|
/// <summary>show icon in selected state</summary>
|
||||||
|
Selected = 0x000010000,
|
||||||
|
/// <summary>get only specified attributes</summary>
|
||||||
|
Attr_Specified = 0x000020000,
|
||||||
|
/// <summary>get large icon</summary>
|
||||||
|
LargeIcon = 0x000000000,
|
||||||
|
/// <summary>get small icon</summary>
|
||||||
|
SmallIcon = 0x000000001,
|
||||||
|
/// <summary>get open icon</summary>
|
||||||
|
OpenIcon = 0x000000002,
|
||||||
|
/// <summary>get shell size icon</summary>
|
||||||
|
ShellIconSize = 0x000000004,
|
||||||
|
/// <summary>pszPath is a pidl</summary>
|
||||||
|
PIDL = 0x000000008,
|
||||||
|
/// <summary>use passed dwFileAttribute</summary>
|
||||||
|
UseFileAttributes = 0x000000010,
|
||||||
|
/// <summary>apply the appropriate overlays</summary>
|
||||||
|
AddOverlays = 0x000000020,
|
||||||
|
/// <summary>Get the index of the overlay in the upper 8 bits of the iIcon</summary>
|
||||||
|
OverlayIndex = 0x000000040,
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct SHFILEINFO
|
||||||
|
{
|
||||||
|
public const int NAMESIZE = 80;
|
||||||
|
public IntPtr hIcon;
|
||||||
|
public int iIcon;
|
||||||
|
public uint dwAttributes;
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
|
||||||
|
public string szDisplayName;
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
|
||||||
|
public string szTypeName;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct RECT
|
||||||
|
{
|
||||||
|
public int left, top, right, bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct POINT
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGELISTDRAWPARAMS
|
||||||
|
{
|
||||||
|
public int cbSize;
|
||||||
|
public IntPtr himl;
|
||||||
|
public int i;
|
||||||
|
public IntPtr hdcDst;
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
public int cx;
|
||||||
|
public int cy;
|
||||||
|
public int xBitmap; // x offest from the upperleft of bitmap
|
||||||
|
public int yBitmap; // y offset from the upperleft of bitmap
|
||||||
|
public int rgbBk;
|
||||||
|
public int rgbFg;
|
||||||
|
public int fStyle;
|
||||||
|
public int dwRop;
|
||||||
|
public int fState;
|
||||||
|
public int Frame;
|
||||||
|
public int crEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct IMAGEINFO
|
||||||
|
{
|
||||||
|
public IntPtr hbmImage;
|
||||||
|
public IntPtr hbmMask;
|
||||||
|
public int Unused1;
|
||||||
|
public int Unused2;
|
||||||
|
public RECT rcImage;
|
||||||
|
}
|
||||||
|
[ComImportAttribute()]
|
||||||
|
[GuidAttribute("46EB5926-582E-4017-9FDF-E8998DAA0950")]
|
||||||
|
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IImageList
|
||||||
|
{
|
||||||
|
[PreserveSig]
|
||||||
|
int Add(IntPtr hbmImage, IntPtr hbmMask, ref int pi);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int ReplaceIcon(int i, IntPtr hicon, ref int pi);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int SetOverlayImage(int iImage, int iOverlay);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Replace(int i, IntPtr hbmImage, IntPtr hbmMask);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int AddMasked(IntPtr hbmImage, int crMask, ref int pi);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Draw(ref IMAGELISTDRAWPARAMS pimldp);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Remove(int i);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetIcon(int i, int flags, ref IntPtr picon);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetImageInfo(int i, ref IMAGEINFO pImageInfo);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Copy(int iDst, IImageList punkSrc, int iSrc, int uFlags);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Merge(int i1, IImageList punk2, int i2, int dx, int dy, ref Guid riid, ref IntPtr ppv);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Clone(ref Guid riid, ref IntPtr ppv);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetImageRect(int i, ref RECT prc);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetIconSize(ref int cx, ref int cy);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int SetIconSize(int cx, int cy);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetImageCount(ref int pi);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int SetImageCount(int uNewCount);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int SetBkColor(int clrBk, ref int pclr);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetBkColor(ref int pclr);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int BeginDrag(int iTrack, int dxHotspot, int dyHotspot);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int EndDrag();
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int DragEnter(IntPtr hwndLock, int x, int y);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int DragLeave(IntPtr hwndLock);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int DragMove(int x, int y);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int SetDragCursorImage(ref IImageList punk, int iDrag, int dxHotspot, int dyHotspot);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int DragShowNolock(int fShow);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetDragImage(ref POINT ppt, ref POINT pptHotspot, ref Guid riid, ref IntPtr ppv);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetItemFlags(int i, ref int dwFlags);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetOverlayImage(int iOverlay, ref int piIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user