Skip to content

Commit 6a72ed2

Browse files
committed
Init
1 parent 6bcec6d commit 6a72ed2

File tree

7 files changed

+243
-141
lines changed

7 files changed

+243
-141
lines changed

src/Files.App.CsWin32/NativeMethods.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,4 @@ SetCurrentProcessExplicitAppUserModelID
222222
GdipCreateBitmapFromScan0
223223
BITMAP
224224
GetObject
225+
_SICHINTF

src/Files.App.Storage/Storables/WindowsStorage/WindowsStorable.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace Files.App.Storage
1010
{
11-
public abstract class WindowsStorable : IWindowsStorable, IStorableChild
11+
public abstract class WindowsStorable : IWindowsStorable, IStorableChild, IEquatable<IWindowsStorable>
1212
{
1313
public ComPtr<IShellItem> ThisPtr { get; protected set; }
1414

@@ -65,6 +65,17 @@ public abstract class WindowsStorable : IWindowsStorable, IStorableChild
6565
return Task.FromResult<IFolder?>(new WindowsFolder(pParentFolder));
6666
}
6767

68+
/// <inheritdoc/>
69+
public override bool Equals(object? obj)
70+
{
71+
return Equals(obj as IWindowsStorable);
72+
}
73+
74+
public override int GetHashCode()
75+
{
76+
return HashCode.Combine(Id, Name);
77+
}
78+
6879
/// <inheritdoc/>
6980
public void Dispose()
7081
{
@@ -76,5 +87,20 @@ public override string ToString()
7687
{
7788
return this.GetDisplayName();
7889
}
90+
91+
/// <inheritdoc/>
92+
public unsafe bool Equals(IWindowsStorable? other)
93+
{
94+
if (other is null)
95+
return false;
96+
97+
return ThisPtr.Get()->Compare(other.ThisPtr.Get(), (uint)_SICHINTF.SICHINT_DISPLAY, out int order).Succeeded && order is 0;
98+
}
99+
100+
public static bool operator ==(WindowsStorable left, WindowsStorable right)
101+
=> left.Equals(right);
102+
103+
public static bool operator !=(WindowsStorable left, WindowsStorable right)
104+
=> !(left == right);
79105
}
80106
}

src/Files.App.Storage/Storables/WindowsStorage/WindowsStorableHelpers.Shell.cs

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
// Copyright (c) Files Community
22
// Licensed under the MIT License.
33

4+
using System.Runtime.CompilerServices;
5+
using System.Text;
46
using Windows.Win32;
57
using Windows.Win32.Foundation;
68
using Windows.Win32.System.SystemServices;
79
using Windows.Win32.UI.Shell;
10+
using Windows.Win32.UI.Shell.PropertiesSystem;
11+
using Windows.Win32.UI.WindowsAndMessaging;
812

