Skip to content

Commit f5cff37

Browse files
Init
Co-Authored-By: Dongle <[email protected]>
1 parent dde3ee7 commit f5cff37

21 files changed

+1004
-391
lines changed

src/Files.App.CsWin32/Extras.cs

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public static unsafe nint SetWindowLongPtr(HWND hWnd, WINDOW_LONG_PTR_INDEX nInd
3737
? (nint)_SetWindowLong(hWnd, (int)nIndex, (int)dwNewLong)
3838
: _SetWindowLongPtr(hWnd, (int)nIndex, dwNewLong);
3939
}
40+
41+
[DllImport("User32", EntryPoint = "SHUpdateRecycleBinIcon")]
42+
public static extern void SHUpdateRecycleBinIcon();
4043
}
4144

4245
namespace Extras
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
// Copyright (c) Files Community
22
// Licensed under the MIT License.
33

4+
using System.Diagnostics;
45
using System.Runtime.InteropServices;
5-
using Windows.Win32.Foundation;
66

7-
namespace Windows.Win32
7+
namespace Windows.Win32.Foundation
88
{
9-
public static class HRESULTExtensions
9+
[DebuggerDisplay("{" + nameof(Value) + ",h}")]
10+
public readonly partial struct HRESULT
1011
{
1112
/// <summary>
1213
/// Throws an exception if the <see cref="HRESULT"/> indicates a failure in debug mode. Otherwise, it returns the original <see cref="HRESULT"/>.
1314
/// </summary>
14-
/// <param name="hr">Represents the result of an operation, indicating success or failure.</param>
1515
/// <returns>Returns the original <see cref="HRESULT"/> value regardless of the operation's success.</returns>
16-
public static HRESULT ThrowIfFailedOnDebug(this HRESULT hr)
16+
public readonly HRESULT ThrowIfFailedOnDebug()
1717
{
1818
#if DEBUG
19-
if (hr.Failed)
20-
Marshal.ThrowExceptionForHR(hr.Value);
19+
if (Failed) Marshal.ThrowExceptionForHR(Value);
2120
#endif
2221

23-
return hr;
22+
return this;
2423
}
2524
}
2625
}

src/Files.App.CsWin32/NativeMethods.txt

+19
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,22 @@ FILE_FILE_COMPRESSION
172172
WM_WINDOWPOSCHANGING
173173
WINDOWPOS
174174
UnregisterClass
175+
E_POINTER
176+
E_NOINTERFACE
177+
E_FAIL
178+
IShellFolder
179+
FILE_FLAGS_AND_ATTRIBUTES
180+
GetLogicalDrives
181+
IShellItemImageFactory
182+
GdipCreateBitmapFromHBITMAP
183+
GdipGetImageEncodersSize
184+
GdipGetImageEncoders
185+
ImageFormatPNG
186+
ImageFormatJPEG
187+
EncoderParameters
188+
IStream
189+
CreateStreamOnHGlobal
190+
STATFLAG
191+
STREAM_SEEK
192+
GdipSaveImageToStream
193+
GdipGetImageRawFormat

src/Files.App.Storage/Files.App.Storage.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
<Configurations>Debug;Release</Configurations>
1010
<Platforms>x86;x64;arm64</Platforms>
1111
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
12+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
1213
</PropertyGroup>
1314

1415
<ItemGroup>
1516
<PackageReference Include="FluentFTP" />
1617
</ItemGroup>
1718

