AppCommand.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Diagnostics; 7 using System.Threading.Tasks; 8 using ManagedCommon; 9 using Microsoft.CmdPal.Ext.Apps.Properties; 10 using Microsoft.CmdPal.Ext.Apps.Utils; 11 using Microsoft.CommandPalette.Extensions.Toolkit; 12 using Windows.Win32; 13 using Windows.Win32.System.Com; 14 using Windows.Win32.UI.Shell; 15 using WyHash; 16 17 namespace Microsoft.CmdPal.Ext.Apps; 18 19 internal sealed partial class AppCommand : InvokableCommand 20 { 21 private readonly AppItem _app; 22 23 public AppCommand(AppItem app) 24 { 25 _app = app; 26 Name = Resources.run_command_action!; 27 Id = GenerateId(); 28 Icon = Icons.GenericAppIcon; 29 } 30 31 private static async Task StartApp(string aumid) 32 { 33 await Task.Run(() => 34 { 35 unsafe 36 { 37 IApplicationActivationManager* appManager = null; 38 try 39 { 40 PInvoke.CoCreateInstance(typeof(ApplicationActivationManager).GUID, null, CLSCTX.CLSCTX_INPROC_SERVER, out appManager).ThrowOnFailure(); 41 using var handle = new SafeComHandle((IntPtr)appManager); 42 appManager->ActivateApplication( 43 aumid, 44 string.Empty, 45 ACTIVATEOPTIONS.AO_NONE, 46 out var unusedPid); 47 } 48 catch (System.Exception ex) 49 { 50 Logger.LogError(ex.Message); 51 } 52 } 53 }).ConfigureAwait(false); 54 } 55 56 private static async Task StartExe(string path) 57 { 58 await Task.Run(() => 59 { 60 try 61 { 62 Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); 63 } 64 catch (System.Exception ex) 65 { 66 Logger.LogError(ex.Message); 67 } 68 }); 69 } 70 71 private async Task Launch() 72 { 73 if (_app.IsPackaged) 74 { 75 await StartApp(_app.UserModelId); 76 } 77 else 78 { 79 await StartExe(_app.ExePath); 80 } 81 } 82 83 public override CommandResult Invoke() 84 { 85 _ = Launch(); 86 return CommandResult.Dismiss(); 87 } 88 89 private string GenerateId() 90 { 91 // Use WyHash64 to generate stable ID hashes. 92 // manually seeding with 0, so that the hash is stable across launches 93 var result = WyHash64.ComputeHash64(_app.Name + _app.Subtitle + _app.ExePath, seed: 0); 94 return $"{_app.Name}_{result}"; 95 } 96 }