913
namespace Files.App.Storage
1014
{
@@ -13,14 +17,27 @@ public static partial class WindowsStorableHelpers
1317
public unsafe static HRESULT GetPropertyValue<TValue>(this IWindowsStorable storable, string propKey, out TValue value)
1418
{
1519
using ComPtr<IShellItem2> pShellItem2 = default;
16-
var shellItem2Iid = typeof(IShellItem2).GUID;
17-
HRESULT hr = storable.ThisPtr.Get()->QueryInterface(&shellItem2Iid, (void**)pShellItem2.GetAddressOf());
18-
hr = PInvoke.PSGetPropertyKeyFromName(propKey, out var originalPathPropertyKey);
19-
hr = pShellItem2.Get()->GetString(originalPathPropertyKey, out var szOriginalPath);
20+
HRESULT hr = storable.ThisPtr.Get()->QueryInterface(IID.IID_IShellItem2, (void**)pShellItem2.GetAddressOf());
21+
22+
PROPERTYKEY propertyKey = default;
23+
fixed (char* pszPropertyKey = propKey)
24+
hr = PInvoke.PSGetPropertyKeyFromName(pszPropertyKey, &propertyKey);
2025

2126
if (typeof(TValue) == typeof(string))
2227
{
23-
value = (TValue)(object)szOriginalPath.ToString();
28+
ComHeapPtr<PWSTR> szPropertyValue = default;
29+
hr = pShellItem2.Get()->GetString(&propertyKey, szPropertyValue.Get());
30+
value = (TValue)(object)szPropertyValue.Get()->ToString();
31+
32+
return hr;
33+
}
34+
if (typeof(TValue) == typeof(bool))
35+
{
36+
bool propertyValue = false;
37+
hr = pShellItem2.Get()->GetBool(propertyKey, out var fPropertyValue);
38+
propertyValue = fPropertyValue;
39+
value = Unsafe.As<bool, TValue>(ref propertyValue);
40+
2441
return hr;
2542
}
2643
else
@@ -51,5 +68,61 @@ public unsafe static string GetDisplayName(this IWindowsStorable storable, SIGDN
5168
? new string((char*)pszName.Get()) // this is safe as it gets memcpy'd internally
5269
: string.Empty;
5370
}
71+
72+
public unsafe static HRESULT TryInvokeContextMenuVerb(this IWindowsStorable storable, string verbName)
73+
{
74+
Debug.Assert(Thread.CurrentThread.GetApartmentState() is ApartmentState.STA);
75+
76+
using ComPtr<IContextMenu> pContextMenu = default;
77+
HRESULT hr = storable.ThisPtr.Get()->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IContextMenu, (void**)pContextMenu.GetAddressOf());
78+
HMENU hMenu = PInvoke.CreatePopupMenu();
79+
hr = pContextMenu.Get()->QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE);
80+
81+
CMINVOKECOMMANDINFO cmici = default;
82+
cmici.cbSize = (uint)sizeof(CMINVOKECOMMANDINFO);
83+
cmici.nShow = (int)SHOW_WINDOW_CMD.SW_HIDE;
84+
85+
fixed (byte* pszVerbName = Encoding.ASCII.GetBytes(verbName))
86+
{
87+
cmici.lpVerb = new(pszVerbName);
88+
hr = pContextMenu.Get()->InvokeCommand(cmici);
89+
90+
if (!PInvoke.DestroyMenu(hMenu))
91+
return HRESULT.E_FAIL;
92+
93+
return hr;
94+
}
95+
}
96+
97+
public unsafe static HRESULT TryInvokeContextMenuVerbs(this IWindowsStorable storable, string[] verbNames, bool earlyReturnOnSuccess)
98+
{
99+
Debug.Assert(Thread.CurrentThread.GetApartmentState() is ApartmentState.STA);
100+
101+
using ComPtr<IContextMenu> pContextMenu = default;
102+
HRESULT hr = storable.ThisPtr.Get()->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IContextMenu, (void**)pContextMenu.GetAddressOf());
103+
HMENU hMenu = PInvoke.CreatePopupMenu();
104+
hr = pContextMenu.Get()->QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE);
105+
106+
CMINVOKECOMMANDINFO cmici = default;
107+
cmici.cbSize = (uint)sizeof(CMINVOKECOMMANDINFO);
108+
cmici.nShow = (int)SHOW_WINDOW_CMD.SW_HIDE;
109+
110+
foreach (var verbName in verbNames)
111+
{
112+
fixed (byte* pszVerbName = Encoding.ASCII.GetBytes(verbName))
113+
{
114+
cmici.lpVerb = new(pszVerbName);
115+
hr = pContextMenu.Get()->InvokeCommand(cmici);
116+
117+
if (!PInvoke.DestroyMenu(hMenu))
118+
return HRESULT.E_FAIL;
119+
120+
if (hr.Succeeded && earlyReturnOnSuccess)
121+
return hr;
122+
}
123+
}
124+
125+
return hr;
126+
}
54127
}
55128
}