1819
<ItemGroup>
20+
<ProjectReference Include="..\Files.App.CsWin32\Files.App.CsWin32.csproj" />
1921
<ProjectReference Include="..\Files.Core.Storage\Files.Core.Storage.csproj" />
2022
<ProjectReference Include="..\Files.Shared\Files.Shared.csproj" />
2123
</ItemGroup>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
using System.Numerics;
5+
using System.Runtime.CompilerServices;
6+
using Windows.Win32;
7+
8+
namespace Files.App.Storage.Storables
9+
{
10+
public partial class HomeFolder : IHomeFolder
11+
{
12+
public string Id => "Home"; // Will be "files://Home" in the future.
13+
14+
public string Name => "Home";
15+
16+
/// <inheritdoc/>
17+
public async IAsyncEnumerable<IStorableChild> GetItemsAsync(StorableType type = StorableType.Folder, [EnumeratorCancellation] CancellationToken cancellationToken = default)
18+
{
19+
await foreach (var folder in GetQuickAccessFolderAsync(cancellationToken))
20+
{
21+
cancellationToken.ThrowIfCancellationRequested();
22+
23+
yield return folder;
24+
}
25+
26+
await foreach (var drive in GetLogicalDrivesAsync(cancellationToken))
27+
{
28+
cancellationToken.ThrowIfCancellationRequested();
29+
30+
yield return drive;
31+
}
32+
33+
await foreach (var location in GetNetworkLocationsAsync(cancellationToken))
34+
{
35+
cancellationToken.ThrowIfCancellationRequested();
36+
37+
yield return location;
38+
}
39+
}
40+
41+
/// <inheritdoc/>
42+
public IAsyncEnumerable<IStorableChild> GetQuickAccessFolderAsync(CancellationToken cancellationToken = default)
43+
{
44+
IFolder folder = new WindowsFolder(new Guid("3936e9e4-d92c-4eee-a85a-bc16d5ea0819"));
45+
return folder.GetItemsAsync(StorableType.Folder, cancellationToken);
46+
}
47+
48+
/// <inheritdoc/>
49+
public async IAsyncEnumerable<IStorableChild> GetLogicalDrivesAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
50+
{
51+
var availableDrives = PInvoke.GetLogicalDrives();
52+
if (availableDrives is 0)
53+
yield break;
54+
55+
int count = BitOperations.PopCount(availableDrives);
56+
var driveLetters = new char[count];
57+
58+
count = 0;
59+
char driveLetter = 'A';
60+
while (availableDrives is not 0)
61+
{
62+
if ((availableDrives & 1) is not 0)
63+
driveLetters[count++] = driveLetter;
64+
65+
availableDrives >>= 1;
66+
driveLetter++;
67+
}
68+
69+
foreach (int letter in driveLetters)
70+
{
71+
cancellationToken.ThrowIfCancellationRequested();
72+
73+
if (!WindowsStorable.TryParse($"{letter}:\\", out var driveRoot) || driveRoot is null)
74+
throw new InvalidOperationException();
75+
76+
yield return new WindowsFolder(driveRoot.ThisPtr);
77+
await Task.Yield();
78+
}
79+
80+
}
81+
82+
/// <inheritdoc/>
83+
public IAsyncEnumerable<IStorableChild> GetNetworkLocationsAsync(CancellationToken cancellationToken = default)
84+
{
85+
Guid FOLDERID_NetHood = new("{C5ABBF53-E17F-4121-8900-86626FC2C973}");
86+
IFolder folder = new WindowsFolder(FOLDERID_NetHood);
87+
return folder.GetItemsAsync(StorableType.Folder, cancellationToken);
88+
}
89+
90+
/// <inheritdoc/>
91+
public IAsyncEnumerable<IStorableChild> GetRecentFilesAsync(CancellationToken cancellationToken = default)
92+
{
93+
Guid FOLDERID_NetHood = new("{AE50C081-EBD2-438A-8655-8A092E34987A}");
94+
IFolder folder = new WindowsFolder(FOLDERID_NetHood);
95+
return folder.GetItemsAsync(StorableType.Folder, cancellationToken);
96+
}
97+
}
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
namespace Files.App.Storage.Storables
5+
{
6+
public partial interface IHomeFolder : IFolder
7+
{
8+
/// <summary>
9+
/// Gets quick access folders.
10+
/// </summary>
11+
/// <param name="cancellationToken">The cancellation token.</param>
12+
/// <returns>A list of the collection.</returns>
13+
public IAsyncEnumerable<IStorableChild> GetQuickAccessFolderAsync(CancellationToken cancellationToken = default);
14+
15+
/// <summary>
16+
/// Gets available logical drives.
17+
/// </summary>
18+
/// <param name="cancellationToken">The cancellation token.</param>
19+
/// <returns>A list of the collection.</returns>
20+
public IAsyncEnumerable<IStorableChild> GetLogicalDrivesAsync(CancellationToken cancellationToken = default);
21+
22+
/// <summary>
23+
/// Gets network locations(shortcuts).
24+
/// </summary>
25+
/// <param name="cancellationToken">The cancellation token.</param>
26+
/// <returns>A list of the collection.</returns>
27+
public IAsyncEnumerable<IStorableChild> GetNetworkLocationsAsync(CancellationToken cancellationToken = default);
28+
29+
/// <summary>
30+
/// Gets recent files.
31+
/// </summary>
32+
/// <param name="cancellationToken">The cancellation token.</param>
33+
/// <returns>A list of the collection.</returns>
34+
public IAsyncEnumerable<IStorableChild> GetRecentFilesAsync(CancellationToken cancellationToken = default);
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
using Windows.Win32;
5+
using Windows.Win32.UI.Shell;
6+
7+
namespace Files.App.Storage.Storables
8+
{
9+
public interface IWindowsStorable
10+
{
11+
ComPtr<IShellItem> ThisPtr { get; }
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
using Windows.Win32;
5+
using Windows.Win32.Foundation;
6+
using Windows.Win32.Storage.FileSystem;
7+
using Windows.Win32.System.Com;
8+
using Windows.Win32.UI.Shell;
9+
10+
namespace Files.App.Storage.Storables
11+
{
12+
public sealed partial class WindowsBulkOperations : IDisposable
13+
{
14+
// Fields
15+
16+
private readonly ComPtr<IFileOperation> _pFileOperation;
17+
private readonly ComPtr<IFileOperationProgressSink> _pProgressSink;
18+
private readonly uint _progressSinkCookie;
19+
20+
private int _disposedValue = 0;
21+
22+
// Events
23+
24+
public event EventHandler<WindowsBulkOperationsEventArgs>? OperationsFinished;
25+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemCopied;
26+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemDeleted;
27+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemMoved;
28+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemCreated;
29+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemRenamed;
30+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemCopying;
31+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemDeleting;
32+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemMoving;
33+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemCreating;
34+
public event EventHandler<WindowsBulkOperationsEventArgs>? ItemRenaming;
35+
public event EventHandler? OperationsStarted;
36+
public event ProgressChangedEventHandler? ProgressUpdated;
37+
38+
// Constructor
39+
40+
public unsafe WindowsBulkOperations(HWND owner = default, FILEOPERATION_FLAGS flags = FILEOPERATION_FLAGS.FOF_ALLOWUNDO | FILEOPERATION_FLAGS.FOF_NOCONFIRMMKDIR)
41+
{
42+
var clsid = typeof(FileOperation).GUID;
43+
var iid = typeof(IFileOperation).GUID;
44+
45+
HRESULT hr = PInvoke.CoCreateInstance(
46+
&clsid,
47+
null,
48+
CLSCTX.CLSCTX_LOCAL_SERVER,
49+
&iid,
50+
(void**)_pFileOperation.GetAddressOf());
51+
52+
if (owner != default)
53+
hr = _pFileOperation.Get()->SetOwnerWindow(owner);
54+
55+
hr = _pFileOperation.Get()->SetOperationFlags(flags);
56+
57+
_pProgressSink.Attach((IFileOperationProgressSink*)WindowsBulkOperationsSink.Create(this));
58+
hr = _pFileOperation.Get()->Advise(_pProgressSink.Get(), out var progressSinkCookie);
59+
_progressSinkCookie = progressSinkCookie;
60+
}
61+
62+
public unsafe HRESULT QueueCopyOperation(WindowsStorable targetItem, WindowsFolder destinationFolder, string? copyName)
63+
{
64+
fixed (char* pszCopyName = copyName)
65+
return _pFileOperation.Get()->CopyItem(targetItem.ThisPtr.Get(), destinationFolder.ThisPtr.Get(), pszCopyName, _pProgressSink.Get());
66+
}
67+
68+
public unsafe HRESULT QueueDeleteOperation(WindowsStorable targetItem)
69+
{
70+
return _pFileOperation.Get()->DeleteItem(targetItem.ThisPtr.Get(), _pProgressSink.Get());
71+
}
72+
73+
public unsafe HRESULT QueueMoveOperation(WindowsStorable targetItem, WindowsFolder destinationFolder, string? newName)
74+
{
75+
fixed (char* pszNewName = newName)
76+
return _pFileOperation.Get()->MoveItem(targetItem.ThisPtr.Get(), destinationFolder.ThisPtr.Get(), pszNewName, null);
77+
}
78+
79+
public unsafe HRESULT QueueCreateOperation(WindowsFolder destinationFolder, FILE_FLAGS_AND_ATTRIBUTES fileAttributes, string name, string? templateName)
80+
{
81+
fixed (char* pszName = name, pszTemplateName = templateName)
82+
return _pFileOperation.Get()->NewItem(destinationFolder.ThisPtr.Get(), (uint)fileAttributes, pszName, pszTemplateName, _pProgressSink.Get());
83+
}
84+
85+
public unsafe HRESULT QueueRenameOperation(WindowsStorable targetItem, string newName)
86+
{
87+
fixed (char* pszNewName = newName)
88+
return _pFileOperation.Get()->RenameItem(targetItem.ThisPtr.Get(), pszNewName, _pProgressSink.Get());
89+
}
90+
91+
public unsafe HRESULT PerformAllOperations()
92+
{
93+
return _pFileOperation.Get()->PerformOperations();
94+
}
95+
96+
public unsafe void Dispose()
97+
{
98+
_pFileOperation.Get()->Unadvise(_progressSinkCookie);
99+
_pFileOperation.Dispose();
100+
_pProgressSink.Dispose();
101+
}
102+
}
103+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
using System.Runtime.CompilerServices;
5+
using Windows.Win32;
6+
using Windows.Win32.Foundation;
7+
using Windows.Win32.System.Com;
8+
using Windows.Win32.UI.Shell;
9+
10+
namespace Files.App.Storage.Storables
11+
{
12+
public class WindowsBulkOperationsEventArgs : EventArgs
13+
{
14+
}
15+
}

0 commit comments

Comments
 (0)