public static ContextMenu GetContextMenuForFiles(string[] filePathList, Shell32.CMF flags, Func <string, bool> itemFilter = null) { List <ShellItem> shellItems = new List <ShellItem>(); try { foreach (var fp in filePathList.Where(x => !string.IsNullOrEmpty(x))) { shellItems.Add(ShellFolderExtensions.GetShellItemFromPathOrPidl(fp)); } return(GetContextMenuForFiles(shellItems.ToArray(), flags, itemFilter)); } catch (Exception ex) when(ex is ArgumentException || ex is FileNotFoundException) { // Return empty context menu return(null); } finally { foreach (var si in shellItems) { si.Dispose(); } } }
private async void RecycleBinWatcher_Changed(object sender, FileSystemEventArgs e) { System.Diagnostics.Debug.WriteLine($"Recycle bin event: {e.ChangeType}, {e.FullPath}"); if (e.Name.StartsWith("$I")) { // Recycle bin also stores a file starting with $I for each item return; } if (connection?.IsConnected ?? false) { var response = new ValueSet() { { "FileSystem", @"Shell:RecycleBinFolder" }, { "Path", e.FullPath }, { "Type", e.ChangeType.ToString() } }; if (e.ChangeType == WatcherChangeTypes.Created) { using var folderItem = new ShellItem(e.FullPath); var shellFileItem = ShellFolderExtensions.GetShellFileItem(folderItem); response["Item"] = JsonConvert.SerializeObject(shellFileItem); } // Send message to UWP app to refresh items await Win32API.SendMessageAsync(connection, response); } }
private async Task ParseNetworkDriveOperationAsync(PipeStream connection, Dictionary <string, object> message) { switch (message.Get("netdriveop", "")) { case "GetNetworkLocations": var networkLocations = await Win32API.StartSTATask(() => { var locations = new List <ShellLinkItem>(); using (var nethood = new ShellFolder(Shell32.KNOWNFOLDERID.FOLDERID_NetHood)) { foreach (var item in nethood) { if (item is ShellLink link) { locations.Add(ShellFolderExtensions.GetShellLinkItem(link)); } else { var linkPath = (string)item.Properties["System.Link.TargetParsingPath"]; if (linkPath != null) { var linkItem = ShellFolderExtensions.GetShellFileItem(item); locations.Add(new ShellLinkItem(linkItem) { TargetPath = linkPath }); } } } } return(locations); }); var response = new ValueSet { { "NetworkLocations", JsonConvert.SerializeObject(networkLocations) } }; await Win32API.SendMessageAsync(connection, response, message.Get("RequestID", (string)null)); break; case "OpenMapNetworkDriveDialog": var hwnd = (long)message["HWND"]; _ = NetworkDrivesAPI.OpenMapNetworkDriveDialog(hwnd); break; case "DisconnectNetworkDrive": var drivePath = (string)message["drive"]; _ = NetworkDrivesAPI.DisconnectNetworkDrive(drivePath); break; } }
private async void OnLibraryChanged(WatcherChangeTypes changeType, string oldPath, string newPath) { if (newPath != null && (!newPath.ToLowerInvariant().EndsWith(ShellLibraryItem.EXTENSION, StringComparison.Ordinal) || !File.Exists(newPath))) { System.Diagnostics.Debug.WriteLine($"Ignored library event: {changeType}, {oldPath} -> {newPath}"); return; } System.Diagnostics.Debug.WriteLine($"Library event: {changeType}, {oldPath} -> {newPath}"); if (connection?.IsConnected ?? false) { var response = new ValueSet { { "Library", newPath ?? oldPath } }; switch (changeType) { case WatcherChangeTypes.Deleted: case WatcherChangeTypes.Renamed: response["OldPath"] = oldPath; break; default: break; } if (!changeType.HasFlag(WatcherChangeTypes.Deleted)) { var library = SafetyExtensions.IgnoreExceptions(() => new ShellLibrary2(Shell32.ShellUtil.GetShellItemForPath(newPath), true)); if (library == null) { Program.Logger.Warn($"Failed to open library after {changeType}: {newPath}"); return; } response["Item"] = JsonConvert.SerializeObject(ShellFolderExtensions.GetShellLibraryItem(library, newPath)); library.Dispose(); } // Send message to UWP app to refresh items await Win32API.SendMessageAsync(connection, response); } }
public async Task ParseArgumentsAsync(PipeStream connection, Dictionary <string, object> message, string arguments) { switch (arguments) { case "Bitlocker": var bitlockerAction = (string)message["action"]; if (bitlockerAction == "Unlock") { var drive = (string)message["drive"]; var password = (string)message["password"]; Win32API.UnlockBitlockerDrive(drive, password); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Bitlocker", "Unlock" } }, message.Get("RequestID", (string)null)); } break; case "SetVolumeLabel": var driveName = (string)message["drivename"]; var newLabel = (string)message["newlabel"]; Win32API.SetVolumeLabel(driveName, newLabel); await Win32API.SendMessageAsync(connection, new ValueSet() { { "SetVolumeLabel", driveName } }, message.Get("RequestID", (string)null)); break; case "GetIconOverlay": var fileIconPath = (string)message["filePath"]; var thumbnailSize = (int)(long)message["thumbnailSize"]; var isOverlayOnly = (bool)message["isOverlayOnly"]; var iconOverlay = await Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath, thumbnailSize, true, isOverlayOnly)); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Icon", iconOverlay.icon }, { "Overlay", iconOverlay.overlay } }, message.Get("RequestID", (string)null)); break; case "GetIconWithoutOverlay": var fileIconPath2 = (string)message["filePath"]; var thumbnailSize2 = (int)(long)message["thumbnailSize"]; var icon2 = await Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath2, thumbnailSize2, false)); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Icon", icon2.icon }, }, message.Get("RequestID", (string)null)); break; case "ShellFolder": // Enumerate shell folder contents and send response to UWP var folderPath = (string)message["folder"]; var responseEnum = new ValueSet(); var folderContentsList = await Win32API.StartSTATask(() => { var flc = new List <ShellFileItem>(); try { using (var shellFolder = new ShellFolder(folderPath)) { foreach (var folderItem in shellFolder) { try { var shellFileItem = ShellFolderExtensions.GetShellFileItem(folderItem); flc.Add(shellFileItem); } catch (FileNotFoundException) { // Happens if files are being deleted } finally { folderItem.Dispose(); } } } } catch { } return(flc); }); responseEnum.Add("Enumerate", JsonConvert.SerializeObject(folderContentsList)); await Win32API.SendMessageAsync(connection, responseEnum, message.Get("RequestID", (string)null)); break; case "GetFolderIconsFromDLL": var iconInfos = Win32API.ExtractIconsFromDLL((string)message["iconFile"]); await Win32API.SendMessageAsync(connection, new ValueSet() { { "IconInfos", JsonConvert.SerializeObject(iconInfos) }, }, message.Get("RequestID", (string)null)); break; case "SetCustomFolderIcon": await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", Win32API.SetCustomDirectoryIcon((string)message["folder"], (string)message["iconFile"], (int)message.Get("iconIndex", 0L)) }, }, message.Get("RequestID", (string)null)); break; case "GetSelectedIconsFromDLL": var selectedIconInfos = Win32API.ExtractSelectedIconsFromDLL((string)message["iconFile"], JsonConvert.DeserializeObject <List <int> >((string)message["iconIndexes"]), Convert.ToInt32(message["requestedIconSize"])); await Win32API.SendMessageAsync(connection, new ValueSet() { { "IconInfos", JsonConvert.SerializeObject(selectedIconInfos) }, }, message.Get("RequestID", (string)null)); break; case "SetAsDefaultExplorer": { var enable = (bool)message["Value"]; var destFolder = Path.Combine(ApplicationData.Current.LocalFolder.Path, "FilesOpenDialog"); Directory.CreateDirectory(destFolder); foreach (var file in Directory.GetFiles(Path.Combine(Package.Current.InstalledLocation.Path, "Files.Launcher", "Assets", "FilesOpenDialog"))) { if (!Extensions.IgnoreExceptions(() => File.Copy(file, Path.Combine(destFolder, Path.GetFileName(file)), true), Program.Logger)) { // Error copying files DetectIsSetAsDefaultFileManager(); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); return; } } try { using var regProcess = Process.Start(new ProcessStartInfo("regedit.exe", @$ "/s " "{Path.Combine(destFolder, enable ? " SetFilesAsDefault.reg " : " UnsetFilesAsDefault.reg ")}" "") { UseShellExecute = true, Verb = "runas" }); regProcess.WaitForExit(); DetectIsSetAsDefaultFileManager(); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", true } }, message.Get("RequestID", (string)null)); } catch { // Canceled UAC DetectIsSetAsDefaultFileManager(); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); } }
private async Task HandleShellLibraryMessage(Dictionary <string, object> message) { switch ((string)message["action"]) { case "Enumerate": // Read library information and send response to UWP var enumerateResponse = await Win32API.StartSTATask(() => { var response = new ValueSet(); try { var libraryItems = new List <ShellLibraryItem>(); // https://docs.microsoft.com/en-us/windows/win32/search/-search-win7-development-scenarios#library-descriptions var libFiles = Directory.EnumerateFiles(ShellLibraryItem.LibrariesPath, "*" + ShellLibraryItem.EXTENSION); foreach (var libFile in libFiles) { using var shellItem = new ShellLibrary2(Shell32.ShellUtil.GetShellItemForPath(libFile), true); if (shellItem is ShellLibrary2 library) { libraryItems.Add(ShellFolderExtensions.GetShellLibraryItem(library, libFile)); } } response.Add("Enumerate", JsonConvert.SerializeObject(libraryItems)); } catch (Exception e) { Program.Logger.Warn(e); } return(response); }); await Win32API.SendMessageAsync(connection, enumerateResponse, message.Get("RequestID", (string)null)); break; case "Create": // Try create new library with the specified name and send response to UWP var createResponse = await Win32API.StartSTATask(() => { var response = new ValueSet(); try { using var library = new ShellLibrary2((string)message["library"], Shell32.KNOWNFOLDERID.FOLDERID_Libraries, false); library.Folders.Add(ShellItem.Open(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments))); // Add default folder so it's not empty library.Commit(); library.Reload(); response.Add("Create", JsonConvert.SerializeObject(ShellFolderExtensions.GetShellLibraryItem(library, library.GetDisplayName(ShellItemDisplayString.DesktopAbsoluteParsing)))); } catch (Exception e) { Program.Logger.Warn(e); } return(response); }); await Win32API.SendMessageAsync(connection, createResponse, message.Get("RequestID", (string)null)); break; case "Update": // Update details of the specified library and send response to UWP var updateResponse = await Win32API.StartSTATask(() => { var response = new ValueSet(); try { var folders = message.ContainsKey("folders") ? JsonConvert.DeserializeObject <string[]>((string)message["folders"]) : null; var defaultSaveFolder = message.Get("defaultSaveFolder", (string)null); var isPinned = message.Get("isPinned", (bool?)null); bool updated = false; var libPath = (string)message["library"]; using var library = new ShellLibrary2(Shell32.ShellUtil.GetShellItemForPath(libPath), false); if (folders != null) { if (folders.Length > 0) { var foldersToRemove = library.Folders.Where(f => !folders.Any(folderPath => string.Equals(folderPath, f.FileSystemPath, StringComparison.OrdinalIgnoreCase))); foreach (var toRemove in foldersToRemove) { library.Folders.Remove(toRemove); updated = true; } var foldersToAdd = folders.Distinct(StringComparer.OrdinalIgnoreCase) .Where(folderPath => !library.Folders.Any(f => string.Equals(folderPath, f.FileSystemPath, StringComparison.OrdinalIgnoreCase))) .Select(ShellItem.Open); foreach (var toAdd in foldersToAdd) { library.Folders.Add(toAdd); updated = true; } foreach (var toAdd in foldersToAdd) { toAdd.Dispose(); } } } if (defaultSaveFolder != null) { library.DefaultSaveFolder = ShellItem.Open(defaultSaveFolder); updated = true; } if (isPinned != null) { library.PinnedToNavigationPane = isPinned == true; updated = true; } if (updated) { library.Commit(); library.Reload(); // Reload folders list response.Add("Update", JsonConvert.SerializeObject(ShellFolderExtensions.GetShellLibraryItem(library, libPath))); } } catch (Exception e) { Program.Logger.Warn(e); } return(response); }); await Win32API.SendMessageAsync(connection, updateResponse, message.Get("RequestID", (string)null)); break; } }
public async Task ParseArgumentsAsync(NamedPipeServerStream connection, Dictionary <string, object> message, string arguments) { switch (arguments) { case "Bitlocker": var bitlockerAction = (string)message["action"]; if (bitlockerAction == "Unlock") { var drive = (string)message["drive"]; var password = (string)message["password"]; Win32API.UnlockBitlockerDrive(drive, password); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Bitlocker", "Unlock" } }, message.Get("RequestID", (string)null)); } break; case "SetVolumeLabel": var driveName = (string)message["drivename"]; var newLabel = (string)message["newlabel"]; Win32API.SetVolumeLabel(driveName, newLabel); await Win32API.SendMessageAsync(connection, new ValueSet() { { "SetVolumeLabel", driveName } }, message.Get("RequestID", (string)null)); break; case "GetIconOverlay": var fileIconPath = (string)message["filePath"]; var thumbnailSize = (int)(long)message["thumbnailSize"]; var isOverlayOnly = (bool)message["isOverlayOnly"]; var iconOverlay = Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath, thumbnailSize, true, isOverlayOnly)).Result; await Win32API.SendMessageAsync(connection, new ValueSet() { { "Icon", iconOverlay.icon }, { "Overlay", iconOverlay.overlay } }, message.Get("RequestID", (string)null)); break; case "GetIconWithoutOverlay": var fileIconPath2 = (string)message["filePath"]; var thumbnailSize2 = (int)(long)message["thumbnailSize"]; var icon2 = Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath2, thumbnailSize2, false)).Result; await Win32API.SendMessageAsync(connection, new ValueSet() { { "Icon", icon2.icon }, }, message.Get("RequestID", (string)null)); break; case "ShellFolder": // Enumerate shell folder contents and send response to UWP var folderPath = (string)message["folder"]; var responseEnum = new ValueSet(); var folderContentsList = await Win32API.StartSTATask(() => { var flc = new List <ShellFileItem>(); try { using (var shellFolder = new ShellFolder(folderPath)) { foreach (var folderItem in shellFolder) { try { var shellFileItem = ShellFolderExtensions.GetShellFileItem(folderItem); flc.Add(shellFileItem); } catch (FileNotFoundException) { // Happens if files are being deleted } finally { folderItem.Dispose(); } } } } catch { } return(flc); }); responseEnum.Add("Enumerate", JsonConvert.SerializeObject(folderContentsList)); await Win32API.SendMessageAsync(connection, responseEnum, message.Get("RequestID", (string)null)); break; case "GetSelectedIconsFromDLL": var selectedIconInfos = Win32API.ExtractSelectedIconsFromDLL((string)message["iconFile"], JsonConvert.DeserializeObject <List <int> >((string)message["iconIndexes"]), Convert.ToInt32(message["requestedIconSize"])); await Win32API.SendMessageAsync(connection, new ValueSet() { { "IconInfos", JsonConvert.SerializeObject(selectedIconInfos) }, }, message.Get("RequestID", (string)null)); break; } }
public async Task ParseArgumentsAsync(PipeStream connection, Dictionary <string, object> message, string arguments) { switch (arguments) { case "Bitlocker": var bitlockerAction = (string)message["action"]; if (bitlockerAction == "Unlock") { var drive = (string)message["drive"]; var password = (string)message["password"]; Win32API.UnlockBitlockerDrive(drive, password); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Bitlocker", "Unlock" } }, message.Get("RequestID", (string)null)); } break; case "SetVolumeLabel": var driveName = (string)message["drivename"]; var newLabel = (string)message["newlabel"]; Win32API.SetVolumeLabel(driveName, newLabel); await Win32API.SendMessageAsync(connection, new ValueSet() { { "SetVolumeLabel", driveName } }, message.Get("RequestID", (string)null)); break; case "GetIconOverlay": var fileIconPath = (string)message["filePath"]; var thumbnailSize = (int)(long)message["thumbnailSize"]; var isOverlayOnly = (bool)message["isOverlayOnly"]; var(icon, overlay) = await Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath, thumbnailSize, true, isOverlayOnly)); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Icon", icon }, { "Overlay", overlay } }, message.Get("RequestID", (string)null)); break; case "GetIconWithoutOverlay": var fileIconPath2 = (string)message["filePath"]; var thumbnailSize2 = (int)(long)message["thumbnailSize"]; var icon2 = await Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath2, thumbnailSize2, false)); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Icon", icon2.icon }, }, message.Get("RequestID", (string)null)); break; case "ShellItem": var itemPath = (string)message["item"]; var siAction = (string)message["action"]; var siResponseEnum = new ValueSet(); var item = await Win32API.StartSTATask(() => { using var shellItem = ShellFolderExtensions.GetShellItemFromPathOrPidl(itemPath); return(ShellFolderExtensions.GetShellFileItem(shellItem)); }); siResponseEnum.Add("Item", JsonConvert.SerializeObject(item)); await Win32API.SendMessageAsync(connection, siResponseEnum, message.Get("RequestID", (string)null)); break; case "ShellFolder": var folderPath = (string)message["folder"]; if (folderPath.StartsWith("::{", StringComparison.Ordinal)) { folderPath = $"shell:{folderPath}"; } var sfAction = (string)message["action"]; var fromIndex = (int)message.Get("from", 0L); var maxItems = (int)message.Get("count", (long)int.MaxValue); var sfResponseEnum = new ValueSet(); var(folder, folderContentsList) = await Win32API.StartSTATask(() => { var flc = new List <ShellFileItem>(); var folder = (ShellFileItem)null; try { using var shellFolder = ShellFolderExtensions.GetShellItemFromPathOrPidl(folderPath) as ShellFolder; folder = ShellFolderExtensions.GetShellFileItem(shellFolder); if ((controlPanel.PIDL.IsParentOf(shellFolder.PIDL, false) || controlPanelCategoryView.PIDL.IsParentOf(shellFolder.PIDL, false)) && !shellFolder.Any()) { // Return null to force open unsupported items in explorer // Only if inside control panel and folder appears empty return(null, flc); } if (sfAction == "Enumerate") { foreach (var folderItem in shellFolder.Skip(fromIndex).Take(maxItems)) { try { var shellFileItem = folderItem is ShellLink link ? ShellFolderExtensions.GetShellLinkItem(link) : ShellFolderExtensions.GetShellFileItem(folderItem); flc.Add(shellFileItem); } catch (FileNotFoundException) { // Happens if files are being deleted } finally { folderItem.Dispose(); } } } } catch { } return(folder, flc); }); sfResponseEnum.Add("Folder", JsonConvert.SerializeObject(folder)); sfResponseEnum.Add("Enumerate", JsonConvert.SerializeObject(folderContentsList, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects })); await Win32API.SendMessageAsync(connection, sfResponseEnum, message.Get("RequestID", (string)null)); break; case "GetFolderIconsFromDLL": var iconInfos = Win32API.ExtractIconsFromDLL((string)message["iconFile"]); await Win32API.SendMessageAsync(connection, new ValueSet() { { "IconInfos", JsonConvert.SerializeObject(iconInfos) }, }, message.Get("RequestID", (string)null)); break; case "SetCustomFolderIcon": await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", Win32API.SetCustomDirectoryIcon((string)message["folder"], (string)message["iconFile"], (int)message.Get("iconIndex", 0L)) }, }, message.Get("RequestID", (string)null)); break; case "GetSelectedIconsFromDLL": var selectedIconInfos = Win32API.ExtractSelectedIconsFromDLL((string)message["iconFile"], JsonConvert.DeserializeObject <List <int> >((string)message["iconIndexes"]), Convert.ToInt32(message["requestedIconSize"])); await Win32API.SendMessageAsync(connection, new ValueSet() { { "IconInfos", JsonConvert.SerializeObject(selectedIconInfos) }, }, message.Get("RequestID", (string)null)); break; case "SetAsDefaultExplorer": { var enable = (bool)message["Value"]; var destFolder = Path.Combine(ApplicationData.Current.LocalFolder.Path, "FilesOpenDialog"); Directory.CreateDirectory(destFolder); foreach (var file in Directory.GetFiles(Path.Combine(Package.Current.InstalledLocation.Path, "Files.FullTrust", "Assets", "FilesOpenDialog"))) { if (!SafetyExtensions.IgnoreExceptions(() => File.Copy(file, Path.Combine(destFolder, Path.GetFileName(file)), true), Program.Logger)) { // Error copying files DetectIsSetAsDefaultFileManager(); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); return; } } var dataPath = Environment.ExpandEnvironmentVariables("%LocalAppData%\\Files"); if (enable) { if (!Win32API.RunPowershellCommand($"-command \"New-Item -Force -Path '{dataPath}' -ItemType Directory; Copy-Item -Filter *.* -Path '{destFolder}\\*' -Recurse -Force -Destination '{dataPath}'\"", false)) { // Error copying files DetectIsSetAsDefaultFileManager(); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); return; } } else { Win32API.RunPowershellCommand($"-command \"Remove-Item -Path '{dataPath}' -Recurse -Force\"", false); } try { using var regProcess = Process.Start(new ProcessStartInfo("regedit.exe", @$ "/s " "{Path.Combine(destFolder, enable ? " SetFilesAsDefault.reg " : " UnsetFilesAsDefault.reg ")}" "") { UseShellExecute = true, Verb = "runas" }); regProcess.WaitForExit(); DetectIsSetAsDefaultFileManager(); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", true } }, message.Get("RequestID", (string)null)); } catch { // Canceled UAC DetectIsSetAsDefaultFileManager(); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); } }
private async Task HandleShellRecentItemsMessage(Dictionary <string, object> message) { var action = (string)message["action"]; var response = new ValueSet(); switch (action) { // enumerate `\Windows\Recent` for recent folders // note: files are enumerated using (Win32MessageHandler: "ShellFolder") in RecentItemsManager case "EnumerateFolders": var enumerateFoldersResponse = await Win32API.StartSTATask(() => { try { var shellLinkItems = new List <ShellLinkItem>(); var excludeMask = FileAttributes.Hidden; var linkFilePaths = Directory.EnumerateFiles(RecentItemsPath).Where(f => (new FileInfo(f).Attributes & excludeMask) == 0); foreach (var linkFilePath in linkFilePaths) { using var link = new ShellLink(linkFilePath, LinkResolution.NoUIWithMsgPump, null, TimeSpan.FromMilliseconds(100)); try { if (!string.IsNullOrEmpty(link.TargetPath) && link.Target.IsFolder) { var shellLinkItem = ShellFolderExtensions.GetShellLinkItem(link); shellLinkItems.Add(shellLinkItem); } } catch (FileNotFoundException) { // occurs when shortcut or shortcut target is deleted and accessed (link.Target) // consequently, we shouldn't include the item as a recent item } } response.Add("EnumerateFolders", JsonConvert.SerializeObject(shellLinkItems)); } catch (Exception e) { Program.Logger.Warn(e); } return(response); }); await Win32API.SendMessageAsync(connection, enumerateFoldersResponse, message.Get("RequestID", (string)null)); break; case "Add": var addResponse = await Win32API.StartSTATask(() => { try { var path = (string)message["Path"]; Shell32.SHAddToRecentDocs(Shell32.SHARD.SHARD_PATHW, path); } catch (Exception e) { Program.Logger.Warn(e); } return(response); }); await Win32API.SendMessageAsync(connection, addResponse, message.Get("RequestID", (string)null)); break; case "Clear": var clearResponse = await Win32API.StartSTATask(() => { try { Shell32.SHAddToRecentDocs(Shell32.SHARD.SHARD_PIDL, (string)null); } catch (Exception e) { Program.Logger.Warn(e); } return(response); }); await Win32API.SendMessageAsync(connection, clearResponse, message.Get("RequestID", (string)null)); break; // invoke 'remove' verb on the file to remove it from Quick Access // note: for folders, we need to use the verb 'unpinfromhome' or 'removefromhome' case "UnpinFile": var unpinFileResponse = await Win32API.StartSTATask(() => { try { var path = (string)message["Path"]; var command = $"-command \"((New-Object -ComObject Shell.Application).Namespace('shell:{QuickAccessGuid}\').Items() " + $"| Where-Object {{ $_.Path -eq '{path}' }}).InvokeVerb('remove')\""; bool success = Win32API.RunPowershellCommand(command, false); response.Add("UnpinFile", path); response.Add("Success", success); } catch (Exception e) { Program.Logger.Warn(e); } return(response); }); await Win32API.SendMessageAsync(connection, unpinFileResponse, message.Get("RequestID", (string)null)); break; } }
private async Task <bool> HandleApplicationLaunch(string application, Dictionary <string, object> message) { var arguments = message.Get("Parameters", ""); var workingDirectory = message.Get("WorkingDirectory", ""); var currentWindows = Win32API.GetDesktopWindows(); if (new[] { ".vhd", ".vhdx" }.Contains(Path.GetExtension(application).ToLowerInvariant())) { // Use powershell to mount vhds as this requires admin rights return(Win32API.MountVhdDisk(application)); } try { using Process process = new Process(); process.StartInfo.UseShellExecute = false; process.StartInfo.FileName = application; // Show window if workingDirectory (opening terminal) process.StartInfo.CreateNoWindow = string.IsNullOrEmpty(workingDirectory); if (arguments == "runas") { process.StartInfo.UseShellExecute = true; process.StartInfo.Verb = "runas"; if (string.Equals(Path.GetExtension(application), ".msi", StringComparison.OrdinalIgnoreCase)) { process.StartInfo.FileName = "msiexec.exe"; process.StartInfo.Arguments = $"/a \"{application}\""; } } else if (arguments == "runasuser") { process.StartInfo.UseShellExecute = true; process.StartInfo.Verb = "runasuser"; if (string.Equals(Path.GetExtension(application), ".msi", StringComparison.OrdinalIgnoreCase)) { process.StartInfo.FileName = "msiexec.exe"; process.StartInfo.Arguments = $"/i \"{application}\""; } } else { process.StartInfo.Arguments = arguments; // Refresh env variables for the child process foreach (DictionaryEntry ent in Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine)) { process.StartInfo.EnvironmentVariables[(string)ent.Key] = (string)ent.Value; } foreach (DictionaryEntry ent in Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)) { process.StartInfo.EnvironmentVariables[(string)ent.Key] = (string)ent.Value; } process.StartInfo.EnvironmentVariables["PATH"] = string.Join(";", Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine), Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User)); } process.StartInfo.WorkingDirectory = workingDirectory; process.Start(); Win32API.BringToForeground(currentWindows); return(true); } catch (Win32Exception) { using Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.FileName = application; process.StartInfo.CreateNoWindow = true; process.StartInfo.Arguments = arguments; process.StartInfo.WorkingDirectory = workingDirectory; try { process.Start(); Win32API.BringToForeground(currentWindows); return(true); } catch (Win32Exception) { try { var opened = await Win32API.StartSTATask(() => { var split = application.Split('|').Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => GetMtpPath(x)); if (split.Count() == 1) { Process.Start(split.First()); Win32API.BringToForeground(currentWindows); } else { var groups = split.GroupBy(x => new { Dir = Path.GetDirectoryName(x), Prog = Win32API.GetFileAssociationAsync(x).Result ?? Path.GetExtension(x) }); foreach (var group in groups) { if (!group.Any()) { continue; } using var cMenu = ContextMenu.GetContextMenuForFiles(group.ToArray(), Shell32.CMF.CMF_DEFAULTONLY); cMenu?.InvokeVerb(Shell32.CMDSTR_OPEN); } } return(true); }); if (!opened) { if (application.StartsWith(@"\\SHELL\", StringComparison.Ordinal)) { opened = await Win32API.StartSTATask(() => { using var si = ShellFolderExtensions.GetShellItemFromPathOrPidl(application); using var cMenu = ContextMenu.GetContextMenuForFiles(new[] { si }, Shell32.CMF.CMF_DEFAULTONLY); cMenu?.InvokeItem(cMenu?.Items.FirstOrDefault().ID ?? -1); return(true); }); } } if (!opened) { var isAlternateStream = Regex.IsMatch(application, @"\w:\w"); if (isAlternateStream) { var basePath = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), Guid.NewGuid().ToString("n")); Kernel32.CreateDirectory(basePath); var tempPath = Path.Combine(basePath, new string(Path.GetFileName(application).SkipWhile(x => x != ':').Skip(1).ToArray())); using var hFileSrc = Kernel32.CreateFile(application, Kernel32.FileAccess.GENERIC_READ, FileShare.ReadWrite, null, FileMode.Open, FileFlagsAndAttributes.FILE_ATTRIBUTE_NORMAL); using var hFileDst = Kernel32.CreateFile(tempPath, Kernel32.FileAccess.GENERIC_WRITE, 0, null, FileMode.Create, FileFlagsAndAttributes.FILE_ATTRIBUTE_NORMAL | FileFlagsAndAttributes.FILE_ATTRIBUTE_READONLY); if (!hFileSrc.IsInvalid && !hFileDst.IsInvalid) { // Copy ADS to temp folder and open using (var inStream = new FileStream(hFileSrc.DangerousGetHandle(), FileAccess.Read)) using (var outStream = new FileStream(hFileDst.DangerousGetHandle(), FileAccess.Write)) { await inStream.CopyToAsync(outStream); await outStream.FlushAsync(); } opened = await HandleApplicationLaunch(tempPath, message); } } } return(opened); } catch (Win32Exception) { // Cannot open file (e.g DLL) return(false); } catch (ArgumentException) { // Cannot open file (e.g DLL) return(false); } } } catch (InvalidOperationException) { // Invalid file path return(false); } catch (Exception ex) { // Generic error, log Program.Logger.Warn(ex, $"Error launching: {application}"); return(false); } }