src/Files.App/Data/Contexts/HomePage/HomePageContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public sealed partial class HomePageContext : ObservableObject, IHomePageContext
1313

1414
public bool IsAnyItemRightClicked => rightClickedItem is not null;
1515

16+
public IHomeFolder HomeFolder { get; } = new HomeFolder();
17+
1618
private WidgetCardItem? rightClickedItem = null;
1719
public WidgetCardItem? RightClickedItem => rightClickedItem;
1820

src/Files.App/Data/Contexts/HomePage/IHomePageContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,10 @@ public interface IHomePageContext
2626
/// Tells whether any item has been right clicked
2727
/// </summary>
2828
bool IsAnyItemRightClicked { get; }
29+
30+
/// <summary>
31+
/// Gets the instance of <see cref="IHomeFolder"/>.
32+
/// </summary>
33+
IHomeFolder HomeFolder { get; }
2934
}
3035
}

src/Files.App/Data/Items/WidgetFolderCardItem.cs

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,63 +2,49 @@
22
// Licensed under the MIT License.
33

44
using Microsoft.UI.Xaml.Media.Imaging;
5+
using Windows.Win32;
6+
using Windows.Win32.UI.Shell;
57

68
namespace Files.App.Data.Items
79
{
8-
public sealed partial class WidgetFolderCardItem : WidgetCardItem, IWidgetCardItem<LocationItem>
10+
public sealed partial class WidgetFolderCardItem : WidgetCardItem, IWidgetCardItem<IWindowsStorable>
911
{
10-
// Fields
11-
12-
private byte[] _thumbnailData;
13-
1412
// Properties
1513

1614
public string? AutomationProperties { get; set; }
1715

18-
public LocationItem? Item { get; private set; }
16+
public IWindowsStorable Item { get; private set; }
1917

2018
public string? Text { get; set; }
2119

2220
public bool IsPinned { get; set; }
2321

24-
public bool HasPath
25-
=> !string.IsNullOrEmpty(Path);
26-
2722
private BitmapImage? _Thumbnail;
28-
public BitmapImage? Thumbnail
29-
{
30-
get => _Thumbnail;
31-
set => SetProperty(ref _Thumbnail, value);
32-
}
23+
public BitmapImage? Thumbnail { get => _Thumbnail; set => SetProperty(ref _Thumbnail, value); }
3324

3425
// Constructor
3526

36-
public WidgetFolderCardItem(LocationItem item, string text, bool isPinned)
27+
public WidgetFolderCardItem(IWindowsStorable item, string text, bool isPinned)
3728
{
38-
if (!string.IsNullOrWhiteSpace(text))
39-
{
40-
Text = text;
41-
AutomationProperties = Text;
42-
}
43-
44-
IsPinned = isPinned;
29+
AutomationProperties = Text;
4530
Item = item;
46-
Path = item.Path;
31+
Text = text;
32+
IsPinned = isPinned;
33+
Path = item.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING);
4734
}
4835

4936
// Methods
5037

5138
public async Task LoadCardThumbnailAsync()
5239
{
53-
var result = await FileThumbnailHelper.GetIconAsync(
54-
Path,
55-
Constants.ShellIconSizes.Large,
56-
true,
57-
IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
40+
if (string.IsNullOrEmpty(Path))
41+
return;
42+
43+
Item.TryGetThumbnail((int)(32f * App.AppModel.AppWindowDPI), SIIGBF.SIIGBF_ICONONLY, out var rawThumbnailData);
44+
if (rawThumbnailData is null)
45+
return;
5846

59-
_thumbnailData = result;
60-
if (_thumbnailData is not null)
61-
Thumbnail = await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => _thumbnailData.ToBitmapAsync(), Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal);
47+
Thumbnail = await rawThumbnailData?.ToBitmapAsync();
6248
}
6349
}
6450
}

0 commit comments

Comments
 (0)