Skip to content

Commit db2aa56

Browse files
authored
Browse zip archives & other things (#5885)
1 parent 97d178e commit db2aa56

File tree

79 files changed

+4050
-852
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+4050
-852
lines changed

Files.Launcher/MessageHandlers/FileOperationsHandler.cs

+32-8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,30 @@ private async Task ParseFileOperationAsync(NamedPipeServerStream connection, Dic
4747
{
4848
switch (message.Get("fileop", ""))
4949
{
50+
case "GetFileHandle":
51+
{
52+
var filePath = (string)message["filepath"];
53+
var readWrite = (bool)message["readwrite"];
54+
using var hFile = Kernel32.CreateFile(filePath, Kernel32.FileAccess.GENERIC_READ | (readWrite ? Kernel32.FileAccess.GENERIC_WRITE : 0), FileShare.ReadWrite, null, FileMode.Open, FileFlagsAndAttributes.FILE_ATTRIBUTE_NORMAL);
55+
if (hFile.IsInvalid)
56+
{
57+
await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null));
58+
return;
59+
}
60+
var processId = (int)(long)message["processid"];
61+
using var uwpProces = System.Diagnostics.Process.GetProcessById(processId);
62+
if (!Kernel32.DuplicateHandle(Kernel32.GetCurrentProcess(), hFile.DangerousGetHandle(), uwpProces.Handle, out var targetHandle, 0, false, Kernel32.DUPLICATE_HANDLE_OPTIONS.DUPLICATE_SAME_ACCESS))
63+
{
64+
await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null));
65+
return;
66+
}
67+
await Win32API.SendMessageAsync(connection, new ValueSet() {
68+
{ "Success", true },
69+
{ "Handle", targetHandle.ToInt64() }
70+
}, message.Get("RequestID", (string)null));
71+
}
72+
break;
73+
5074
case "Clipboard":
5175
await Win32API.StartSTATask(() =>
5276
{
@@ -158,7 +182,7 @@ await Win32API.StartSTATask(() =>
158182
shellOperationResult.Items.Add(new ShellOperationItemResult()
159183
{
160184
Succeeded = e.Result.Succeeded,
161-
Source = e.SourceItem.FileSystemPath,
185+
Source = e.SourceItem.FileSystemPath ?? e.SourceItem.ParsingName,
162186
Destination = e.DestItem?.FileSystemPath,
163187
HRresult = (int)e.Result
164188
});
@@ -224,7 +248,7 @@ await Win32API.StartSTATask(() =>
224248
shellOperationResult.Items.Add(new ShellOperationItemResult()
225249
{
226250
Succeeded = e.Result.Succeeded,
227-
Source = e.SourceItem.FileSystemPath,
251+
Source = e.SourceItem.FileSystemPath ?? e.SourceItem.ParsingName,
228252
Destination = !string.IsNullOrEmpty(e.Name) ? Path.Combine(Path.GetDirectoryName(e.SourceItem.FileSystemPath), e.Name) : null,
229253
HRresult = (int)e.Result
230254
});
@@ -288,8 +312,8 @@ await Win32API.StartSTATask(() =>
288312
shellOperationResult.Items.Add(new ShellOperationItemResult()
289313
{
290314
Succeeded = e.Result.Succeeded,
291-
Source = e.SourceItem.FileSystemPath,
292-
Destination = e.DestFolder != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null,
315+
Source = e.SourceItem.FileSystemPath ?? e.SourceItem.ParsingName,
316+
Destination = e.DestFolder?.FileSystemPath != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null,
293317
HRresult = (int)e.Result
294318
});
295319
};
@@ -363,8 +387,8 @@ await Win32API.StartSTATask(() =>
363387
shellOperationResult.Items.Add(new ShellOperationItemResult()
364388
{
365389
Succeeded = e.Result.Succeeded,
366-
Source = e.SourceItem.FileSystemPath,
367-
Destination = e.DestFolder != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null,
390+
Source = e.SourceItem.FileSystemPath ?? e.SourceItem.ParsingName,
391+
Destination = e.DestFolder?.FileSystemPath != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null,
368392
HRresult = (int)e.Result
369393
});
370394
};
@@ -566,8 +590,8 @@ private void UpdateFileTageDb(object sender, ShellFileOperations.ShellFileOpEven
566590
{
567591
"delete" => e.DestItem?.FileSystemPath,
568592
"rename" => (!string.IsNullOrEmpty(e.Name) ? Path.Combine(Path.GetDirectoryName(e.SourceItem.FileSystemPath), e.Name) : null),
569-
"copy" => (e.DestFolder != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null),
570-
_ => (e.DestFolder != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null)
593+
"copy" => (e.DestFolder?.FileSystemPath != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null),
594+
_ => (e.DestFolder?.FileSystemPath != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null)
571595
};
572596
if (destination == null)
573597
{

Files.Launcher/Program.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Files.Common;
2-
using FilesFullTrust.Helpers;
32
using FilesFullTrust.MessageHandlers;
43
using Newtonsoft.Json;
54
using System;
@@ -235,7 +234,7 @@ private static async Task ParseArgumentsAsync(Dictionary<string, object> message
235234
{
236235
await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", -1 } }, message.Get("RequestID", (string)null));
237236
}
238-
break;
237+
break;
239238

240239
default:
241240
foreach (var mh in messageHandlers)

Files.Package/Package.appxmanifest

+7
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959
</uap5:AppExecutionAlias>
6060
</uap5:Extension>
6161
<Extension Category="windows.updateTask" EntryPoint="BackgroundTasks.UpdateTask" />
62+
<uap:Extension Category="windows.fileTypeAssociation">
63+
<uap:FileTypeAssociation Name="zip">
64+
<uap:SupportedFileTypes>
65+
<uap:FileType>.zip</uap:FileType>
66+
</uap:SupportedFileTypes>
67+
</uap:FileTypeAssociation>
68+
</uap:Extension>
6269
</Extensions>
6370
</Application>
6471
</Applications>

Files/App.xaml.cs

+59-29
Original file line numberDiff line numberDiff line change
@@ -129,32 +129,16 @@ private void OnLeavingBackground(object sender, LeavingBackgroundEventArgs e)
129129
protected override async void OnLaunched(LaunchActivatedEventArgs e)
130130
{
131131
await logWriter.InitializeAsync("debug.log");
132+
Logger.Info($"App launched. Prelaunch: {e.PrelaunchActivated}");
133+
132134
//start tracking app usage
133135
SystemInformation.Instance.TrackAppUse(e);
134136

135-
Logger.Info("App launched");
136-
137137
bool canEnablePrelaunch = ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch");
138138

139139
await EnsureSettingsAndConfigurationAreBootstrapped();
140140

141-
// Do not repeat app initialization when the Window already has content,
142-
// just ensure that the window is active
143-
if (!(Window.Current.Content is Frame rootFrame))
144-
{
145-
// Create a Frame to act as the navigation context and navigate to the first page
146-
rootFrame = new Frame();
147-
rootFrame.CacheSize = 1;
148-
rootFrame.NavigationFailed += OnNavigationFailed;
149-
150-
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
151-
{
152-
//TODO: Load state from previously suspended application
153-
}
154-
155-
// Place the frame in the current Window
156-
Window.Current.Content = rootFrame;
157-
}
141+
var rootFrame = EnsureWindowIsInitialized();
158142

159143
if (e.PrelaunchActivated == false)
160144
{
@@ -184,6 +168,60 @@ protected override async void OnLaunched(LaunchActivatedEventArgs e)
184168
}
185169
}
186170

171+
protected override async void OnFileActivated(FileActivatedEventArgs e)
172+
{
173+
await logWriter.InitializeAsync("debug.log");
174+
Logger.Info("App activated by file");
175+
176+
//start tracking app usage
177+
SystemInformation.Instance.TrackAppUse(e);
178+
179+
await EnsureSettingsAndConfigurationAreBootstrapped();
180+
181+
var rootFrame = EnsureWindowIsInitialized();
182+
183+
var index = 0;
184+
if (rootFrame.Content == null)
185+
{
186+
// When the navigation stack isn't restored navigate to the first page,
187+
// configuring the new page by passing required information as a navigation
188+
// parameter
189+
rootFrame.Navigate(typeof(MainPage), e.Files.First().Path, new SuppressNavigationTransitionInfo());
190+
index = 1;
191+
}
192+
for (; index < e.Files.Count; index++)
193+
{
194+
await MainPageViewModel.AddNewTabByPathAsync(typeof(PaneHolderPage), e.Files[index].Path);
195+
}
196+
197+
// Ensure the current window is active
198+
Window.Current.Activate();
199+
Window.Current.CoreWindow.Activated += CoreWindow_Activated;
200+
}
201+
202+
private Frame EnsureWindowIsInitialized()
203+
{
204+
// Do not repeat app initialization when the Window already has content,
205+
// just ensure that the window is active
206+
if (!(Window.Current.Content is Frame rootFrame))
207+
{
208+
// Create a Frame to act as the navigation context and navigate to the first page
209+
rootFrame = new Frame();
210+
rootFrame.CacheSize = 1;
211+
rootFrame.NavigationFailed += OnNavigationFailed;
212+
213+
//if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
214+
//{
215+
// //TODO: Load state from previously suspended application
216+
//}
217+
218+
// Place the frame in the current Window
219+
Window.Current.Content = rootFrame;
220+
}
221+
222+
return rootFrame;
223+
}
224+
187225
private void CoreWindow_Activated(CoreWindow sender, WindowActivatedEventArgs args)
188226
{
189227
if (args.WindowActivationState == CoreWindowActivationState.CodeActivated ||
@@ -201,20 +239,12 @@ private void CoreWindow_Activated(CoreWindow sender, WindowActivatedEventArgs ar
201239
protected override async void OnActivated(IActivatedEventArgs args)
202240
{
203241
await logWriter.InitializeAsync("debug.log");
204-
205-
Logger.Info("App activated");
242+
Logger.Info($"App activated by {args.Kind.ToString()}");
206243

207244
await EnsureSettingsAndConfigurationAreBootstrapped();
208245

209-
// Window management
210-
if (!(Window.Current.Content is Frame rootFrame))
211-
{
212-
rootFrame = new Frame();
213-
rootFrame.CacheSize = 1;
214-
Window.Current.Content = rootFrame;
215-
}
246+
var rootFrame = EnsureWindowIsInitialized();
216247

217-
var currentView = SystemNavigationManager.GetForCurrentView();
218248
switch (args.Kind)
219249
{
220250
case ActivationKind.Protocol:

Files/BaseLayout.cs

+23-5
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ protected override async void OnNavigatedTo(NavigationEventArgs eventArgs)
433433
ParentShellPageInstance.InstanceViewModel.IsPageTypeRecycleBin = workingDir.StartsWith(App.AppSettings.RecycleBinPath);
434434
ParentShellPageInstance.InstanceViewModel.IsPageTypeMtpDevice = workingDir.StartsWith("\\\\?\\");
435435
ParentShellPageInstance.InstanceViewModel.IsPageTypeFtp = FtpHelpers.IsFtpPath(workingDir);
436+
ParentShellPageInstance.InstanceViewModel.IsPageTypeZipFolder = ZipStorageFolder.IsZipPath(workingDir);
436437
ParentShellPageInstance.InstanceViewModel.IsPageTypeSearchResults = false;
437438
ParentShellPageInstance.NavToolbarViewModel.PathControlDisplayText = navigationArguments.NavPathParam;
438439
if (!navigationArguments.IsLayoutSwitch)
@@ -453,6 +454,7 @@ protected override async void OnNavigatedTo(NavigationEventArgs eventArgs)
453454
ParentShellPageInstance.InstanceViewModel.IsPageTypeRecycleBin = false;
454455
ParentShellPageInstance.InstanceViewModel.IsPageTypeFtp = false;
455456
ParentShellPageInstance.InstanceViewModel.IsPageTypeMtpDevice = false;
457+
ParentShellPageInstance.InstanceViewModel.IsPageTypeZipFolder = false;
456458
ParentShellPageInstance.InstanceViewModel.IsPageTypeSearchResults = true;
457459
if (!navigationArguments.IsLayoutSwitch)
458460
{
@@ -588,7 +590,10 @@ public async void BaseContextFlyout_Opening(object sender, object e)
588590
return;
589591
}
590592

591-
AddShellItemsToMenu(shellMenuItems, BaseContextMenuFlyout, shiftPressed);
593+
if (!InstanceViewModel.IsPageTypeZipFolder)
594+
{
595+
AddShellItemsToMenu(shellMenuItems, BaseContextMenuFlyout, shiftPressed);
596+
}
592597
}
593598
}
594599
catch (Exception error)
@@ -619,7 +624,7 @@ private async Task LoadMenuItemsAsync()
619624
secondaryElements.OfType<FrameworkElement>().ForEach(i => i.MinWidth = 250); // Set menu min width
620625
secondaryElements.ForEach(i => ItemContextMenuFlyout.SecondaryCommands.Add(i));
621626

622-
if (AppSettings.AreFileTagsEnabled && !InstanceViewModel.IsPageTypeSearchResults && !InstanceViewModel.IsPageTypeRecycleBin && !InstanceViewModel.IsPageTypeFtp)
627+
if (AppSettings.AreFileTagsEnabled && !InstanceViewModel.IsPageTypeSearchResults && !InstanceViewModel.IsPageTypeRecycleBin && !InstanceViewModel.IsPageTypeFtp && !InstanceViewModel.IsPageTypeZipFolder)
623628
{
624629
AddFileTagsItemToMenu(ItemContextMenuFlyout);
625630
}
@@ -630,7 +635,10 @@ private async Task LoadMenuItemsAsync()
630635
return;
631636
}
632637

633-
AddShellItemsToMenu(shellMenuItems, ItemContextMenuFlyout, shiftPressed);
638+
if (!InstanceViewModel.IsPageTypeZipFolder)
639+
{
640+
AddShellItemsToMenu(shellMenuItems, ItemContextMenuFlyout, shiftPressed);
641+
}
634642
}
635643

636644
private void AddFileTagsItemToMenu(Microsoft.UI.Xaml.Controls.CommandBarFlyout contextMenu)
@@ -771,10 +779,14 @@ protected async void FileList_DragItemsStarting(object sender, DragItemsStarting
771779
{
772780
if (item.PrimaryItemAttribute == StorageItemTypes.File)
773781
{
774-
selectedStorageItems.Add(await new FtpStorageFile(ParentShellPageInstance.FilesystemViewModel, ftpItem).ToStorageFileAsync());
782+
selectedStorageItems.Add(await new FtpStorageFile(ftpItem).ToStorageFileAsync());
783+
}
784+
else if (item.PrimaryItemAttribute == StorageItemTypes.Folder)
785+
{
786+
selectedStorageItems.Add(new FtpStorageFolder(ftpItem));
775787
}
776788
}
777-
else if (item.PrimaryItemAttribute == StorageItemTypes.File)
789+
else if (item.PrimaryItemAttribute == StorageItemTypes.File || item is ZipItem)
778790
{
779791
result = await ParentShellPageInstance.FilesystemViewModel.GetFileFromPathAsync(item.ItemPath)
780792
.OnSuccess(t => selectedStorageItems.Add(t));
@@ -907,6 +919,12 @@ protected async void Item_DragOver(object sender, DragEventArgs e)
907919
e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), item.ItemName);
908920
e.AcceptedOperation = DataPackageOperation.Move;
909921
}
922+
else if (draggedItems.Any(x => x.Item is ZipStorageFile || x.Item is ZipStorageFolder)
923+
|| ZipStorageFolder.IsZipPath(item.ItemPath))
924+
{
925+
e.DragUIOverride.Caption = string.Format("CopyToFolderCaptionText".GetLocalized(), item.ItemName);
926+
e.AcceptedOperation = DataPackageOperation.Copy;
927+
}
910928
else if (draggedItems.AreItemsInSameDrive(item.ItemPath))
911929
{
912930
e.DragUIOverride.Caption = string.Format("MoveToFolderCaptionText".GetLocalized(), item.ItemName);

Files/DataModels/FilesystemItemsOperationDataModel.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public async Task<List<FilesystemOperationItemViewModel>> ToItems(Action updateP
6666
// Add conflicting items first
6767
foreach (var item in ConflictingItems)
6868
{
69-
var iconData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(item.SourcePath, 64u);
69+
var iconData = await FileThumbnailHelper.LoadIconFromPathAsync(item.SourcePath, 64u, Windows.Storage.FileProperties.ThumbnailMode.ListView);
7070

7171
items.Add(new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip)
7272
{
@@ -84,7 +84,7 @@ public async Task<List<FilesystemOperationItemViewModel>> ToItems(Action updateP
8484
// Then add non-conflicting items
8585
foreach (var item in nonConflictingItems)
8686
{
87-
var iconData = await FileThumbnailHelper.LoadIconWithoutOverlayAsync(item.SourcePath, 64u);
87+
var iconData = await FileThumbnailHelper.LoadIconFromPathAsync(item.SourcePath, 64u, Windows.Storage.FileProperties.ThumbnailMode.ListView);
8888

8989
items.Add(new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip)
9090
{

0 commit comments

Comments
 (0)