Skip to content

Commit

Permalink
Update Win32API.cs
Browse files Browse the repository at this point in the history
  • Loading branch information
yaira2 committed Feb 20, 2024
1 parent 4c40a7d commit 1779e4e
Show file tree
Hide file tree
Showing 22 changed files with 195 additions and 135 deletions.
5 changes: 4 additions & 1 deletion src/Files.App/Data/Items/DriveItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,10 @@ public int CompareTo(INavigationControlItem other)
public async Task LoadThumbnailAsync()
{
if (!string.IsNullOrEmpty(DeviceID) && !string.Equals(DeviceID, "network-folder"))
IconData ??= await FileThumbnailHelper.LoadIconWithoutOverlayAsync(DeviceID, Constants.ShellIconSizes.Small, false, false, true, true);
{
var result = await FileThumbnailHelper.GetIconAsync(DeviceID, Constants.ShellIconSizes.Small, false, false, IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
IconData ??= result.IconData;
}

if (Root is not null)
{
Expand Down
3 changes: 2 additions & 1 deletion src/Files.App/Data/Items/SidebarLibraryItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public async Task<bool> CheckDefaultSaveFolderAccess()

public async Task LoadLibraryIconAsync()
{
IconData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(Path, Constants.ShellIconSizes.Small, false, false, true, true);
var result = await FileThumbnailHelper.GetIconAsync(Path, Constants.ShellIconSizes.Small, false, false, IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
IconData = result.IconData;

if (IconData is not null)
Icon = await IconData.ToBitmapAsync();
Expand Down
3 changes: 2 additions & 1 deletion src/Files.App/Data/Items/WidgetDriveCardItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public WidgetDriveCardItem(DriveItem item)

public async Task LoadCardThumbnailAsync()
{
thumbnailData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(Item.Path, Constants.ShellIconSizes.Large, true, false, true, true);
var result = await FileThumbnailHelper.GetIconAsync(Item.Path, Constants.ShellIconSizes.Large, true, false, IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
thumbnailData = result.IconData;

// Thumbnail data is valid, set the item icon
if (thumbnailData is not null && thumbnailData.Length > 0)
Expand Down
3 changes: 2 additions & 1 deletion src/Files.App/Data/Items/WidgetFolderCardItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public WidgetFolderCardItem(LocationItem item, string text, bool isPinned)

public async Task LoadCardThumbnailAsync()
{
_thumbnailData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(Path, Constants.ShellIconSizes.Large, true, false, true, true);
var result = await FileThumbnailHelper.GetIconAsync(Path, Constants.ShellIconSizes.Large, true, false, IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
_thumbnailData = result.IconData;

if (_thumbnailData is not null && _thumbnailData.Length > 0)
Thumbnail = await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => _thumbnailData.ToBitmapAsync(), Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
Expand Down
7 changes: 5 additions & 2 deletions src/Files.App/Data/Models/AppModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,13 @@ public string PCloudDrivePath

/// <summary>
/// Gets or sets a value indicating the AppWindow DPI.
/// TODO update value if the DPI changes
/// </summary>
public float AppWindowDpi
private float appWindowDPI = InteropHelpers.GetDpiForWindow(MainWindow.Instance.WindowHandle) / 96f;
public float AppWindowDPI
{
get => InteropHelpers.GetDpiForWindow(MainWindow.Instance.WindowHandle) / 96f;
get => appWindowDPI;
set => SetProperty(ref appWindowDPI, value);
}
}
}
24 changes: 13 additions & 11 deletions src/Files.App/Data/Models/ItemViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,7 @@ private async Task LoadItemThumbnailAsync(ListedItem item)
{
var getIconOnly = UserSettingsService.FoldersSettingsService.ShowThumbnails == false || thumbnailSize < 48;
var getThumbnailOnly = !item.IsExecutable && !getIconOnly;
var iconInfo = await FileThumbnailHelper.LoadIconAndOverlayAsync(item.ItemPath, thumbnailSize, false, getThumbnailOnly, getIconOnly);
var iconInfo = await FileThumbnailHelper.GetIconAsync(item.ItemPath, thumbnailSize, false, getThumbnailOnly, getIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None);

if (!iconInfo.isIconCached)
{
Expand All @@ -962,7 +962,7 @@ await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
var cancellationTokenSource = new CancellationTokenSource(3000);
while (!iconInfo.isIconCached)
{
iconInfo = await FileThumbnailHelper.LoadIconAndOverlayAsync(item.ItemPath, thumbnailSize, false, getThumbnailOnly, getIconOnly);
iconInfo = await FileThumbnailHelper.GetIconAsync(item.ItemPath, thumbnailSize, false, getThumbnailOnly, getIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None);
cancellationTokenSource.Token.ThrowIfCancellationRequested();
await Task.Delay(500);
}
Expand All @@ -984,28 +984,29 @@ await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
!item.IsExecutable
)
{
var fileIcon = await FileThumbnailHelper.LoadIconAndOverlayAsync(item.ItemPath, thumbnailSize, false, false, true);
var fileIcon = await FileThumbnailHelper.GetIconAsync(item.ItemPath, thumbnailSize, false, false, IconOptions.ReturnIconOnly);
var bitmapImage = await fileIcon.IconData.ToBitmapAsync();
DefaultIcons.TryAdd(item.FileExtension.ToLowerInvariant(), bitmapImage);
}

}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}

if (iconInfo.OverlayData is not null)
var iconOverlay = await FileThumbnailHelper.GetIconOverlayAsync(item.ItemPath, false);
if (iconOverlay is not null)
{
// Assign the icon overlay to the listed item
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
item.IconOverlay = await iconInfo.OverlayData.ToBitmapAsync();
item.IconOverlay = await iconOverlay.ToBitmapAsync();
item.ShieldIcon = await GetShieldIcon();
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}
}
else
{
var getIconOnly = UserSettingsService.FoldersSettingsService.ShowThumbnails == false || thumbnailSize < 48;
var iconInfo = await FileThumbnailHelper.LoadIconAndOverlayAsync(item.ItemPath, thumbnailSize, true, false, getIconOnly);
var iconInfo = await FileThumbnailHelper.GetIconAsync(item.ItemPath, thumbnailSize, true, false, getIconOnly ? IconOptions.ReturnIconOnly : IconOptions.None);

if (iconInfo.IconData is not null)
{
Expand All @@ -1015,11 +1016,12 @@ await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}

if (iconInfo.OverlayData is not null)
var iconOverlay = await FileThumbnailHelper.GetIconOverlayAsync(item.ItemPath, true);
if (iconOverlay is not null)
{
await dispatcherQueue.EnqueueOrInvokeAsync(async () =>
{
item.IconOverlay = await iconInfo.OverlayData.ToBitmapAsync();
item.IconOverlay = await iconOverlay.ToBitmapAsync();
item.ShieldIcon = await GetShieldIcon();
}, Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
}
Expand Down Expand Up @@ -1284,10 +1286,10 @@ await SafetyExtensions.IgnoreExceptions(() =>
ImageSource? groupImage = null;
if (item.PrimaryItemAttribute != StorageItemTypes.Folder || item.IsArchive)
{
var headerIconInfo = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(item.ItemPath, Constants.ShellIconSizes.Large, false, false, true, true);
var headerIconInfo = await FileThumbnailHelper.GetIconAsync(item.ItemPath, Constants.ShellIconSizes.Large, false, false, IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);

if (headerIconInfo is not null && !item.IsShortcut)
groupImage = await dispatcherQueue.EnqueueOrInvokeAsync(() => headerIconInfo.ToBitmapAsync(), Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);
if (headerIconInfo.IconData is not null && !item.IsShortcut)
groupImage = await dispatcherQueue.EnqueueOrInvokeAsync(() => headerIconInfo.IconData.ToBitmapAsync(), Microsoft.UI.Dispatching.DispatcherQueuePriority.Low);

// The groupImage is null if loading icon from fulltrust process failed
if (!item.IsShortcut && !item.IsHiddenItem && !FtpHelpers.IsFtpPath(item.ItemPath) && groupImage is null)
Expand Down
4 changes: 2 additions & 2 deletions src/Files.App/Data/Models/SidebarPinnedModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ public async Task<LocationItem> CreateLocationItemFromPathAsync(string path)
locationItem.IsInvalid = false;
if (res && res.Result is not null)
{
var iconData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(res.Result.Path, Constants.ShellIconSizes.Small, true, false, true, true);
locationItem.IconData = iconData;
var result = await FileThumbnailHelper.GetIconAsync(res.Result.Path, Constants.ShellIconSizes.Small, true, false, IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
locationItem.IconData = result.IconData;

if (locationItem.IconData is not null)
locationItem.Icon = await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => locationItem.IconData.ToBitmapAsync());
Expand Down
4 changes: 3 additions & 1 deletion src/Files.App/Helpers/Navigation/NavigationHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ private static async Task UpdateTabInfoAsync(TabBarItem tabItem, object navigati

if (iconSource.ImageSource is null)
{
var iconData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(currentPath, Constants.ShellIconSizes.Small, true, false, true, true);
var result = await FileThumbnailHelper.GetIconAsync(currentPath, Constants.ShellIconSizes.Small, true, false, IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
var iconData = result.IconData;

if (iconData is not null)
iconSource.ImageSource = await iconData.ToBitmapAsync();
}
Expand Down
9 changes: 8 additions & 1 deletion src/Files.App/Utils/Cloud/CloudDrivesManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,14 @@ public static async Task UpdateDrivesAsync()
ShowProperties = true,
};

var iconData = provider.IconData ?? await FileThumbnailHelper.LoadIconWithoutOverlayAsync(provider.SyncFolder, Constants.ShellIconSizes.Small, false, false, true, true);
var iconData = provider.IconData;

if (iconData is null)
{
var result = await FileThumbnailHelper.GetIconAsync(provider.SyncFolder, Constants.ShellIconSizes.Small, false, false, IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
iconData = result.IconData;
}

if (iconData is not null)
{
cloudProviderItem.IconData = iconData;
Expand Down
6 changes: 3 additions & 3 deletions src/Files.App/Utils/RecentItem/RecentItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ public RecentItem(ShellFileItem fileItem) : base()

public async Task LoadRecentItemIconAsync()
{
var iconData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(RecentPath, Constants.ShellIconSizes.Large, false, false, false, false);
if (iconData is not null)
var result = await FileThumbnailHelper.GetIconAsync(RecentPath, Constants.ShellIconSizes.Large, false, false, IconOptions.None);
if (result.IconData is not null)
{
EmptyImgVis = false;
FileImg = await iconData.ToBitmapAsync();
FileImg = await result.IconData.ToBitmapAsync();
}
}

Expand Down
108 changes: 70 additions & 38 deletions src/Files.App/Utils/Shell/Win32API.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,63 @@ public static string ExtractStringFromDLL(string file, int number)
}
}

private static readonly object _iconOverlayLock = new object();

private static readonly object _lock = new object();
/// <summary>
/// Returns overlay for given file or folder
/// </summary>
/// <param name="path"></param>
/// <param name="isDirectory"></param>
/// <returns></returns>
public static byte[]? GetIconOverlay(string path, bool isDirectory)
{
var shFileInfo = new Shell32.SHFILEINFO();
var flags = Shell32.SHGFI.SHGFI_OVERLAYINDEX | Shell32.SHGFI.SHGFI_ICON | Shell32.SHGFI.SHGFI_SYSICONINDEX | Shell32.SHGFI.SHGFI_ICONLOCATION;
byte[]? overlayData = null;

try
{
IntPtr result = Shell32.SHGetFileInfo(path, isDirectory ? FileAttributes.Directory : 0, ref shFileInfo, Shell32.SHFILEINFO.Size, flags);
if (result == IntPtr.Zero)
return null;

User32.DestroyIcon(shFileInfo.hIcon);

lock (_iconOverlayLock)
{
if (!Shell32.SHGetImageList(Shell32.SHIL.SHIL_LARGE, typeof(ComCtl32.IImageList).GUID, out var imageListOut).Succeeded)
return null;

var imageList = (ComCtl32.IImageList)imageListOut;

var overlayIdx = shFileInfo.iIcon >> 24;
if (overlayIdx != 0)
{
var overlayImage = imageList.GetOverlayImage(overlayIdx);

using var hOverlay = imageList.GetIcon(overlayImage, ComCtl32.IMAGELISTDRAWFLAGS.ILD_TRANSPARENT);

if (!hOverlay.IsNull && !hOverlay.IsInvalid)
{
using var icon = hOverlay.ToIcon();
using var image = icon.ToBitmap();

overlayData = (byte[]?)new ImageConverter().ConvertTo(image, typeof(byte[]));
}
}

Marshal.ReleaseComObject(imageList);
}
}
catch (Exception)
{
return null;
}

return overlayData;
}

private static readonly object _iconLock = new object();

/// <summary>
/// Returns an icon when a thumbnail isn't available or if getIconOnly is true.
Expand All @@ -231,22 +286,17 @@ public static string ExtractStringFromDLL(string file, int number)
/// <param name="thumbnailSize"></param>
/// <param name="isFolder"></param>
/// <param name="getIconOnly"></param>
/// <param name="getOverlay"></param>
/// <param name="onlyGetOverlay"></param>
/// <returns></returns>
public static (byte[]? icon, byte[]? overlay, bool isIconCached) GetFileIconAndOverlay(
public static (byte[]? icon, bool isIconCached) GetIcon(
string path,
int thumbnailSize,
bool isFolder,
bool getThumbnailOnly,
bool getIconOnly,
bool getOverlay = true,
bool onlyGetOverlay = false)
bool getIconOnly)
{
byte[]? iconData = null, overlayData = null;
byte[]? iconData = null;
bool isIconCached = false;


try
{
// Attempt to get file icon/thumbnail using IShellItemImageFactory GetImage
Expand Down Expand Up @@ -275,19 +325,19 @@ public static (byte[]? icon, byte[]? overlay, bool isIconCached) GetFileIconAndO
Marshal.ReleaseComObject(shellFactory);
}

if (getOverlay || (!onlyGetOverlay && iconData is null))
if (iconData is not null)
return (iconData, isIconCached);
else
{
var shfi = new Shell32.SHFILEINFO();
var flags = Shell32.SHGFI.SHGFI_OVERLAYINDEX | Shell32.SHGFI.SHGFI_ICON | Shell32.SHGFI.SHGFI_SYSICONINDEX | Shell32.SHGFI.SHGFI_ICONLOCATION;
var flags = Shell32.SHGFI.SHGFI_OVERLAYINDEX | Shell32.SHGFI.SHGFI_ICON | Shell32.SHGFI.SHGFI_SYSICONINDEX | Shell32.SHGFI.SHGFI_ICONLOCATION | Shell32.SHGFI.SHGFI_USEFILEATTRIBUTES;

// Cannot access file, use file attributes
var useFileAttibutes = !onlyGetOverlay && iconData is null;
var useFileAttibutes = iconData is null;

var ret = ShellFolderExtensions.GetStringAsPIDL(path, out var pidl) ?
Shell32.SHGetFileInfo(pidl, 0, ref shfi, Shell32.SHFILEINFO.Size, Shell32.SHGFI.SHGFI_PIDL | flags) :
Shell32.SHGetFileInfo(path, isFolder ? FileAttributes.Directory : 0, ref shfi, Shell32.SHFILEINFO.Size, flags | (useFileAttibutes ? Shell32.SHGFI.SHGFI_USEFILEATTRIBUTES : 0));
var ret = Shell32.SHGetFileInfo(path, isFolder ? FileAttributes.Directory : 0, ref shfi, Shell32.SHFILEINFO.Size, flags);
if (ret == IntPtr.Zero)
return (iconData, null, isIconCached);
return (iconData, isIconCached);

User32.DestroyIcon(shfi.hIcon);

Expand All @@ -299,14 +349,14 @@ public static (byte[]? icon, byte[]? overlay, bool isIconCached) GetFileIconAndO
_ => Shell32.SHIL.SHIL_JUMBO,
};

lock (_lock)
lock (_iconLock)
{
if (!Shell32.SHGetImageList(imageListSize, typeof(ComCtl32.IImageList).GUID, out var imageListOut).Succeeded)
return (iconData, null, isIconCached);
return (iconData, isIconCached);

var imageList = (ComCtl32.IImageList)imageListOut;

if (!onlyGetOverlay && iconData is null)
if (iconData is null)
{
var iconIdx = shfi.iIcon & 0xFFFFFF;
if (iconIdx != 0)
Expand Down Expand Up @@ -338,28 +388,10 @@ public static (byte[]? icon, byte[]? overlay, bool isIconCached) GetFileIconAndO
}
}

var overlayIdx = shfi.iIcon >> 24;
if (overlayIdx != 0 && getOverlay)
{
var overlayImage = imageList.GetOverlayImage(overlayIdx);
using var hOverlay = imageList.GetIcon(overlayImage, ComCtl32.IMAGELISTDRAWFLAGS.ILD_TRANSPARENT);
if (!hOverlay.IsNull && !hOverlay.IsInvalid)
{
using var icon = hOverlay.ToIcon();
using var image = icon.ToBitmap();

overlayData = (byte[]?)new ImageConverter().ConvertTo(image, typeof(byte[]));
}
}

Marshal.ReleaseComObject(imageList);
}

return (iconData, overlayData, isIconCached);
}
else
{
return (iconData, null, isIconCached);
return (iconData, isIconCached);
}
}
finally
Expand Down
Loading

0 comments on commit 1779e4e

Please sign in to comment.