Compare commits
	
		
			5 Commits
		
	
	
		
			v1.2.0-pre
			...
			6de76da8ad
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6de76da8ad | |||
| 48161b5c2e | |||
| 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,44 +4,59 @@ 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;
 | 
				
			||||||
 | 
					using BitFaster.Caching.Lru;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FocusVolumeControl.AudioSessions;
 | 
					namespace FocusVolumeControl.AudioSessions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public sealed class ActiveAudioSessionWrapper : IAudioSession
 | 
					public sealed class ActiveAudioSessionWrapper : IAudioSession
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						static ConcurrentLru<string, string> _iconCache = new ConcurrentLru<string, string>(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public string DisplayName { get; set; }
 | 
						public string DisplayName { get; set; }
 | 
				
			||||||
	public string ExecutablePath { get; set; }
 | 
						public string ExecutablePath { get; set; }
 | 
				
			||||||
	public string IconPath { get; set; }
 | 
						public string IconPath { get; set; }
 | 
				
			||||||
	private List<IAudioSessionControl2> Sessions { get; } = new List<IAudioSessionControl2>();
 | 
						private List<IAudioSessionControl2> Sessions { get; } = new List<IAudioSessionControl2>();
 | 
				
			||||||
	private IEnumerable<ISimpleAudioVolume> Volume => Sessions.Cast<ISimpleAudioVolume>();
 | 
						private IEnumerable<ISimpleAudioVolume> Volume => Sessions.Cast<ISimpleAudioVolume>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	string _icon;
 | 
						string GetIconFromIconPath()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return _iconCache.GetOrAdd(IconPath, (key) =>
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var tmp = (Bitmap)Bitmap.FromFile(IconPath);
 | 
				
			||||||
 | 
								tmp.MakeTransparent();
 | 
				
			||||||
 | 
								return Tools.ImageToBase64(tmp, true);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						string GetIconFromExecutablePath()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return _iconCache.GetOrAdd(ExecutablePath, (key) =>
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var tmp = IconExtraction.GetIcon(ExecutablePath);
 | 
				
			||||||
 | 
								//var tmp = Icon.ExtractAssociatedIcon(ExecutablePath);
 | 
				
			||||||
 | 
								return Tools.ImageToBase64(tmp, true);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public string GetIcon()
 | 
						public string GetIcon()
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (string.IsNullOrEmpty(_icon))
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		try
 | 
							try
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (!string.IsNullOrEmpty(IconPath))
 | 
								if (!string.IsNullOrEmpty(IconPath))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
					var tmp = (Bitmap)Bitmap.FromFile(IconPath);
 | 
									return GetIconFromIconPath();
 | 
				
			||||||
					tmp.MakeTransparent();
 | 
					 | 
				
			||||||
					_icon = Tools.ImageToBase64(tmp, true);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
					var tmp = Icon.ExtractAssociatedIcon(ExecutablePath);
 | 
									return GetIconFromExecutablePath();
 | 
				
			||||||
					_icon = Tools.ImageToBase64(tmp.ToBitmap(), true);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		catch
 | 
							catch
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
				_icon = "Images/encoderIcon";
 | 
								return "Images/encoderIcon";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		return _icon;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Any()
 | 
						public bool Any()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
				
			|||||||
@ -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" />
 | 
				
			||||||
@ -96,6 +97,9 @@
 | 
				
			|||||||
    </Content>
 | 
					    </Content>
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <PackageReference Include="BitFaster.Caching">
 | 
				
			||||||
 | 
					      <Version>2.2.1</Version>
 | 
				
			||||||
 | 
					    </PackageReference>
 | 
				
			||||||
    <PackageReference Include="IsExternalInit">
 | 
					    <PackageReference Include="IsExternalInit">
 | 
				
			||||||
      <Version>1.0.3</Version>
 | 
					      <Version>1.0.3</Version>
 | 
				
			||||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
					      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										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);
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -39,12 +39,24 @@ namespace FocusVolumeControl
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		public event Action WindowChanged;
 | 
							public event Action WindowChanged;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		private void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
 | 
							CancellationTokenSource? _cancellationTokenSource = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private async void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			try
 | 
								try
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
 | 
									//debounce the window changed events by 100 ms because if you click mouse over an application on the start bar
 | 
				
			||||||
 | 
									//and then click on the preview window, it will quickly go from current -> fallback -> new app
 | 
				
			||||||
 | 
									//which can often result in it getting stuck on the fallback app
 | 
				
			||||||
 | 
									_cancellationTokenSource?.Cancel();
 | 
				
			||||||
 | 
									_cancellationTokenSource = new CancellationTokenSource();
 | 
				
			||||||
 | 
									await Task.Delay(100, _cancellationTokenSource.Token);
 | 
				
			||||||
				WindowChanged?.Invoke();
 | 
									WindowChanged?.Invoke();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								catch (TaskCanceledException)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									//ignored
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			catch (Exception ex)
 | 
								catch (Exception ex)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Logger.Instance.LogMessage(TracingLevel.ERROR, $"Unexpected Error in EventHandler:\n {ex}");
 | 
									Logger.Instance.LogMessage(TracingLevel.ERROR, $"Unexpected Error in EventHandler:\n {ex}");
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user