[PT Run] Service Plugin (#8076)

* PT Run service plugin

* icon, localization and fixes

* basic toast notification

* service start mode

* improved keys

* fixed setup

* improvements

* added _ keyword
* better shortcuts
* action for open services.msc

* pt run service plugin dll signing

* renamed Microsoft.Plugin.Service

* changed output dir

* set ! action keyword

* launcher dll

Co-authored-by: Clint Rutkas <clint@rutkas.com>
This commit is contained in:
Davide Giacometti 2021-01-06 11:40:07 +01:00 committed by GitHub
parent f0600f1725
commit 3a87c4909c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1071 additions and 4 deletions

View file

@ -130,6 +130,7 @@ build:
- 'modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Wox.Infrastructure.dll'
- 'modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Wox.Plugin.dll'
- 'modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Telemetry.dll'
- 'modules\launcher\Plugins\Service\Microsoft.PowerToys.Run.Plugin.Service.dll'
- 'modules\launcher\PowerLauncher.dll'
- 'modules\launcher\PowerLauncher.exe'
- 'modules\launcher\PowerLauncher.Telemetry.dll'

View file

@ -151,6 +151,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerLauncher", "src\module
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4}
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {59BD9891-3837-438A-958D-ADC7F91F6F7E}
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}
{0351ADA4-0C32-4652-9BA0-41F7B602372B} = {0351ADA4-0C32-4652-9BA0-41F7B602372B}
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4} = {787B8AA6-CA93-4C84-96FE-DF31110AD1C4}
{F8B870EB-D5F5-45BA-9CF7-A5C459818820} = {F8B870EB-D5F5-45BA-9CF7-A5C459818820}
{74F1B9ED-F59C-4FE7-B473-7B453E30837E} = {74F1B9ED-F59C-4FE7-B473-7B453E30837E}
@ -244,6 +245,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Sys", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Sys.UnitTests", "src\modules\launcher\Plugins\Microsoft.Plugin.Sys.UnitTests\Microsoft.Plugin.Sys.UnitTests.csproj", "{DA5A6FE9-0040-40CC-83CC-764AE5306590}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.Service", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Service\Microsoft.PowerToys.Run.Plugin.Service.csproj", "{0351ADA4-0C32-4652-9BA0-41F7B602372B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logger", "src\common\logger\logger.vcxproj", "{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SetttingsAPI", "src\common\SettingsAPI\SetttingsAPI.vcxproj", "{6955446D-23F7-4023-9BB3-8657F904AF99}"
@ -560,6 +563,10 @@ Global
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.Build.0 = Debug|x64
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.ActiveCfg = Release|x64
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.Build.0 = Release|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.ActiveCfg = Debug|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.Build.0 = Debug|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.ActiveCfg = Release|x64
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.Build.0 = Release|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.ActiveCfg = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.Build.0 = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.ActiveCfg = Release|x64
@ -686,6 +693,7 @@ Global
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F} = {E4E03FE0-94FD-47C7-88C5-F17D0AA549D3}
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{DA5A6FE9-0040-40CC-83CC-764AE5306590} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{0351ADA4-0C32-4652-9BA0-41F7B602372B} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD} = {E4E03FE0-94FD-47C7-88C5-F17D0AA549D3}
{6955446D-23F7-4023-9BB3-8657F904AF99} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{58736667-1027-4AD7-BFDF-7A3A6474103A} = {5A7818A8-109C-4E1C-850D-1A654E234B0E}

View file

