private static async void HandleApplicationLaunch(string application, AppServiceRequestReceivedEventArgs args) { var arguments = args.Request.Message.Get("Arguments", ""); var workingDirectory = args.Request.Message.Get("WorkingDirectory", ""); try { 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 (Path.GetExtension(application).ToLower() == ".msi") { process.StartInfo.FileName = "msiexec.exe"; process.StartInfo.Arguments = $"/a \"{application}\""; } } else if (arguments == "runasuser") { process.StartInfo.UseShellExecute = true; process.StartInfo.Verb = "runasuser"; if (Path.GetExtension(application).ToLower() == ".msi") { process.StartInfo.FileName = "msiexec.exe"; process.StartInfo.Arguments = $"/i \"{application}\""; } } else { process.StartInfo.Arguments = arguments; } process.StartInfo.WorkingDirectory = workingDirectory; process.Start(); } catch (Win32Exception) { Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.Verb = "runas"; process.StartInfo.FileName = application; process.StartInfo.CreateNoWindow = true; process.StartInfo.Arguments = arguments; process.StartInfo.WorkingDirectory = workingDirectory; try { process.Start(); } catch (Win32Exception) { try { await Win32API.StartSTATask(() => { var split = application.Split('|').Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => GetMtpPath(x)); if (split.Count() == 1) { Process.Start(split.First()); } 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 = Win32API.ContextMenu.GetContextMenuForFiles(group.ToArray(), Shell32.CMF.CMF_DEFAULTONLY); cMenu?.InvokeVerb(Shell32.CMDSTR_OPEN); } } return true; }); } catch (Win32Exception) { // Cannot open file (e.g DLL) } catch (ArgumentException) { // Cannot open file (e.g DLL) } } } catch (InvalidOperationException) { // Invalid file path } }
private static async Task ParseArgumentsAsync(AppServiceRequestReceivedEventArgs args, AppServiceDeferral messageDeferral, string arguments, ApplicationDataContainer localSettings) { switch (arguments) { case "Terminate": // Exit fulltrust process (UWP is closed or suspended) appServiceExit.Set(); messageDeferral.Complete(); break; case "RecycleBin": var binAction = (string)args.Request.Message["action"]; await ParseRecycleBinActionAsync(args, binAction); break; case "StartupTasks": // Check QuickLook Availability QuickLook.CheckQuickLookAvailability(localSettings); break; case "ToggleQuickLook": var path = (string)args.Request.Message["path"]; QuickLook.ToggleQuickLook(path); break; case "ShellCommand": // Kill the process. This is a BRUTAL WAY to kill a process. #if DEBUG // In debug mode this kills this process too?? #else var pid = (int)args.Request.Message["pid"]; Process.GetProcessById(pid).Kill(); #endif Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.FileName = "explorer.exe"; process.StartInfo.CreateNoWindow = false; process.StartInfo.Arguments = (string)args.Request.Message["ShellCommand"]; process.Start(); break; case "LoadContextMenu": var contextMenuResponse = new ValueSet(); var loadThreadWithMessageQueue = new Win32API.ThreadWithMessageQueue <ValueSet>(HandleMenuMessage); var cMenuLoad = await loadThreadWithMessageQueue.PostMessageAsync <Win32API.ContextMenu>(args.Request.Message); contextMenuResponse.Add("Handle", handleTable.AddValue(loadThreadWithMessageQueue)); contextMenuResponse.Add("ContextMenu", JsonConvert.SerializeObject(cMenuLoad)); await args.Request.SendResponseAsync(contextMenuResponse); break; case "ExecAndCloseContextMenu": var menuKey = (string)args.Request.Message["Handle"]; var execThreadWithMessageQueue = handleTable.GetValue <Win32API.ThreadWithMessageQueue <ValueSet> >(menuKey); if (execThreadWithMessageQueue != null) { await execThreadWithMessageQueue.PostMessage(args.Request.Message); } // The following line is needed to cleanup resources when menu is closed. // Unfortunately if you uncomment it some menu items will randomly stop working. // Resource cleanup is currently done on app closing, // if we find a solution for the issue above, we should cleanup as soon as a menu is closed. //handleTable.RemoveValue(menuKey); break; case "InvokeVerb": var filePath = (string)args.Request.Message["FilePath"]; var split = filePath.Split('|').Where(x => !string.IsNullOrWhiteSpace(x)); using (var cMenu = Win32API.ContextMenu.GetContextMenuForFiles(split.ToArray(), Shell32.CMF.CMF_DEFAULTONLY)) { cMenu?.InvokeVerb((string)args.Request.Message["Verb"]); } break; case "Bitlocker": var bitlockerAction = (string)args.Request.Message["action"]; if (bitlockerAction == "Unlock") { var drive = (string)args.Request.Message["drive"]; var password = (string)args.Request.Message["password"]; Win32API.UnlockBitlockerDrive(drive, password); await args.Request.SendResponseAsync(new ValueSet() { { "Bitlocker", "Unlock" } }); } break; case "SetVolumeLabel": var driveName = (string)args.Request.Message["drivename"]; var newLabel = (string)args.Request.Message["newlabel"]; Win32API.SetVolumeLabel(driveName, newLabel); break; case "FileOperation": await ParseFileOperationAsync(args); break; case "GetIconOverlay": var fileIconPath = (string)args.Request.Message["filePath"]; var thumbnailSize = (int)args.Request.Message["thumbnailSize"]; var iconOverlay = Win32API.GetFileIconAndOverlay(fileIconPath, thumbnailSize); await args.Request.SendResponseAsync(new ValueSet() { { "Icon", iconOverlay.icon }, { "Overlay", iconOverlay.overlay }, { "HasCustomIcon", iconOverlay.isCustom } }); break; case "GetOneDriveAccounts": using (var oneDriveAccountsKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\OneDrive\Accounts", false)) { if (oneDriveAccountsKey == null) { await args.Request.SendResponseAsync(new ValueSet()); return; } var oneDriveAccounts = new ValueSet(); foreach (var account in oneDriveAccountsKey.GetSubKeyNames()) { var accountKeyName = @$ "{oneDriveAccountsKey.Name}\{account}"; var displayName = (string)Registry.GetValue(accountKeyName, "DisplayName", null); var userFolder = (string)Registry.GetValue(accountKeyName, "UserFolder", null); var accountName = string.IsNullOrWhiteSpace(displayName) ? "OneDrive" : $"OneDrive - {displayName}"; if (!string.IsNullOrWhiteSpace(userFolder) && !oneDriveAccounts.ContainsKey(accountName)) { oneDriveAccounts.Add(accountName, userFolder); } } await args.Request.SendResponseAsync(oneDriveAccounts); } break;
private static async Task parseArguments(AppServiceRequestReceivedEventArgs args, AppServiceDeferral messageDeferral, string arguments, ApplicationDataContainer localSettings) { switch (arguments) { case "Terminate": // Exit fulltrust process (UWP is closed or suspended) appServiceExit.Set(); messageDeferral.Complete(); break; case "RecycleBin": var binAction = (string)args.Request.Message["action"]; await parseRecycleBinAction(args, binAction); break; case "StartupTasks": // Check QuickLook Availability QuickLook.CheckQuickLookAvailability(localSettings); break; case "ToggleQuickLook": var path = (string)args.Request.Message["path"]; QuickLook.ToggleQuickLook(path); break; case "ShellCommand": // Kill the process. This is a BRUTAL WAY to kill a process. #if DEBUG // In debug mode this kills this process too?? #else var pid = (int)args.Request.Message["pid"]; Process.GetProcessById(pid).Kill(); #endif Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.FileName = "explorer.exe"; process.StartInfo.CreateNoWindow = false; process.StartInfo.Arguments = (string)args.Request.Message["ShellCommand"]; process.Start(); break; case "LoadContextMenu": var contextMenuResponse = new ValueSet(); var loadThreadWithMessageQueue = new Win32API.ThreadWithMessageQueue <ValueSet>(HandleMenuMessage); var cMenuLoad = await loadThreadWithMessageQueue.PostMessage <Win32API.ContextMenu>(args.Request.Message); contextMenuResponse.Add("Handle", handleTable.AddValue(loadThreadWithMessageQueue)); contextMenuResponse.Add("ContextMenu", JsonConvert.SerializeObject(cMenuLoad)); await args.Request.SendResponseAsync(contextMenuResponse); break; case "ExecAndCloseContextMenu": var menuKey = (string)args.Request.Message["Handle"]; var execThreadWithMessageQueue = handleTable.GetValue <Win32API.ThreadWithMessageQueue <ValueSet> >(menuKey); if (execThreadWithMessageQueue != null) { await execThreadWithMessageQueue.PostMessage(args.Request.Message); } // The following line is needed to cleanup resources when menu is closed. // Unfortunately if you uncomment it some menu items will randomly stop working. // Resource cleanup is currently done on app closing, // if we find a solution for the issue above, we should cleanup as soon as a menu is closed. //handleTable.RemoveValue(menuKey); break; case "InvokeVerb": var filePath = (string)args.Request.Message["FilePath"]; var split = filePath.Split('|').Where(x => !string.IsNullOrWhiteSpace(x)); using (var cMenu = Win32API.ContextMenu.GetContextMenuForFiles(split.ToArray(), Shell32.CMF.CMF_DEFAULTONLY)) { cMenu?.InvokeVerb((string)args.Request.Message["Verb"]); } break; case "Bitlocker": var bitlockerAction = (string)args.Request.Message["action"]; if (bitlockerAction == "Unlock") { var drive = (string)args.Request.Message["drive"]; var password = (string)args.Request.Message["password"]; Win32API.UnlockBitlockerDrive(drive, password); await args.Request.SendResponseAsync(new ValueSet() { { "Bitlocker", "Unlock" } }); } break; case "FileOperation": await parseFileOperation(args); break; default: if (args.Request.Message.ContainsKey("Application")) { var application = (string)args.Request.Message["Application"]; HandleApplicationLaunch(application, args); } else if (args.Request.Message.ContainsKey("ApplicationList")) { var applicationList = JsonConvert.DeserializeObject <IEnumerable <string> >((string)args.Request.Message["ApplicationList"]); HandleApplicationsLaunch(applicationList, args); } break; } }
private static async Task ParseFileOperationAsync(AppServiceRequestReceivedEventArgs args) { var fileOp = (string)args.Request.Message["fileop"]; switch (fileOp) { case "Clipboard": await Win32API.StartSTATask(() => { System.Windows.Forms.Clipboard.Clear(); var fileToCopy = (string)args.Request.Message["filepath"]; var operation = (DataPackageOperation)(int)args.Request.Message["operation"]; var fileList = new System.Collections.Specialized.StringCollection(); fileList.AddRange(fileToCopy.Split('|')); if (operation == DataPackageOperation.Copy) { System.Windows.Forms.Clipboard.SetFileDropList(fileList); } else if (operation == DataPackageOperation.Move) { byte[] moveEffect = new byte[] { 2, 0, 0, 0 }; MemoryStream dropEffect = new MemoryStream(); dropEffect.Write(moveEffect, 0, moveEffect.Length); var data = new System.Windows.Forms.DataObject(); data.SetFileDropList(fileList); data.SetData("Preferred DropEffect", dropEffect); System.Windows.Forms.Clipboard.SetDataObject(data, true); } return true; }); break; case "MoveToBin": var fileToDeletePath = (string)args.Request.Message["filepath"]; using (var op = new ShellFileOperations()) { op.Options = ShellFileOperations.OperationFlags.AllowUndo | ShellFileOperations.OperationFlags.NoUI; using var shi = new ShellItem(fileToDeletePath); op.QueueDeleteOperation(shi); op.PerformOperations(); } //ShellFileOperations.Delete(fileToDeletePath, ShellFileOperations.OperationFlags.AllowUndo | ShellFileOperations.OperationFlags.NoUI); break; case "ParseLink": var linkPath = (string)args.Request.Message["filepath"]; try { if (linkPath.EndsWith(".lnk")) { using var link = new ShellLink(linkPath, LinkResolution.NoUIWithMsgPump, null, TimeSpan.FromMilliseconds(100)); await args.Request.SendResponseAsync(new ValueSet() { { "TargetPath", link.TargetPath }, { "Arguments", link.Arguments }, { "WorkingDirectory", link.WorkingDirectory }, { "RunAsAdmin", link.RunAsAdministrator }, { "IsFolder", !string.IsNullOrEmpty(link.TargetPath) && link.Target.IsFolder } }); } else if (linkPath.EndsWith(".url")) { var linkUrl = await Win32API.StartSTATask(() => { var ipf = new Url.IUniformResourceLocator(); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Load(linkPath, 0); ipf.GetUrl(out var retVal); return retVal; }); await args.Request.SendResponseAsync(new ValueSet() { { "TargetPath", linkUrl }, { "Arguments", null }, { "WorkingDirectory", null }, { "RunAsAdmin", false }, { "IsFolder", false } }); } } catch (Exception ex) { // Could not parse shortcut Logger.Warn(ex, ex.Message); await args.Request.SendResponseAsync(new ValueSet() { { "TargetPath", null }, { "Arguments", null }, { "WorkingDirectory", null }, { "RunAsAdmin", false }, { "IsFolder", false } }); } break; case "CreateLink": case "UpdateLink": var linkSavePath = (string)args.Request.Message["filepath"]; var targetPath = (string)args.Request.Message["targetpath"]; if (linkSavePath.EndsWith(".lnk")) { var arguments = (string)args.Request.Message["arguments"]; var workingDirectory = (string)args.Request.Message["workingdir"]; var runAsAdmin = (bool)args.Request.Message["runasadmin"]; using var newLink = new ShellLink(targetPath, arguments, workingDirectory); newLink.RunAsAdministrator = runAsAdmin; newLink.SaveAs(linkSavePath); // Overwrite if exists } else if (linkSavePath.EndsWith(".url")) { await Win32API.StartSTATask(() => { var ipf = new Url.IUniformResourceLocator(); ipf.SetUrl(targetPath, Url.IURL_SETURL_FLAGS.IURL_SETURL_FL_GUESS_PROTOCOL); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Save(linkSavePath, false); // Overwrite if exists return true; }); } break; } }
private static void HandleApplicationLaunch(string application, AppServiceRequestReceivedEventArgs args) { var arguments = args.Request.Message.Get("Arguments", ""); var workingDirectory = args.Request.Message.Get("WorkingDirectory", ""); try { Process process = new Process(); process.StartInfo.UseShellExecute = false; process.StartInfo.FileName = application; // Show window if workingDirectory (opening terminal) process.StartInfo.CreateNoWindow = string.IsNullOrEmpty(workingDirectory); process.StartInfo.Arguments = arguments; process.StartInfo.WorkingDirectory = workingDirectory; process.Start(); } catch (Win32Exception) { Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.Verb = "runas"; process.StartInfo.FileName = application; process.StartInfo.CreateNoWindow = true; process.StartInfo.Arguments = arguments; process.StartInfo.WorkingDirectory = workingDirectory; try { process.Start(); } catch (Win32Exception) { try { var split = application.Split(';').Where(x => !string.IsNullOrWhiteSpace(x)); if (split.Count() == 1) { Process.Start(application); } else { var groups = split.GroupBy(x => new { Dir = Path.GetDirectoryName(x), Prog = Win32API.GetFileAssociation(x).Result ?? Path.GetExtension(x) }); foreach (var group in groups) { if (!group.Any()) { continue; } var files = group.Select(x => new ShellItem(x)); using var sf = files.First().Parent; Vanara.PInvoke.Shell32.IContextMenu menu = null; try { menu = sf.GetChildrenUIObjects <Vanara.PInvoke.Shell32.IContextMenu>(null, files.ToArray()); menu.QueryContextMenu(Vanara.PInvoke.HMENU.NULL, 0, 0, 0, Vanara.PInvoke.Shell32.CMF.CMF_DEFAULTONLY); var pici = new Vanara.PInvoke.Shell32.CMINVOKECOMMANDINFOEX(); pici.lpVerb = Vanara.PInvoke.Shell32.CMDSTR_OPEN; pici.nShow = Vanara.PInvoke.ShowWindowCommand.SW_SHOW; pici.cbSize = (uint)Marshal.SizeOf(pici); menu.InvokeCommand(pici); } finally { foreach (var elem in files) { elem.Dispose(); } if (menu != null) { Marshal.ReleaseComObject(menu); } } } } } catch (Win32Exception) { // Cannot open file (e.g DLL) } catch (ArgumentException) { // Cannot open file (e.g DLL) } } } }
private static async Task parseRecycleBinAction(AppServiceRequestReceivedEventArgs args, string action) { switch (action) { case "Empty": // Shell function to empty recyclebin Vanara.PInvoke.Shell32.SHEmptyRecycleBin(IntPtr.Zero, null, Vanara.PInvoke.Shell32.SHERB.SHERB_NOCONFIRMATION | Vanara.PInvoke.Shell32.SHERB.SHERB_NOPROGRESSUI); break; case "Query": var responseQuery = new ValueSet(); Win32API.SHQUERYRBINFO queryBinInfo = new Win32API.SHQUERYRBINFO(); queryBinInfo.cbSize = (uint)Marshal.SizeOf(typeof(Win32API.SHQUERYRBINFO)); var res = Win32API.SHQueryRecycleBin("", ref queryBinInfo); // TODO: use this when updated library is released //Vanara.PInvoke.Shell32.SHQUERYRBINFO queryBinInfo = new Vanara.PInvoke.Shell32.SHQUERYRBINFO(); //Vanara.PInvoke.Shell32.SHQueryRecycleBin(null, ref queryBinInfo); if (res == Vanara.PInvoke.HRESULT.S_OK) { var numItems = queryBinInfo.i64NumItems; var binSize = queryBinInfo.i64Size; responseQuery.Add("NumItems", numItems); responseQuery.Add("BinSize", binSize); await args.Request.SendResponseAsync(responseQuery); } break; case "Enumerate": // Enumerate recyclebin contents and send response to UWP var responseEnum = new ValueSet(); var folderContentsList = new List <ShellFileItem>(); foreach (var folderItem in recycler) { try { folderItem.Properties.ReadOnly = true; folderItem.Properties.NoInheritedProperties = false; string recyclePath = folderItem.FileSystemPath; // True path on disk string fileName = Path.GetFileName(folderItem.Name); // Original file name string filePath = folderItem.Name; // Original file path + name var dt = (System.Runtime.InteropServices.ComTypes.FILETIME)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.DateCreated]; var recycleDate = dt.ToDateTime().ToLocalTime(); // This is LocalTime string fileSize = folderItem.Properties.GetPropertyString(Vanara.PInvoke.Ole32.PROPERTYKEY.System.Size); long fileSizeBytes = (long)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.Size]; string fileType = (string)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.ItemTypeText]; bool isFolder = folderItem.IsFolder && Path.GetExtension(folderItem.Name) != ".zip"; folderContentsList.Add(new ShellFileItem(isFolder, recyclePath, fileName, filePath, recycleDate, fileSize, fileSizeBytes, fileType)); } catch (System.IO.FileNotFoundException) { // Happens if files are being deleted } finally { folderItem.Dispose(); } } responseEnum.Add("Enumerate", Newtonsoft.Json.JsonConvert.SerializeObject(folderContentsList)); await args.Request.SendResponseAsync(responseEnum); break; default: break; } }
private static async Task parseArguments(AppServiceRequestReceivedEventArgs args, AppServiceDeferral messageDeferral, string arguments, ApplicationDataContainer localSettings) { switch (arguments) { case "Terminate": // Exit fulltrust process (UWP is closed or suspended) appServiceExit.Set(); messageDeferral.Complete(); break; case "RecycleBin": var action = (string)args.Request.Message["action"]; await parseRecycleBinAction(args, action); break; case "StartupTasks": // Check QuickLook Availability QuickLook.CheckQuickLookAvailability(localSettings); break; case "ToggleQuickLook": var path = (string)args.Request.Message["path"]; QuickLook.ToggleQuickLook(path); break; case "ShellCommand": // Kill the process. This is a BRUTAL WAY to kill a process. #if DEBUG // In debug mode this kills this process too?? #else var pid = (int)args.Request.Message["pid"]; Process.GetProcessById(pid).Kill(); #endif Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.FileName = "explorer.exe"; process.StartInfo.CreateNoWindow = false; process.StartInfo.Arguments = (string)args.Request.Message["ShellCommand"]; process.Start(); break; case "LoadMUIVerb": var responseSet = new ValueSet(); responseSet.Add("MUIVerbString", Win32API.ExtractStringFromDLL((string)args.Request.Message["MUIVerbLocation"], (int)args.Request.Message["MUIVerbLine"])); await args.Request.SendResponseAsync(responseSet); break; case "ParseAguments": var responseArray = new ValueSet(); var resultArgument = Win32API.CommandLineToArgs((string)args.Request.Message["Command"]); responseArray.Add("ParsedArguments", Newtonsoft.Json.JsonConvert.SerializeObject(resultArgument)); await args.Request.SendResponseAsync(responseArray); break; default: if (args.Request.Message.ContainsKey("Application")) { var application = (string)args.Request.Message["Application"]; HandleApplicationLaunch(application, args); } else if (args.Request.Message.ContainsKey("ApplicationList")) { var applicationList = JsonConvert.DeserializeObject <IEnumerable <string> >((string)args.Request.Message["ApplicationList"]); HandleApplicationsLaunch(applicationList, args); } break; } }
private static void EnumMenuItems( Shell32.IContextMenu cMenu, HMENU hMenu, List <Win32ContextMenuItem> menuItemsResult, Func <string, bool> itemFilter = null) { var itemCount = User32.GetMenuItemCount(hMenu); var mii = new User32.MENUITEMINFO(); mii.cbSize = (uint)Marshal.SizeOf(mii); mii.fMask = User32.MenuItemInfoMask.MIIM_BITMAP | User32.MenuItemInfoMask.MIIM_FTYPE | User32.MenuItemInfoMask.MIIM_STRING | User32.MenuItemInfoMask.MIIM_ID | User32.MenuItemInfoMask.MIIM_SUBMENU; for (uint ii = 0; ii < itemCount; ii++) { var menuItem = new ContextMenuItem(); var container = new SafeCoTaskMemString(512); mii.dwTypeData = (IntPtr)container; mii.cch = (uint)container.Capacity - 1; // https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723 var retval = User32.GetMenuItemInfo(hMenu, ii, true, ref mii); if (!retval) { container.Dispose(); continue; } menuItem.Type = (MenuItemType)mii.fType; menuItem.ID = (int)(mii.wID - 1); // wID - idCmdFirst if (menuItem.Type == MenuItemType.MFT_STRING) { Debug.WriteLine("Item {0} ({1}): {2}", ii, mii.wID, mii.dwTypeData); menuItem.Label = mii.dwTypeData; menuItem.CommandString = GetCommandString(cMenu, mii.wID - 1); if (itemFilter != null && (itemFilter(menuItem.CommandString) || itemFilter(menuItem.Label))) { // Skip items implemented in UWP container.Dispose(); continue; } if (mii.hbmpItem != HBITMAP.NULL && !Enum.IsDefined(typeof(HBITMAP_HMENU), ((IntPtr)mii.hbmpItem).ToInt64())) { using var bitmap = Win32API.GetBitmapFromHBitmap(mii.hbmpItem); if (bitmap != null) { byte[] bitmapData = (byte[])new ImageConverter().ConvertTo(bitmap, typeof(byte[])); menuItem.IconBase64 = Convert.ToBase64String(bitmapData, 0, bitmapData.Length); } } if (mii.hSubMenu != HMENU.NULL) { Debug.WriteLine("Item {0}: has submenu", ii); var subItems = new List <Win32ContextMenuItem>(); try { (cMenu as Shell32.IContextMenu2)?.HandleMenuMsg((uint)User32.WindowMessage.WM_INITMENUPOPUP, (IntPtr)mii.hSubMenu, new IntPtr(ii)); } catch (NotImplementedException) { // Only for dynamic/owner drawn? (open with, etc) } EnumMenuItems(cMenu, mii.hSubMenu, subItems, itemFilter); menuItem.SubItems = subItems; Debug.WriteLine("Item {0}: done submenu", ii); } } else { Debug.WriteLine("Item {0}: {1}", ii, mii.fType.ToString()); } container.Dispose(); menuItemsResult.Add(menuItem); } }
private static async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { // Get a deferral because we use an awaitable API below to respond to the message // and we don't want this call to get cancelled while we are waiting. var messageDeferral = args.GetDeferral(); if (args.Request.Message == null) { messageDeferral.Complete(); return; } try { if (args.Request.Message.ContainsKey("Arguments")) { // This replaces launching the fulltrust process with arguments // Instead a single instance of the process is running // Requests from UWP app are sent via AppService connection var arguments = (string)args.Request.Message["Arguments"]; var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; Logger.Info($"Argument: {arguments}"); if (arguments == "Terminate") { // Exit fulltrust process (UWP is closed or suspended) appServiceExit.Set(); messageDeferral.Complete(); } else if (arguments == "RecycleBin") { var action = (string)args.Request.Message["action"]; if (action == "Empty") { // Shell function to empty recyclebin Vanara.PInvoke.Shell32.SHEmptyRecycleBin(IntPtr.Zero, null, Vanara.PInvoke.Shell32.SHERB.SHERB_NOCONFIRMATION | Vanara.PInvoke.Shell32.SHERB.SHERB_NOPROGRESSUI); } else if (action == "Query") { var responseQuery = new ValueSet(); Win32API.SHQUERYRBINFO queryBinInfo = new Win32API.SHQUERYRBINFO(); queryBinInfo.cbSize = (uint)Marshal.SizeOf(typeof(Win32API.SHQUERYRBINFO)); var res = Win32API.SHQueryRecycleBin("", ref queryBinInfo); // TODO: use this when updated library is released //Vanara.PInvoke.Shell32.SHQUERYRBINFO queryBinInfo = new Vanara.PInvoke.Shell32.SHQUERYRBINFO(); //Vanara.PInvoke.Shell32.SHQueryRecycleBin(null, ref queryBinInfo); if (res == Vanara.PInvoke.HRESULT.S_OK) { var numItems = queryBinInfo.i64NumItems; var binSize = queryBinInfo.i64Size; responseQuery.Add("NumItems", numItems); responseQuery.Add("BinSize", binSize); await args.Request.SendResponseAsync(responseQuery); } } else if (action == "Enumerate") { // Enumerate recyclebin contents and send response to UWP var responseEnum = new ValueSet(); var folderContentsList = new List <ShellFileItem>(); foreach (var folderItem in recycler) { try { folderItem.Properties.ReadOnly = true; folderItem.Properties.NoInheritedProperties = false; string recyclePath = folderItem.FileSystemPath; // True path on disk string fileName = Path.GetFileName(folderItem.Name); // Original file name string filePath = folderItem.Name; // Original file path + name var dt = (System.Runtime.InteropServices.ComTypes.FILETIME)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.DateCreated]; var recycleDate = dt.ToDateTime().ToLocalTime(); // This is LocalTime string fileSize = folderItem.Properties.GetPropertyString(Vanara.PInvoke.Ole32.PROPERTYKEY.System.Size); ulong fileSizeBytes = (ulong)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.Size]; string fileType = (string)folderItem.Properties[Vanara.PInvoke.Ole32.PROPERTYKEY.System.ItemTypeText]; bool isFolder = folderItem.IsFolder && Path.GetExtension(folderItem.Name) != ".zip"; folderContentsList.Add(new ShellFileItem(isFolder, recyclePath, fileName, filePath, recycleDate, fileSize, fileSizeBytes, fileType)); } catch (System.IO.FileNotFoundException) { // Happens if files are being deleted } finally { folderItem.Dispose(); } } responseEnum.Add("Enumerate", Newtonsoft.Json.JsonConvert.SerializeObject(folderContentsList)); await args.Request.SendResponseAsync(responseEnum); } } else if (arguments == "StartupTasks") { // Check QuickLook Availability QuickLook.CheckQuickLookAvailability(localSettings); } else if (arguments == "ToggleQuickLook") { var path = (string)args.Request.Message["path"]; QuickLook.ToggleQuickLook(path); } else if (arguments == "ShellCommand") { // Kill the process. This is a BRUTAL WAY to kill a process. #if DEBUG // In debug mode this kills this process too?? #else var pid = (int)args.Request.Message["pid"]; Process.GetProcessById(pid).Kill(); #endif Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.FileName = "explorer.exe"; process.StartInfo.CreateNoWindow = false; process.StartInfo.Arguments = (string)args.Request.Message["ShellCommand"]; process.Start(); } else if (args.Request.Message.ContainsKey("Application")) { HandleApplicationLaunch(args); } } else if (args.Request.Message.ContainsKey("Application")) { HandleApplicationLaunch(args); } } finally { // Complete the deferral so that the platform knows that we're done responding to the app service call. // Note for error handling: this must be called even if SendResponseAsync() throws an exception. messageDeferral.Complete(); } }