Skip to content

Code Quality: Improved WindowsStorables #17191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions src/Files.App.CsWin32/ComPtr`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,6 @@ public void Attach(T* other)
return (T**)Unsafe.AsPointer(ref Unsafe.AsRef(in this));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Obsolete("Use `HRESULT As<U>(U** other)` instead.")]
public readonly ComPtr<U> As<U>() where U : unmanaged, IComIID
{
ComPtr<U> ptr = default;
((IUnknown*)_ptr)->QueryInterface((Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in U.Guid)), (void**)ptr.GetAddressOf());
return ptr;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly HRESULT As<U>(U** other) where U : unmanaged, IComIID
{
Expand All @@ -91,22 +82,6 @@ public readonly HRESULT CoCreateInstance(Guid* rclsid, IUnknown* pUnkOuter = nul
return PInvoke.CoCreateInstance(rclsid, pUnkOuter, dwClsContext, (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in T.Guid)), (void**)this.GetAddressOf());
}

// Conversion operators

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ComPtr<T>(T* other)
{
ComPtr<T> ptr = default;
ptr.Attach(other);
return ptr;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator T*(ComPtr<T> other)
{
return other._ptr;
}

// Disposer

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
30 changes: 30 additions & 0 deletions src/Files.App.CsWin32/ManualGuid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ public static Guid* IID_IStorageProviderStatusUISourceFactory

[GuidRVAGen.Guid("00021500-0000-0000-C000-000000000046")]
public static partial Guid* IID_IQueryInfo { get; }

[GuidRVAGen.Guid("BCC18B79-BA16-442F-80C4-8A59C30C463B")]
public static partial Guid* IID_IShellItemImageFactory { get; }

[GuidRVAGen.Guid("000214F9-0000-0000-C000-000000000046")]
public static partial Guid* IID_IShellLinkW { get; }

[GuidRVAGen.Guid("B63EA76D-1F85-456F-A19C-48159EFA858B")]
public static partial Guid* IID_IShellItemArray { get; }

[GuidRVAGen.Guid("7F9185B0-CB92-43C5-80A9-92277A4F7B54")]
public static partial Guid* IID_IExecuteCommand { get; }

[GuidRVAGen.Guid("1C9CD5BB-98E9-4491-A60F-31AACC72B83C")]
public static partial Guid* IID_IObjectWithSelection { get; }

[GuidRVAGen.Guid("000214E8-0000-0000-C000-000000000046")]
public static partial Guid* IID_IShellExtInit { get; }

[GuidRVAGen.Guid("000214F4-0000-0000-C000-000000000046")]
public static partial Guid* IID_IContextMenu2 { get; }
}

public static unsafe partial class CLSID
Expand All @@ -59,6 +80,15 @@ public static unsafe partial class CLSID

[GuidRVAGen.Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]
public static partial Guid* CLSID_ApplicationActivationManager { get; }

[GuidRVAGen.Guid("B455F46E-E4AF-4035-B0A4-CF18D2F6F28E")]
public static partial Guid* CLSID_PinToFrequentExecute { get; }

[GuidRVAGen.Guid("EE20EEBA-DF64-4A4E-B7BB-2D1C6B2DFCC1")]
public static partial Guid* CLSID_UnPinFromFrequentExecute { get; }

[GuidRVAGen.Guid("D969A300-E7FF-11d0-A93B-00A0C90F2719")]
public static partial Guid* CLSID_NewMenu { get; }
}