@ -250,6 +250,9 @@
<Directory Id="WindowWalkerImagesFolder" Name="Images" />
<Directory Id="WindowWalkerLanguagesFolder" Name="Languages" />
</Directory>
<Directory Id="ServicePluginFolder" Name="Service">
<Directory Id="ServiceImagesFolder" Name="Images" />
</Directory>
</Directory>
<Directory Id="LauncherPropertiesFolder" Name="Properties" />
</Directory>
@ -876,9 +879,17 @@
</Fragment>
<Fragment>
<ComponentGroup Id="LauncherComponents">
<Component Id="launcherInstallComponent" Directory="LauncherInstallFolder" Guid="5E688DB4-C522-4268-BA54-ED1CDFFE9DB6">
<!-- Toast Notification AUMID -->
<RegistryKey Root="HKCU" Key="SOFTWARE\Classes\AppUserModelId\PowerToysRun">
<RegistryValue Type="string" Name="DisplayName" Value="PowerToys Run" />
<RegistryValue Type="string" Name="IconUri" Value="[LauncherImagesFolder]icon.ico" />
</RegistryKey>
<File Source="$(var.BinX64Dir)modules\Launcher\Microsoft.Launcher.dll" />
<?foreach File in concrt140_app.dll;ICSharpCode.SharpZipLib.dll;JetBrains.Annotations.dll;Mages.Core.dll;Microsoft.Search.Interop.dll;Mono.Cecil.dll;Mono.Cecil.Mdb.dll;Mono.Cecil.Pdb.dll;Mono.Cecil.Rocks.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;NLog.dll;NLog.Extensions.Logging.dll;PowerLauncher.deps.json;PowerLauncher.dll;PowerLauncher.exe;Microsoft.Xaml.Behaviors.dll;System.Text.Json.dll;PowerLauncher.runtimeconfig.json;System.Data.OleDb.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;Wox.Infrastructure.dll;Wox.Plugin.dll;PowerToysInterop.dll;ManagedTelemetry.dll;PowerLauncher.Telemetry.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.DependencyInjection.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;ControlzEx.dll;ManagedCommon.dll;System.IO.Abstractions.dll;Microsoft.PowerToys.Common.UI.dll?>
<?foreach File in concrt140_app.dll;ICSharpCode.SharpZipLib.dll;JetBrains.Annotations.dll;Mages.Core.dll;Microsoft.Search.Interop.dll;Mono.Cecil.dll;Mono.Cecil.Mdb.dll;Mono.Cecil.Pdb.dll;Mono.Cecil.Rocks.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;NLog.dll;NLog.Extensions.Logging.dll;PowerLauncher.deps.json;PowerLauncher.dll;PowerLauncher.exe;Microsoft.Xaml.Behaviors.dll;System.Text.Json.dll;PowerLauncher.runtimeconfig.json;System.Data.OleDb.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;Wox.Infrastructure.dll;Wox.Plugin.dll;PowerToysInterop.dll;ManagedTelemetry.dll;PowerLauncher.Telemetry.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.DependencyInjection.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;ControlzEx.dll;ManagedCommon.dll;System.IO.Abstractions.dll;Microsoft.PowerToys.Common.UI.dll;System.ServiceProcess.ServiceController.dll;Microsoft.Toolkit.Uwp.Notifications.dll?>
<File Id="File_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\$(var.File)" />
<?endforeach?>
<File Source="$(var.BinX64Dir)SettingsUIRunner\Microsoft.PowerToys.Settings.UI.Lib.dll" />
@ -888,7 +899,7 @@
<?endforeach?>
</Component>
<Component Id="launcherImagesComponent" Directory="LauncherImagesFolder" Guid="D254220C-1DD9-4C74-8810-1AAB2F940DE8">
<?foreach File in app.dark.png;app.light.png;app_error.dark.png;app_error.light.png;Browser.png;calculator.png;cancel.png;close.png;cmd.png;color.png;copy.png;down.png;EXE.png;file.png;find.png;folder.png;history.png;image.png;Link.png;lock.png;logoff.png;ok.png;open.png;plugin.png;recyclebin.png;restart.png;search.png;settings.png;shutdown.png;sleep.png;up.png;update.png;warning.png?>
<?foreach File in app.dark.png;app.light.png;app_error.dark.png;app_error.light.png;Browser.png;calculator.png;cancel.png;close.png;cmd.png;color.png;copy.png;down.png;EXE.png;file.png;find.png;folder.png;history.png;image.png;Link.png;lock.png;logoff.png;ok.png;open.png;plugin.png;recyclebin.png;restart.png;search.png;settings.png;shutdown.png;sleep.png;up.png;update.png;warning.png;icon.ico?>
<File Id="File_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Images\$(var.File)" />
<?endforeach?>
<File Source="$(var.BinX64Dir)modules\launcher\Images\New Message.png" />
@ -974,6 +985,17 @@
<File Id="WindowWalkerDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Images\windowwalker.dark.png" />
<File Id="WindowWalkerLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Images\windowwalker.light.png" />
</Component>
<!-- Service Plugin -->
<Component Id="ServiceComponent" Directory="ServicePluginFolder" Guid="66245D20-0078-4136-8A34-4A282FB894D5">
<?foreach File in plugin.json;Microsoft.PowerToys.Run.Plugin.Service.deps.json;Microsoft.PowerToys.Run.Plugin.Service.dll?>
<File Id="Service_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Service\$(var.File)" />
<?endforeach?>
</Component>
<Component Id="ServiceImagesComponent" Directory="ServiceImagesFolder" Guid="5846BF01-5BCB-47DC-9472-0E478A41B1AE">
<File Id="ServiceDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Service\Images\service.dark.png" />
<File Id="ServiceLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Service\Images\service.light.png" />
</Component>
</ComponentGroup>
</Fragment>

