mirror of
https://github.com/Hofknecht/SystemTrayMenu.git
synced 2024-10-05 04:24:38 +13:00
Fix COMException at CreateBitmapSourceFromHIcon
This commit is contained in:
parent
cb54dbd0d3
commit
d5dd89b3fe
1 changed files with 75 additions and 57 deletions
|
@ -143,78 +143,96 @@ namespace SystemTrayMenu.Utilities
|
||||||
uint flags = GetFlags(linkOverlay, largeIcon);
|
uint flags = GetFlags(linkOverlay, largeIcon);
|
||||||
uint attribute = NativeMethods.FileAttributeDirectory;
|
uint attribute = NativeMethods.FileAttributeDirectory;
|
||||||
IntPtr imageList = NativeMethods.Shell32SHGetFileInfo(path, attribute, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), flags);
|
IntPtr imageList = NativeMethods.Shell32SHGetFileInfo(path, attribute, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), flags);
|
||||||
return GetIcon(path, linkOverlay, shFileInfo, imageList);
|
return TryGetIcon(path, linkOverlay, shFileInfo, imageList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BitmapSource CreateBitmapSourceFromIcon(Icon icon) => Application.Current.Dispatcher.Invoke(() =>
|
private static BitmapSource? TryCreateBitmapSourceFromIcon(string path, Icon icon) => Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
BitmapSource bitmap = Imaging.CreateBitmapSourceFromHIcon(
|
BitmapSource? bitmap = null;
|
||||||
icon.Handle,
|
try
|
||||||
Int32Rect.Empty,
|
{
|
||||||
BitmapSizeOptions.FromEmptyOptions());
|
bitmap = Imaging.CreateBitmapSourceFromHIcon(
|
||||||
bitmap.Freeze();
|
icon.Handle,
|
||||||
|
Int32Rect.Empty,
|
||||||
|
BitmapSizeOptions.FromEmptyOptions());
|
||||||
|
bitmap.Freeze();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Warn($"Failed to {nameof(TryCreateBitmapSourceFromIcon)}: {path} ", ex);
|
||||||
|
}
|
||||||
|
|
||||||
return bitmap;
|
return bitmap;
|
||||||
});
|
});
|
||||||
|
|
||||||
private static BitmapSource? TryGetIconAsBitmapSourceSTA(string path, string resolvedPath, bool linkOverlay, bool isFolder)
|
private static BitmapSource? TryGetIconAsBitmapSourceSTA(string path, string resolvedPath, bool linkOverlay, bool isFolder)
|
||||||
{
|
{
|
||||||
BitmapSource? result = null;
|
BitmapSource? result = null;
|
||||||
Icon? icon = null;
|
|
||||||
|
|
||||||
|
if (!isFolder &&
|
||||||
|
Path.GetExtension(path).Equals(".ico", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
if (TryGetIconExtractAssociatedIcon(path, out Icon icon))
|
||||||
|
{
|
||||||
|
result = TryCreateBitmapSourceFromIcon(path, icon);
|
||||||
|
icon.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!isFolder && File.Exists(resolvedPath) &&
|
||||||
|
Path.GetExtension(resolvedPath).Equals(".ico", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
if (TryGetIconExtractAssociatedIcon(resolvedPath, out Icon icon))
|
||||||
|
{
|
||||||
|
result = TryCreateBitmapSourceFromIcon(resolvedPath, icon);
|
||||||
|
icon.Dispose();
|
||||||
|
if (result != null && linkOverlay && OverlayImage != null)
|
||||||
|
{
|
||||||
|
result = ImagingHelper.CreateIconWithOverlay(result, OverlayImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This code block must run in an STA thread otherwise the results may be incorrectly loaded icons!
|
||||||
|
NativeMethods.SHFILEINFO shFileInfo = default;
|
||||||
|
bool largeIcon = // Note: large returns another folder icon than windows explorer
|
||||||
|
Scaling.Factor >= 1.25f ||
|
||||||
|
Scaling.FactorByDpi >= 1.25f ||
|
||||||
|
Properties.Settings.Default.IconSizeInPercent / 100f >= 1.25f;
|
||||||
|
uint flags = GetFlags(linkOverlay, largeIcon);
|
||||||
|
uint attribute = isFolder ? NativeMethods.FileAttributeDirectory : NativeMethods.FileAttributeNormal;
|
||||||
|
IntPtr imageList = NativeMethods.Shell32SHGetFileInfo(path, attribute, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), flags);
|
||||||
|
Icon? icon = TryGetIcon(path, linkOverlay, shFileInfo, imageList);
|
||||||
|
if (icon != null)
|
||||||
|
{
|
||||||
|
result = TryCreateBitmapSourceFromIcon(path, icon);
|
||||||
|
icon.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetIconExtractAssociatedIcon(string path, out Icon icon)
|
||||||
|
{
|
||||||
|
Icon? iconOrNull = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!isFolder && Path.GetExtension(path).Equals(".ico", StringComparison.InvariantCultureIgnoreCase))
|
iconOrNull = Icon.ExtractAssociatedIcon(path);
|
||||||
{
|
|
||||||
icon = Icon.ExtractAssociatedIcon(path);
|
|
||||||
if (icon != null)
|
|
||||||
{
|
|
||||||
result = CreateBitmapSourceFromIcon(icon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!isFolder && File.Exists(resolvedPath) &&
|
|
||||||
Path.GetExtension(resolvedPath).Equals(".ico", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
icon = Icon.ExtractAssociatedIcon(resolvedPath);
|
|
||||||
if (icon != null)
|
|
||||||
{
|
|
||||||
result = CreateBitmapSourceFromIcon(icon);
|
|
||||||
if (linkOverlay && OverlayImage != null)
|
|
||||||
{
|
|
||||||
result = ImagingHelper.CreateIconWithOverlay(result, OverlayImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This code block must run in an STA thread otherwise the results may be incorrectly loaded icons!
|
|
||||||
NativeMethods.SHFILEINFO shFileInfo = default;
|
|
||||||
bool largeIcon = // Note: large returns another folder icon than windows explorer
|
|
||||||
Scaling.Factor >= 1.25f ||
|
|
||||||
Scaling.FactorByDpi >= 1.25f ||
|
|
||||||
Properties.Settings.Default.IconSizeInPercent / 100f >= 1.25f;
|
|
||||||
uint flags = GetFlags(linkOverlay, largeIcon);
|
|
||||||
uint attribute = isFolder ? NativeMethods.FileAttributeDirectory : NativeMethods.FileAttributeNormal;
|
|
||||||
IntPtr imageList = NativeMethods.Shell32SHGetFileInfo(path, attribute, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), flags);
|
|
||||||
icon = GetIcon(path, linkOverlay, shFileInfo, imageList);
|
|
||||||
if (icon != null)
|
|
||||||
{
|
|
||||||
result = CreateBitmapSourceFromIcon(icon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (COMException ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// This seems to happen very rarely, so we just log it and go on
|
Log.Warn($"Failed to {nameof(TryGetIconExtractAssociatedIcon)}: {path}", ex);
|
||||||
// However, we protect this log message from being called often, so we stop logging after a while
|
|
||||||
if (maxCOMExceptionLogs > 0)
|
|
||||||
{
|
|
||||||
maxCOMExceptionLogs--; // Note: written by multiple threads, but it is not worth any protection
|
|
||||||
Log.Warn("Reading native Icon failed:", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
icon?.Dispose();
|
if (iconOrNull != null)
|
||||||
return result;
|
{
|
||||||
|
icon = iconOrNull;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon = new Icon(string.Empty);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BitmapSource GetIconAsBitmapSourceSTA(string path, string resolvedPath, bool linkOverlay, bool isFolder)
|
private static BitmapSource GetIconAsBitmapSourceSTA(string path, string resolvedPath, bool linkOverlay, bool isFolder)
|
||||||
|
@ -260,7 +278,7 @@ namespace SystemTrayMenu.Utilities
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Icon? GetIcon(
|
private static Icon? TryGetIcon(
|
||||||
string path, bool linkOverlay, NativeMethods.SHFILEINFO shFileInfo, IntPtr imageList)
|
string path, bool linkOverlay, NativeMethods.SHFILEINFO shFileInfo, IntPtr imageList)
|
||||||
{
|
{
|
||||||
Icon? icon = null;
|
Icon? icon = null;
|
||||||
|
|
Loading…
Reference in a new issue