Browse Source

[Windows] Inherit default Window icon from the Process resources

pull/15298/head
Max Katz 2 years ago
parent
commit
b08f5d52cc
  1. 9
      src/Windows/Avalonia.Win32/IconImpl.cs
  2. 26
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  3. 7
      src/Windows/Avalonia.Win32/Interop/Win32Icon.cs
  4. 34
      src/Windows/Avalonia.Win32/WindowImpl.cs

9
src/Windows/Avalonia.Win32/IconImpl.cs

@ -12,6 +12,12 @@ namespace Avalonia.Win32
private static readonly int s_taskbarIconSize = Win32Platform.WindowsVersion < PlatformConstants.Windows10 ? 32 : 24;
public IconImpl(Win32Icon smallIcon, Win32Icon bigIcon)
{
_smallIcon = smallIcon;
_bigIcon = bigIcon;
}
public IconImpl(Stream smallIcon, Stream bigIcon)
{
_smallIcon = CreateIconImpl(smallIcon);
@ -23,6 +29,9 @@ namespace Avalonia.Win32
_smallIcon = _bigIcon = CreateIconImpl(icon);
}
public Win32Icon SmallIcon => _smallIcon;
public Win32Icon BigIcon => _bigIcon;
private static Win32Icon CreateIconImpl(Stream stream)
{
if (stream.CanSeek)

26
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1376,6 +1376,10 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern bool DestroyIcon(IntPtr hIcon);
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
public static extern int ExtractIconEx(string szExeFileName, int nIconIndex, out IntPtr phiconLarge,
out IntPtr phiconSmall, int nIcons);
[DllImport("user32.dll", EntryPoint = "PeekMessageW", ExactSpelling = true)]
public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
@ -1824,6 +1828,28 @@ namespace Avalonia.Win32.Interop
}
}
[DllImport("kernel32", EntryPoint = "GetModuleFileName", CharSet=CharSet.Unicode, SetLastError = true)]
private static extern uint IntGetModuleFileName(IntPtr hModule, StringBuilder buffer, uint length);
internal static string? GetModuleFileName(IntPtr hModule)
{
// Environment.ProcessPath is not avaialable on netstandard.
uint length;
var buffer = new StringBuilder(260);
while ((length = IntGetModuleFileName(hModule, buffer, (uint)buffer.Capacity)) >= buffer.Capacity)
{
buffer.EnsureCapacity((int)length);
}
if (length == 0)
{
return null;
}
buffer.Length = (int)length;
return buffer.ToString();
}
[DllImport("kernel32", EntryPoint = "WaitForMultipleObjectsEx", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int IntWaitForMultipleObjectsEx(int nCount, IntPtr[] pHandles, bool bWaitAll, int dwMilliseconds, bool bAlertable);

7
src/Windows/Avalonia.Win32/Interop/Win32Icon.cs

@ -11,11 +11,16 @@ namespace Avalonia.Win32.Interop;
internal class Win32Icon : IDisposable
{
public Win32Icon(IntPtr handle)
{
Handle = handle;
}
public Win32Icon(Bitmap bitmap, PixelPoint hotSpot = default)
{
Handle = CreateIcon(bitmap, hotSpot);
}
public Win32Icon(IBitmapImpl bitmap, PixelPoint hotSpot = default)
{
using var memoryStream = new MemoryStream();

34
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -55,6 +55,8 @@ namespace Avalonia.Win32
{ WindowEdge.West, HitTestValues.HTLEFT }
};
private static readonly Lazy<IconImpl?> s_defaultIconImpl = new(LoadDefaultIcon);
/// <summary>
/// The Windows DPI which equates to a <see cref="RenderScaling"/> of 1.0.
/// </summary>
@ -782,14 +784,24 @@ namespace Avalonia.Win32
private Win32Icon? LoadIcon(Icons type, uint dpi)
{
if (_iconImpl == null)
if (type == Icons.ICON_SMALL2)
{
return null;
type = Icons.ICON_SMALL;
}
if (type == Icons.ICON_SMALL2)
if (_iconImpl == null)
{
type = Icons.ICON_SMALL;
if (s_defaultIconImpl.Value is { } defaultIcon)
{
return type switch
{
Icons.ICON_SMALL => defaultIcon.SmallIcon,
Icons.ICON_BIG => defaultIcon.BigIcon,
_ => throw new NotImplementedException(),
};
}
return null;
}
var iconKey = (type, dpi);
@ -807,6 +819,20 @@ namespace Avalonia.Win32
return icon;
}
private static IconImpl? LoadDefaultIcon()
{
if (GetModuleFileName(default) is { } moduleFileName)
{
var iconsCount = ExtractIconEx(moduleFileName, 0, out var largeIcon, out var smallIcon, 1);
if (iconsCount >= 1)
{
return new IconImpl(new Win32Icon(smallIcon), new Win32Icon(largeIcon));
}
}
return null;
}
private void RefreshIcon()
{
SendMessage(_hwnd, (int)WindowsMessage.WM_SETICON, (nint)Icons.ICON_SMALL, LoadIcon(Icons.ICON_SMALL, _dpi)?.Handle ?? default);

Loading…
Cancel
Save