View file

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.Run.Plugin.Service
{
public enum Action
{
Start,
Stop,
Restart,
}
}

View file

@ -0,0 +1,215 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;
using Microsoft.PowerToys.Run.Plugin.Service.Properties;
using Wox.Plugin;
using Wox.Plugin.Logger;
namespace Microsoft.PowerToys.Run.Plugin.Service.Helpers
{
public static class ServiceHelper
{
public static IEnumerable<Result> Search(string search, string icoPath)
{
var services = ServiceController.GetServices();
return services
.Where(s => s.DisplayName.StartsWith(search, StringComparison.OrdinalIgnoreCase) || s.ServiceName.StartsWith(search, StringComparison.OrdinalIgnoreCase))
.Select(s => new Result
{
Title = GetResultTitle(s),
SubTitle = GetResultSubTitle(s),
IcoPath = icoPath,
ContextData = new ServiceResult(s),
});
}
public static void ChangeStatus(ServiceResult serviceResult, Action action, IPublicAPI contextAPI)
{
if (serviceResult == null)
{
throw new ArgumentNullException(nameof(serviceResult));
}
if (contextAPI == null)
{
throw new ArgumentNullException(nameof(contextAPI));
}
try
{
var info = new ProcessStartInfo
{
FileName = "net",
Verb = "runas",
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Hidden,
};
if (action == Action.Start)
{
info.Arguments = string.Join(' ', "start", serviceResult.ServiceName);
}
else if (action == Action.Stop)
{
info.Arguments = string.Join(' ', "stop", serviceResult.ServiceName);
}
else if (action == Action.Restart)
{
info.FileName = "cmd";
info.Arguments = string.Join(' ', "/c net stop", serviceResult.ServiceName, "&&", "net start", serviceResult.ServiceName);
}
var process = Process.Start(info);
process.WaitForExit();
var exitCode = process.ExitCode;
if (exitCode == 0)
{
contextAPI.ShowNotification(GetLocalizedMessage(serviceResult, action));
}
else
{
contextAPI.ShowNotification("An error occurred");
Log.Error($"The command returned {exitCode}", MethodBase.GetCurrentMethod().DeclaringType);
}
}
catch (Win32Exception ex)
{
Log.Error(ex.Message, MethodBase.GetCurrentMethod().DeclaringType);
}
}
public static void OpenServices()
{
try
{
var info = new ProcessStartInfo
{
FileName = "services.msc",
UseShellExecute = true,
};
Process.Start(info);
}
catch (Win32Exception ex)
{
Log.Error(ex.Message, MethodBase.GetCurrentMethod().DeclaringType);
}
}
private static string GetResultTitle(ServiceController serviceController)
{
if (serviceController == null)
{
throw new ArgumentNullException(nameof(serviceController));
}
var suffix = $"({serviceController.ServiceName})";
return serviceController.DisplayName.EndsWith(suffix, StringComparison.CurrentCulture) ? serviceController.DisplayName : $"{serviceController.DisplayName} {suffix}";
}
private static string GetResultSubTitle(ServiceController serviceController)
{
if (serviceController == null)
{
throw new ArgumentNullException(nameof(serviceController));
}
return $"{Resources.wox_plugin_service_status}: {GetLocalizedStatus(serviceController.Status)} - {Resources.wox_plugin_service_startup}: {GetLocalizedStartType(serviceController.StartType)}";
}
private static string GetLocalizedStatus(ServiceControllerStatus status)
{
if (status == ServiceControllerStatus.Stopped)
{
return Resources.wox_plugin_service_stopped;
}
else if (status == ServiceControllerStatus.StartPending)
{
return Resources.wox_plugin_service_start_pending;
}
else if (status == ServiceControllerStatus.StopPending)
{
return Resources.wox_plugin_service_stop_pending;
}
else if (status == ServiceControllerStatus.Running)
{
return Resources.wox_plugin_service_running;
}
else if (status == ServiceControllerStatus.ContinuePending)
{
return Resources.wox_plugin_service_continue_pending;
}
else if (status == ServiceControllerStatus.PausePending)
{
return Resources.wox_plugin_service_pause_pending;
}
else if (status == ServiceControllerStatus.Paused)
{
return Resources.wox_plugin_service_paused;
}
else
{
return status.ToString();
}
}
private static string GetLocalizedStartType(ServiceStartMode startMode)
{
if (startMode == ServiceStartMode.Boot)
{
return Resources.wox_plugin_service_start_mode_boot;
}
else if (startMode == ServiceStartMode.System)
{
return Resources.wox_plugin_service_start_mode_system;
}
else if (startMode == ServiceStartMode.Automatic)
{
return Resources.wox_plugin_service_start_mode_automatic;
}
else if (startMode == ServiceStartMode.Manual)
{
return Resources.wox_plugin_service_start_mode_manual;
}
else if (startMode == ServiceStartMode.Disabled)
{
return Resources.wox_plugin_service_start_mode_disabled;
}
else
{
return startMode.ToString();
}
}
private static string GetLocalizedMessage(ServiceResult serviceResult, Action action)
{
if (action == Action.Start)
{
return string.Format(CultureInfo.CurrentCulture, Resources.wox_plugin_service_started_notification, serviceResult.DisplayName);
}
else if (action == Action.Stop)
{
return string.Format(CultureInfo.CurrentCulture, Resources.wox_plugin_service_stopped_notification, serviceResult.DisplayName);
}
else if (action == Action.Restart)
{
return string.Format(CultureInfo.CurrentCulture, Resources.wox_plugin_service_restarted_notification, serviceResult.DisplayName);
}
else
{
return string.Empty;
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1,143 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Input;
using ManagedCommon;
using Microsoft.PowerToys.Run.Plugin.Service.Helpers;
using Microsoft.PowerToys.Run.Plugin.Service.Properties;
using Wox.Plugin;
namespace Microsoft.PowerToys.Run.Plugin.Service
{
public class Main : IPlugin, IContextMenu, IPluginI18n
{
private PluginInitContext _context;
private string _icoPath;
public void Init(PluginInitContext context)
{
_context = context;
_context.API.ThemeChanged += OnThemeChanged;
UpdateIconPath(_context.API.GetCurrentTheme());
}
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
{
if (!(selectedResult?.ContextData is ServiceResult))
{
return new List<ContextMenuResult>();
}
var contextMenuResult = new List<ContextMenuResult>();
var serviceResult = selectedResult.ContextData as ServiceResult;
if (serviceResult.IsRunning)
{
// Stop
contextMenuResult.Add(new ContextMenuResult
{
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Title = Resources.wox_plugin_service_stop,
Glyph = "\xE71A",
FontFamily = "Segoe MDL2 Assets",
AcceleratorKey = Key.Enter,
Action = _ =>
{
Task.Run(() => ServiceHelper.ChangeStatus(serviceResult, Action.Stop, _context.API));
return true;
},
});
// Restart
contextMenuResult.Add(new ContextMenuResult
{
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Title = Resources.wox_plugin_service_restart,
Glyph = "\xE72C",
FontFamily = "Segoe MDL2 Assets",
AcceleratorKey = Key.R,
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
Action = _ =>
{
Task.Run(() => ServiceHelper.ChangeStatus(serviceResult, Action.Restart, _context.API));
return true;
},
});
}
else
{
// Start
contextMenuResult.Add(new ContextMenuResult
{
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Title = Resources.wox_plugin_service_start,
Glyph = "\xEDB5",
FontFamily = "Segoe MDL2 Assets",
AcceleratorKey = Key.Enter,
Action = _ =>
{
Task.Run(() => ServiceHelper.ChangeStatus(serviceResult, Action.Start, _context.API));
return true;
},
});
}
// Open services
contextMenuResult.Add(new ContextMenuResult
{
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Title = Resources.wox_plugin_service_open_services,
Glyph = "\xE8A7",
FontFamily = "Segoe MDL2 Assets",
AcceleratorKey = Key.O,
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
Action = _ =>
{
Task.Run(() => ServiceHelper.OpenServices());
return true;
},
});
return contextMenuResult;
}
public List<Result> Query(Query query)
{
var search = query?.Search ?? string.Empty;
return ServiceHelper.Search(search, _icoPath).ToList();
}
public string GetTranslatedPluginTitle()
{
return Resources.wox_plugin_service_plugin_name;
}
public string GetTranslatedPluginDescription()
{
return Resources.wox_plugin_service_plugin_description;
}
private void UpdateIconPath(Theme theme)
{
if (theme == Theme.Light || theme == Theme.HighContrastWhite)
{
_icoPath = "Images/service.light.png";
}
else
{
_icoPath = "Images/service.dark.png";
}
}
private void OnThemeChanged(Theme currentTheme, Theme newTheme)
{
UpdateIconPath(newTheme);
}
}
}

View file

@ -0,0 +1,100 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Microsoft.PowerToys.Run.Plugin.Service</RootNamespace>
<AssemblyName>Microsoft.PowerToys.Run.Plugin.Service</AssemblyName>
<Version>$(Version).0</Version>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<Platforms>x64</Platforms>
<NeutralLanguage>en-US</NeutralLanguage>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Service\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Service\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<None Include="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\..\codeAnalysis\GlobalSuppressions.cs">
<Link>GlobalSuppressions.cs</Link>
</Compile>
<AdditionalFiles Include="..\..\..\..\codeAnalysis\StyleCop.json">
<Link>StyleCop.json</Link>
</AdditionalFiles>
</ItemGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Update="Images\service.dark.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\service.light.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -0,0 +1,277 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.PowerToys.Run.Plugin.Service.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.PowerToys.Run.Plugin.Service.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Continue.
/// </summary>
internal static string wox_plugin_service_continue_pending {
get {
return ResourceManager.GetString("wox_plugin_service_continue_pending", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open services (Ctrl+Shift+O).
/// </summary>
internal static string wox_plugin_service_open_services {
get {
return ResourceManager.GetString("wox_plugin_service_open_services", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Pausing.
/// </summary>
internal static string wox_plugin_service_pause_pending {
get {
return ResourceManager.GetString("wox_plugin_service_pause_pending", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Paused.
/// </summary>
internal static string wox_plugin_service_paused {
get {
return ResourceManager.GetString("wox_plugin_service_paused", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Manages Windows services.
/// </summary>
internal static string wox_plugin_service_plugin_description {
get {
return ResourceManager.GetString("wox_plugin_service_plugin_description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Service.
/// </summary>
internal static string wox_plugin_service_plugin_name {
get {
return ResourceManager.GetString("wox_plugin_service_plugin_name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Restart (Ctrl+Shift+R).
/// </summary>
internal static string wox_plugin_service_restart {
get {
return ResourceManager.GetString("wox_plugin_service_restart", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} has been restarted.
/// </summary>
internal static string wox_plugin_service_restarted_notification {
get {
return ResourceManager.GetString("wox_plugin_service_restarted_notification", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Running.
/// </summary>
internal static string wox_plugin_service_running {
get {
return ResourceManager.GetString("wox_plugin_service_running", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Start (Enter).
/// </summary>
internal static string wox_plugin_service_start {
get {
return ResourceManager.GetString("wox_plugin_service_start", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Automatic.
/// </summary>
internal static string wox_plugin_service_start_mode_automatic {
get {
return ResourceManager.GetString("wox_plugin_service_start_mode_automatic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Boot.
/// </summary>
internal static string wox_plugin_service_start_mode_boot {
get {
return ResourceManager.GetString("wox_plugin_service_start_mode_boot", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Disabled.
/// </summary>
internal static string wox_plugin_service_start_mode_disabled {
get {
return ResourceManager.GetString("wox_plugin_service_start_mode_disabled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Manual.
/// </summary>
internal static string wox_plugin_service_start_mode_manual {
get {
return ResourceManager.GetString("wox_plugin_service_start_mode_manual", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to System.
/// </summary>
internal static string wox_plugin_service_start_mode_system {
get {
return ResourceManager.GetString("wox_plugin_service_start_mode_system", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Starting.
/// </summary>
internal static string wox_plugin_service_start_pending {
get {
return ResourceManager.GetString("wox_plugin_service_start_pending", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Started.
/// </summary>
internal static string wox_plugin_service_started {
get {
return ResourceManager.GetString("wox_plugin_service_started", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} has been started.
/// </summary>
internal static string wox_plugin_service_started_notification {
get {
return ResourceManager.GetString("wox_plugin_service_started_notification", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Startup.
/// </summary>
internal static string wox_plugin_service_startup {
get {
return ResourceManager.GetString("wox_plugin_service_startup", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Status.
/// </summary>
internal static string wox_plugin_service_status {
get {
return ResourceManager.GetString("wox_plugin_service_status", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Stop (Enter).
/// </summary>
internal static string wox_plugin_service_stop {
get {
return ResourceManager.GetString("wox_plugin_service_stop", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Stopping.
/// </summary>
internal static string wox_plugin_service_stop_pending {
get {
return ResourceManager.GetString("wox_plugin_service_stop_pending", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Stopped.
/// </summary>
internal static string wox_plugin_service_stopped {
get {
return ResourceManager.GetString("wox_plugin_service_stopped", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} has been stopped.
/// </summary>
internal static string wox_plugin_service_stopped_notification {
get {
return ResourceManager.GetString("wox_plugin_service_stopped_notification", resourceCulture);
}
}
}
}

View file

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="wox_plugin_service_continue_pending" xml:space="preserve">
<value>Continue</value>
</data>
<data name="wox_plugin_service_open_services" xml:space="preserve">
<value>Open services (Ctrl+Shift+O)</value>
</data>
<data name="wox_plugin_service_paused" xml:space="preserve">
<value>Paused</value>
</data>
<data name="wox_plugin_service_pause_pending" xml:space="preserve">
<value>Pausing</value>
</data>
<data name="wox_plugin_service_plugin_description" xml:space="preserve">
<value>Manages Windows services</value>
</data>
<data name="wox_plugin_service_plugin_name" xml:space="preserve">
<value>Service</value>
</data>
<data name="wox_plugin_service_restart" xml:space="preserve">
<value>Restart (Ctrl+Shift+R)</value>
</data>
<data name="wox_plugin_service_restarted_notification" xml:space="preserve">
<value>{0} has been restarted</value>
</data>
<data name="wox_plugin_service_running" xml:space="preserve">
<value>Running</value>
</data>
<data name="wox_plugin_service_start" xml:space="preserve">
<value>Start (Enter)</value>
</data>
<data name="wox_plugin_service_started" xml:space="preserve">
<value>Started</value>
</data>
<data name="wox_plugin_service_started_notification" xml:space="preserve">
<value>{0} has been started</value>
</data>
<data name="wox_plugin_service_startup" xml:space="preserve">
<value>Startup</value>
</data>
<data name="wox_plugin_service_start_mode_automatic" xml:space="preserve">
<value>Automatic</value>
</data>
<data name="wox_plugin_service_start_mode_boot" xml:space="preserve">
<value>Boot</value>
</data>
<data name="wox_plugin_service_start_mode_disabled" xml:space="preserve">
<value>Disabled</value>
</data>
<data name="wox_plugin_service_start_mode_manual" xml:space="preserve">
<value>Manual</value>
</data>
<data name="wox_plugin_service_start_mode_system" xml:space="preserve">
<value>System</value>
</data>
<data name="wox_plugin_service_start_pending" xml:space="preserve">
<value>Starting</value>
</data>
<data name="wox_plugin_service_status" xml:space="preserve">
<value>Status</value>
</data>
<data name="wox_plugin_service_stop" xml:space="preserve">
<value>Stop (Enter)</value>
</data>
<data name="wox_plugin_service_stopped" xml:space="preserve">
<value>Stopped</value>
</data>
<data name="wox_plugin_service_stopped_notification" xml:space="preserve">
<value>{0} has been stopped</value>
</data>
<data name="wox_plugin_service_stop_pending" xml:space="preserve">
<value>Stopping</value>
</data>
</root>

View file

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.ServiceProcess;
namespace Microsoft.PowerToys.Run.Plugin.Service
{
public class ServiceResult
{
public string ServiceName { get; }
public string DisplayName { get; }
public ServiceStartMode StartMode { get; }
public bool IsRunning { get; }
public ServiceResult(ServiceController serviceController)
{
if (serviceController == null)
{
throw new ArgumentNullException(nameof(serviceController));
}
ServiceName = serviceController.ServiceName;
DisplayName = serviceController.DisplayName;
StartMode = serviceController.StartType;
IsRunning = serviceController.Status != ServiceControllerStatus.Stopped && serviceController.Status != ServiceControllerStatus.StopPending;
}
}
}

View file

@ -0,0 +1,12 @@
{
"ID": "11A6C36E4E91439CA69F702CBD364EF7",
"ActionKeyword": "!",
"Name": "Service",
"Description": "Manages Windows services",
"Author": "davidegiacometti",
"Version": "1.0.0",
"Language": "csharp",
"Website": "https://aka.ms/powertoys",
"ExecuteFileName": "Microsoft.PowerToys.Run.Plugin.Service.dll",
"IcoPath": "Images\\service.dark.png"
}

View file

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using Microsoft.Toolkit.Uwp.Notifications;
namespace PowerLauncher.Helper
{
[ClassInterface(ClassInterfaceType.None)]
#pragma warning disable CS0618 // Type or member is obsolete
[ComSourceInterfaces(typeof(INotificationActivationCallback))]
#pragma warning restore CS0618 // Type or member is obsolete
[Guid("DD5CACDA-7C2E-4997-A62A-04A597B58F76")]
[ComVisible(true)]
public class LauncherNotificationActivator : NotificationActivator
{
public override void OnActivated(string invokedArgs, NotificationUserInput userInput, string appUserModelId)
{
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
@ -100,6 +100,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="6.1.1" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.19" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NuGet.CommandLine" Version="5.7.0">
@ -113,6 +114,7 @@
<PackageReference Include="System.Runtime" Version="4.3.1" />
<PackageReference Include="Microsoft.VCRTForwarders.140" Version="1.0.6" />
<PackageReference Include="System.Data.OleDb" Version="4.7.1" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.7.0" />
<PackageReference Include="tlbimp-Microsoft.Search.Interop" Version="1.0.0">
<NoWarn>NU1701</NoWarn>
</PackageReference>
@ -175,6 +177,9 @@
<None Update="Images\history.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\icon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\image.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@ -9,9 +9,11 @@ using System.Net;
using System.Windows;
using ManagedCommon;
using Microsoft.PowerToys.Common.UI;
using Microsoft.Toolkit.Uwp.Notifications;
using PowerLauncher.Helper;
using PowerLauncher.Plugin;
using PowerLauncher.ViewModel;
using Windows.UI.Notifications;
using Wox.Infrastructure.Image;
using Wox.Plugin;
@ -33,6 +35,9 @@ namespace Wox
_themeManager = themeManager ?? throw new ArgumentNullException(nameof(themeManager));
_themeManager.ThemeChanged += OnThemeChanged;
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
DesktopNotificationManagerCompat.RegisterActivator<LauncherNotificationActivator>();
DesktopNotificationManagerCompat.RegisterAumidAndComServer<LauncherNotificationActivator>("PowerToysRun");
}
public void ChangeQuery(string query, bool requery = false)
@ -79,6 +84,18 @@ namespace Wox
});
}
public void ShowNotification(string text)
{
Application.Current.Dispatcher.Invoke(() =>
{
ToastContent toastContent = new ToastContentBuilder()
.AddText(text)
.GetToastContent();
var toast = new ToastNotification(toastContent.GetXml());
DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
});
}
public void InstallPlugin(string path)
{
Application.Current.Dispatcher.Invoke(() => PluginManager.InstallPlugin(path));

View file

@ -74,5 +74,11 @@ namespace Wox.Plugin
/// Get all loaded plugins
/// </summary>
List<PluginPair> GetAllPlugins();
/// <summary>
/// Show toast notification
/// </summary>
/// <param name="text">Notification text</param>
void ShowNotification(string text);
}
}