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(); } } }
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 <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); } }