public static unsafe partial class BHID
Expand Down
9 changes: 9 additions & 0 deletions src/Files.App.CsWin32/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,12 @@ QITIPF_FLAGS
GetKeyboardState
MapVirtualKey
GetKeyboardLayout
S_FALSE
IExecuteCommand
IObjectWithSelection
SHCreateShellItemArrayFromShellItem
IShellExtInit
IContextMenu2
GetSubMenu
GetMenuItemCount
GetMenuItemInfo
50 changes: 24 additions & 26 deletions src/Files.App.Storage/Storables/HomeFolder/HomeFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace Files.App.Storage.Storables
{
public partial class HomeFolder : IHomeFolder
public unsafe partial class HomeFolder : IHomeFolder
{
public string Id => "Home"; // Will be "files://Home" in the future.

Expand Down Expand Up @@ -48,38 +48,36 @@ public IAsyncEnumerable<IStorableChild> GetQuickAccessFolderAsync(CancellationTo
/// <inheritdoc/>
public IAsyncEnumerable<IStorableChild> GetLogicalDrivesAsync(CancellationToken cancellationToken = default)
{
return GetLogicalDrives().ToAsyncEnumerable();
var availableDrives = PInvoke.GetLogicalDrives();
if (availableDrives is 0)
return Enumerable.Empty<IStorableChild>().ToAsyncEnumerable();

IEnumerable<IStorableChild> GetLogicalDrives()
{
var availableDrives = PInvoke.GetLogicalDrives();
if (availableDrives is 0)
yield break;

int count = BitOperations.PopCount(availableDrives);
var driveLetters = new char[count];
int count = BitOperations.PopCount(availableDrives);
var driveLetters = new char[count];

count = 0;
char driveLetter = 'A';
while (availableDrives is not 0)
{
if ((availableDrives & 1) is not 0)
driveLetters[count++] = driveLetter;
count = 0;
char driveLetter = 'A';
while (availableDrives is not 0)
{
if ((availableDrives & 1) is not 0)
driveLetters[count++] = driveLetter;

availableDrives >>= 1;
driveLetter++;
}
availableDrives >>= 1;
driveLetter++;
}

foreach (char letter in driveLetters)
{
cancellationToken.ThrowIfCancellationRequested();
List<IStorableChild> driveItems = [];
foreach (char letter in driveLetters)
{
cancellationToken.ThrowIfCancellationRequested();

if (WindowsStorable.TryParse($"{letter}:\\") is not IWindowsStorable driveRoot)
throw new InvalidOperationException();
if (WindowsStorable.TryParse($"{letter}:\\") is not IWindowsStorable driveRoot)
throw new InvalidOperationException();

yield return new WindowsFolder(driveRoot.ThisPtr);
}
driveItems.Add(new WindowsFolder(driveRoot.ThisPtr));
}

return driveItems.ToAsyncEnumerable();
}

/// <inheritdoc/>
Expand Down
19 changes: 19 additions & 0 deletions src/Files.App.Storage/Storables/WindowsStorage/ContextMenuItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

namespace Files.App.Storage
{
/// <summary>
/// Represents a Windows Shell ContextMenu item.
/// </summary>
public partial class ContextMenuItem
{
public ContextMenuType Type { get; set; }

public uint Id { get; set; }

public byte[]? Icon { get; set; }

public string? Name { get; set; }
}
}
18 changes: 18 additions & 0 deletions src/Files.App.Storage/Storables/WindowsStorage/ContextMenuType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

namespace Files.App.Storage
{
public enum ContextMenuType
{
Normal = 0x00000000,

Disabled = 0x00000003,

Checked = 0x00000008,

Highlighted = 0x00000080,

Default = 0x00001000,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

namespace Files.App.Storage
{
public interface IWindowsFile : IWindowsStorable, IChildFile
{
}
}
15 changes: 15 additions & 0 deletions src/Files.App.Storage/Storables/WindowsStorage/IWindowsFolder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

using Windows.Win32.UI.Shell;

namespace Files.App.Storage
{
public unsafe interface IWindowsFolder : IWindowsStorable, IChildFolder
{
/// <summary>
/// Gets or sets the cached <see cref="IContextMenu"/> for the ShellNew context menu.
/// </summary>
public IContextMenu* ShellNewMenu { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

using Windows.Win32;
using Windows.Win32.UI.Shell;

namespace Files.App.Storage
{
public interface IWindowsStorable : IDisposable
public unsafe interface IWindowsStorable : IStorableChild, IEquatable<IWindowsStorable>, IDisposable
{
ComPtr<IShellItem> ThisPtr { get; }
IShellItem* ThisPtr { get; set; }

IContextMenu* ContextMenu { get; set; }
}
}
47 changes: 22 additions & 25 deletions src/Files.App.Storage/Storables/WindowsStorage/STATask.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
// Copyright (c) Files Community
// Licensed under the MIT License.

using Microsoft.Extensions.Logging;
using Windows.Win32;

namespace Files.App.Storage
{
/// <summary>
/// Represents an asynchronous operation on STA.
/// Represents a synchronous/asynchronous operation on STA.
/// </summary>
public partial class STATask
{
public static Task Run(Action action)
public static Task Run(Action action, ILogger? logger = null)
{
var tcs = new TaskCompletionSource();

Expand All @@ -26,25 +27,24 @@ public static Task Run(Action action)
}
catch (Exception ex)
{
tcs.SetResult();
logger?.LogWarning(ex, "An exception was occurred during the execution within STA.");
tcs.SetException(ex);
}
finally
{
PInvoke.OleUninitialize();
}
})
{
IsBackground = true,
Priority = ThreadPriority.Normal
};
});

thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

return tcs.Task;
}

public static Task<T> Run<T>(Func<T> func)
public static Task<T> Run<T>(Func<T> func, ILogger? logger = null)
{
var tcs = new TaskCompletionSource<T>();

Expand All @@ -59,25 +59,24 @@ public static Task<T> Run<T>(Func<T> func)
}
catch (Exception ex)
{
tcs.SetResult(default!);
logger?.LogWarning(ex, "An exception was occurred during the execution within STA.");
tcs.SetException(ex);
}
finally
{
PInvoke.OleUninitialize();
}
})
{
IsBackground = true,
Priority = ThreadPriority.Normal
};
});

thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

return tcs.Task;
}

public static Task Run(Func<Task> func)
public static Task Run(Func<Task> func, ILogger? logger = null)
{
var tcs = new TaskCompletionSource();

Expand All @@ -93,25 +92,24 @@ public static Task Run(Func<Task> func)
}
catch (Exception ex)
{
tcs.SetResult();
logger?.LogWarning(ex, "An exception was occurred during the execution within STA.");
tcs.SetException(ex);
}
finally
{
PInvoke.OleUninitialize();
}
})
{
IsBackground = true,
Priority = ThreadPriority.Normal
};
});

thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

return tcs.Task;
}

public static Task<T?> Run<T>(Func<Task<T>> func)
public static Task<T?> Run<T>(Func<Task<T>> func, ILogger? logger = null)
{
var tcs = new TaskCompletionSource<T?>();

Expand All @@ -126,18 +124,17 @@ public static Task Run(Func<Task> func)
}
catch (Exception ex)
{
tcs.SetResult(default);
logger?.LogWarning(ex, "An exception was occurred during the execution within STA.");
tcs.SetException(ex);
}
finally
{
PInvoke.OleUninitialize();
}
})
{
IsBackground = true,
Priority = ThreadPriority.Normal
};
});

thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Expand Down
Loading
Loading