Merge pull request #29 from zadjii-msft/dev/migrie/template-project
Add a template project and a script to generate an extension
@@ -26,6 +26,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessMonitorExtension", "
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Prototype", "Prototype", "{B4B13D2C-8C19-43D0-9FD4-3084F42EA4C2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemplateExtension", "extensions\TemplateExtension\TemplateExtension.csproj", "{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MastodonExtension", "extensions\MastodonExtension\MastodonExtension.csproj", "{65E22130-6A8F-4AB7-80EC-FF75475DE821}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@@ -114,6 +118,26 @@ Global
|
||||
{9456257A-3292-4A8D-AF63-9830EABE7ED2}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{9456257A-3292-4A8D-AF63-9830EABE7ED2}.Release|x64.ActiveCfg = Release|x64
|
||||
{9456257A-3292-4A8D-AF63-9830EABE7ED2}.Release|x64.Build.0 = Release|x64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Debug|x64.Build.0 = Debug|x64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Release|x64.ActiveCfg = Release|x64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Release|x64.Build.0 = Release|x64
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB}.Release|x64.Deploy.0 = Release|x64
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821}.Debug|x64.Build.0 = Debug|x64
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821}.Release|x64.ActiveCfg = Release|x64
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -128,6 +152,8 @@ Global
|
||||
{1A506BBA-06A9-476E-B5D3-1495F299D53F} = {B7FF739F-7716-4FC3-B622-705486187B87}
|
||||
{D08AE85F-B6FE-4E1C-8402-DB396B70D6DA} = {B7FF739F-7716-4FC3-B622-705486187B87}
|
||||
{9456257A-3292-4A8D-AF63-9830EABE7ED2} = {B7FF739F-7716-4FC3-B622-705486187B87}
|
||||
{EB13FDBD-7DD5-4E7E-8BEB-727B3C9331CB} = {B7FF739F-7716-4FC3-B622-705486187B87}
|
||||
{65E22130-6A8F-4AB7-80EC-FF75475DE821} = {B7FF739F-7716-4FC3-B622-705486187B87}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {BC94BFC2-A741-4978-B6A4-9E01B7660E6B}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>MastodonExtension</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
|
||||
<UseWinUI>false</UseWinUI>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extensionsdk\Microsoft.Windows.CommandPalette.Extensions.Helpers\Microsoft.CmdPal.Extensions.Helpers.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
package has not yet been restored.
|
||||
-->
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
|
||||
Explorer "Package and Publish" context menu entry to be enabled for this project even if
|
||||
the Windows App SDK Nuget package has not yet been restored.
|
||||
-->
|
||||
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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 Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
|
||||
namespace MastodonExtension;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
|
||||
internal sealed class MastodonExtensionPage : ListPage
|
||||
{
|
||||
public MastodonExtensionPage()
|
||||
{
|
||||
Icon = new("https://mastodon.social/packs/media/icons/android-chrome-36x36-4c61fdb42936428af85afdbf8c6a45a8.png");
|
||||
Name = "Mastodon";
|
||||
}
|
||||
|
||||
public override ISection[] GetItems()
|
||||
{
|
||||
return [
|
||||
new ListSection()
|
||||
{
|
||||
Items = [
|
||||
new ListItem(new NoOpAction()) { Title = "TODO: Implement your extension here" }
|
||||
],
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
|
||||
public class MastodonExtensionActionsProvider : ICommandProvider
|
||||
{
|
||||
public string DisplayName => $"Mastodon extension for cmdpal Commands";
|
||||
|
||||
public IconDataType Icon => new(string.Empty);
|
||||
|
||||
private readonly IListItem[] _actions = [
|
||||
new ListItem(new MastodonExtensionPage()),
|
||||
];
|
||||
|
||||
#pragma warning disable CA1816 // Dispose methods should call SuppressFinalize
|
||||
public void Dispose() => throw new NotImplementedException();
|
||||
#pragma warning restore CA1816 // Dispose methods should call SuppressFinalize
|
||||
|
||||
public IListItem[] TopLevelCommands()
|
||||
{
|
||||
return _actions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap uap3 rescap">
|
||||
|
||||
<Identity
|
||||
Name="MastodonExtension"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="0.0.1.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Mastodon extension for cmdpal</DisplayName>
|
||||
<PublisherDisplayName>A Lone Developer</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="Mastodon extension for cmdpal"
|
||||
Description="Mastodon extension for cmdpal"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:ExeServer Executable="MastodonExtension.exe" Arguments="-RegisterProcessAsComServer" DisplayName="ClementineExtensionApp">
|
||||
<com:Class Id="f0e93f1a-2b64-4896-abcc-8d2145480ede" DisplayName="Mastodon extension for cmdpal" />
|
||||
</com:ExeServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
<uap3:Extension Category="windows.appExtension">
|
||||
<uap3:AppExtension Name="com.microsoft.windows.commandpalette"
|
||||
Id="PG-SP-ID"
|
||||
PublicFolder="Public"
|
||||
DisplayName="Mastodon extension for cmdpal"
|
||||
Description="Mastodon extension for cmdpal">
|
||||
<uap3:Properties>
|
||||
<CmdPalProvider>
|
||||
<Activation>
|
||||
<CreateInstance ClassId="f0e93f1a-2b64-4896-abcc-8d2145480ede" />
|
||||
</Activation>
|
||||
<SupportedInterfaces>
|
||||
<Commands/>
|
||||
</SupportedInterfaces>
|
||||
</CmdPalProvider>
|
||||
</uap3:Properties>
|
||||
</uap3:AppExtension>
|
||||
</uap3:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
36
src/modules/cmdpal/extensions/MastodonExtension/Program.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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.Threading;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
|
||||
namespace MastodonExtension;
|
||||
|
||||
public class Program
|
||||
{
|
||||
[MTAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length > 0 && args[0] == "-RegisterProcessAsComServer")
|
||||
{
|
||||
using ExtensionServer server = new();
|
||||
var extensionDisposedEvent = new ManualResetEvent(false);
|
||||
var extensionInstance = new SampleExtension(extensionDisposedEvent);
|
||||
|
||||
// We are instantiating an extension instance once above, and returning it every time the callback in RegisterExtension below is called.
|
||||
// This makes sure that only one instance of SampleExtension is alive, which is returned every time the host asks for the IExtension object.
|
||||
// If you want to instantiate a new instance each time the host asks, create the new instance inside the delegate.
|
||||
server.RegisterExtension(() => extensionInstance);
|
||||
|
||||
// This will make the main thread wait until the event is signalled by the extension class.
|
||||
// Since we have single instance of the extension object, we exit as sooon as it is disposed.
|
||||
extensionDisposedEvent.WaitOne();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Not being launched as a Extension... exiting.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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 System.Threading;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
|
||||
namespace MastodonExtension;
|
||||
|
||||
[ComVisible(true)]
|
||||
[Guid("f0e93f1a-2b64-4896-abcc-8d2145480ede")]
|
||||
[ComDefaultInterface(typeof(IExtension))]
|
||||
public sealed class SampleExtension : IExtension
|
||||
{
|
||||
private readonly ManualResetEvent _extensionDisposedEvent;
|
||||
|
||||
public SampleExtension(ManualResetEvent extensionDisposedEvent)
|
||||
{
|
||||
this._extensionDisposedEvent = extensionDisposedEvent;
|
||||
}
|
||||
|
||||
public object GetProvider(ProviderType providerType)
|
||||
{
|
||||
switch (providerType)
|
||||
{
|
||||
case ProviderType.Commands:
|
||||
return new MastodonExtensionActionsProvider();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this._extensionDisposedEvent.Set();
|
||||
}
|
||||
}
|
||||
19
src/modules/cmdpal/extensions/MastodonExtension/app.manifest
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="HackerNewsExtension.app"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
|
||||
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
|
||||
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
124
src/modules/cmdpal/extensions/NewExtension.ps1
Normal file
@@ -0,0 +1,124 @@
|
||||
Param(
|
||||
[string]$Name = "MyNewExtension",
|
||||
[string]$DisplayName = "My new command palette extension",
|
||||
[switch]$Help = $false,
|
||||
[switch]$Verbose = $false
|
||||
),
|
||||
|
||||
$StartTime = Get-Date
|
||||
|
||||
if ($Help) {
|
||||
Write-Host @"
|
||||
Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License.
|
||||
|
||||
Syntax:
|
||||
NewExtension.ps1 [options]
|
||||
|
||||
Description:
|
||||
Creates a new Command Palette extension.
|
||||
|
||||
Options:
|
||||
|
||||
-Name <projectName>
|
||||
The new name for your project. This will be used to name the folder,
|
||||
classes, package, etc. This should not include spaces or special characters.
|
||||
Example: -Name MyCoolExtension
|
||||
|
||||
-DisplayName <a friendly display name>
|
||||
A display name for your extension
|
||||
Example: -DisplayName "My really cool new extension"
|
||||
|
||||
-Help
|
||||
Display this usage message.
|
||||
|
||||
Examples:
|
||||
|
||||
.\extensions\NewExtension.ps1 -name MastodonExtension -DisplayName "Mastodon extension for cmdpal"
|
||||
"@
|
||||
Exit
|
||||
}
|
||||
|
||||
if(-not $Name) {
|
||||
Write-Host "You must specify a name for your extension. Use -Name <projectName> to specify the name." -ForegroundColor RED
|
||||
Exit
|
||||
}
|
||||
|
||||
$Name = $Name -replace " ", ""
|
||||
$NewGuid = [guid]::NewGuid().ToString()
|
||||
|
||||
|
||||
$ExtensionRoot = Join-Path $PSScriptRoot $Name
|
||||
$TemplateRoot = Join-Path $PSScriptRoot "TemplateExtension"
|
||||
|
||||
if(Test-Path $ExtensionRoot) {
|
||||
Write-Host "The folder $Name already exists. Please specify a different name." -ForegroundColor RED
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Host "Creating new extension $Name"
|
||||
|
||||
# Get all the folders and files tracked in git in the template
|
||||
$TemplateFiles = git ls-files --full-name $TemplateRoot
|
||||
|
||||
# Create the new extension folder
|
||||
New-Item -ItemType Directory -Path $ExtensionRoot -Force | Out-Null
|
||||
|
||||
# $TemplateFiles will be relative to the git root. That's something like
|
||||
# src/modules/cmdpal/extensions/TemplateExtension/
|
||||
|
||||
$gitRoot = git rev-parse --show-toplevel
|
||||
|
||||
# Copy all the files from the template to the new extension
|
||||
foreach($file in $TemplateFiles) {
|
||||
$RelativePath = (Join-Path $gitRoot $file) -replace [regex]::Escape($TemplateRoot), ""
|
||||
$SourcePath = Join-Path $TemplateRoot $RelativePath
|
||||
$DestinationPath = Join-Path $ExtensionRoot $RelativePath
|
||||
if ($Verbose) {
|
||||
Write-Host "Copying $SourcePath -> $DestinationPath" -ForegroundColor DarkGray
|
||||
}
|
||||
$DestinationFolder = Split-Path $DestinationPath -Parent
|
||||
if(-not (Test-Path $DestinationFolder)) {
|
||||
New-Item -ItemType Directory -Path $DestinationFolder -Force | Out-Null
|
||||
}
|
||||
Copy-Item -Path $SourcePath -Destination $DestinationPath -Force
|
||||
}
|
||||
|
||||
# Replace all the placeholders in the files
|
||||
$Files = Get-ChildItem -Path $ExtensionRoot -Recurse -File
|
||||
foreach($file in $Files) {
|
||||
$Content = Get-Content -Path $file.FullName
|
||||
$Content = $Content -replace "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF", $NewGuid
|
||||
$Content = $Content -replace "TemplateDisplayName", $DisplayName
|
||||
$Content = $Content -replace "TemplateExtension", $Name
|
||||
Set-Content -Path $file.FullName -Value $Content
|
||||
}
|
||||
|
||||
# also renamve files with TemplateExtension in the name
|
||||
$Files = Get-ChildItem -Path $ExtensionRoot -Recurse -File -Filter "*TemplateExtension*"
|
||||
foreach($file in $Files) {
|
||||
$NewName = $file.Name -replace "TemplateExtension", $Name
|
||||
$NewPath = Join-Path $file.DirectoryName $NewName
|
||||
Move-Item -Path $file.FullName -Destination $NewPath
|
||||
}
|
||||
|
||||
Write-Host "Extension created in $ExtensionRoot" -ForegroundColor GREEN
|
||||
Write-Host "Don't forget to add your new extension to the 'Sample plugins' in the WindowsCommandPalette solution."
|
||||
|
||||
$pathToSolution = Join-Path $gitRoot "src\modules\cmdpal\WindowsCommandPalette.sln"
|
||||
Write-Host @"
|
||||
You can open the solution with
|
||||
start $pathToSolution
|
||||
and get started by editing the file
|
||||
$ExtensionRoot\src\${Name}Page.cs
|
||||
"@
|
||||
|
||||
if ($Verbose) {
|
||||
$TotalTime = (Get-Date)-$StartTime
|
||||
$TotalMinutes = [math]::Floor($TotalTime.TotalMinutes)
|
||||
$TotalSeconds = [math]::Ceiling($TotalTime.TotalSeconds)
|
||||
Write-Host @"
|
||||
Total Running Time:
|
||||
$TotalMinutes minutes and $TotalSeconds seconds
|
||||
"@ -ForegroundColor CYAN
|
||||
}
|
||||
|
After Width: | Height: | Size: 432 B |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 283 B |
|
After Width: | Height: | Size: 456 B |
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap uap3 rescap">
|
||||
|
||||
<Identity
|
||||
Name="TemplateExtension"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="0.0.1.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>TemplateDisplayName</DisplayName>
|
||||
<PublisherDisplayName>A Lone Developer</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="TemplateDisplayName"
|
||||
Description="TemplateDisplayName"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:ExeServer Executable="TemplateExtension.exe" Arguments="-RegisterProcessAsComServer" DisplayName="ClementineExtensionApp">
|
||||
<com:Class Id="FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF" DisplayName="TemplateDisplayName" />
|
||||
</com:ExeServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
<uap3:Extension Category="windows.appExtension">
|
||||
<uap3:AppExtension Name="com.microsoft.windows.commandpalette"
|
||||
Id="PG-SP-ID"
|
||||
PublicFolder="Public"
|
||||
DisplayName="TemplateDisplayName"
|
||||
Description="TemplateDisplayName">
|
||||
<uap3:Properties>
|
||||
<CmdPalProvider>
|
||||
<Activation>
|
||||
<CreateInstance ClassId="FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF" />
|
||||
</Activation>
|
||||
<SupportedInterfaces>
|
||||
<Commands/>
|
||||
</SupportedInterfaces>
|
||||
</CmdPalProvider>
|
||||
</uap3:Properties>
|
||||
</uap3:AppExtension>
|
||||
</uap3:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
36
src/modules/cmdpal/extensions/TemplateExtension/Program.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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.Threading;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
|
||||
namespace TemplateExtension;
|
||||
|
||||
public class Program
|
||||
{
|
||||
[MTAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length > 0 && args[0] == "-RegisterProcessAsComServer")
|
||||
{
|
||||
using ExtensionServer server = new();
|
||||
var extensionDisposedEvent = new ManualResetEvent(false);
|
||||
var extensionInstance = new SampleExtension(extensionDisposedEvent);
|
||||
|
||||
// We are instantiating an extension instance once above, and returning it every time the callback in RegisterExtension below is called.
|
||||
// This makes sure that only one instance of SampleExtension is alive, which is returned every time the host asks for the IExtension object.
|
||||
// If you want to instantiate a new instance each time the host asks, create the new instance inside the delegate.
|
||||
server.RegisterExtension(() => extensionInstance);
|
||||
|
||||
// This will make the main thread wait until the event is signalled by the extension class.
|
||||
// Since we have single instance of the extension object, we exit as sooon as it is disposed.
|
||||
extensionDisposedEvent.WaitOne();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Not being launched as a Extension... exiting.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Platform>ARM64</Platform>
|
||||
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
|
||||
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>False</PublishSingleFile>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Platform>x64</Platform>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>False</PublishSingleFile>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Platform>x86</Platform>
|
||||
<RuntimeIdentifier Condition="$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)')) >= 8">win-x86</RuntimeIdentifier>
|
||||
<RuntimeIdentifier Condition="$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)')) < 8">win10-x86</RuntimeIdentifier>
|
||||
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>False</PublishSingleFile>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"profiles": {
|
||||
"TemplateExtension (Package)": {
|
||||
"commandName": "MsixPackage"
|
||||
},
|
||||
"TemplateExtension (Unpackaged)": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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 System.Threading;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
|
||||
namespace TemplateExtension;
|
||||
|
||||
[ComVisible(true)]
|
||||
[Guid("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")]
|
||||
[ComDefaultInterface(typeof(IExtension))]
|
||||
public sealed class SampleExtension : IExtension
|
||||
{
|
||||
private readonly ManualResetEvent _extensionDisposedEvent;
|
||||
|
||||
public SampleExtension(ManualResetEvent extensionDisposedEvent)
|
||||
{
|
||||
this._extensionDisposedEvent = extensionDisposedEvent;
|
||||
}
|
||||
|
||||
public object GetProvider(ProviderType providerType)
|
||||
{
|
||||
switch (providerType)
|
||||
{
|
||||
case ProviderType.Commands:
|
||||
return new TemplateExtensionActionsProvider();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this._extensionDisposedEvent.Set();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>TemplateExtension</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
|
||||
<UseWinUI>false</UseWinUI>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extensionsdk\Microsoft.Windows.CommandPalette.Extensions.Helpers\Microsoft.CmdPal.Extensions.Helpers.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
package has not yet been restored.
|
||||
-->
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
|
||||
Explorer "Package and Publish" context menu entry to be enabled for this project even if
|
||||
the Windows App SDK Nuget package has not yet been restored.
|
||||
-->
|
||||
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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 Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
|
||||
namespace TemplateExtension;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
|
||||
internal sealed class TemplateExtensionPage : ListPage
|
||||
{
|
||||
public TemplateExtensionPage()
|
||||
{
|
||||
Icon = new(string.Empty);
|
||||
Name = "TemplateDisplayName";
|
||||
}
|
||||
|
||||
public override ISection[] GetItems()
|
||||
{
|
||||
return [
|
||||
new ListSection()
|
||||
{
|
||||
Items = [
|
||||
new ListItem(new NoOpAction()) { Title = "TODO: Implement your extension here" }
|
||||
],
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
|
||||
public class TemplateExtensionActionsProvider : ICommandProvider
|
||||
{
|
||||
public string DisplayName => $"TemplateDisplayName Commands";
|
||||
|
||||
public IconDataType Icon => new(string.Empty);
|
||||
|
||||
private readonly IListItem[] _actions = [
|
||||
new ListItem(new TemplateExtensionPage()),
|
||||
];
|
||||
|
||||
#pragma warning disable CA1816 // Dispose methods should call SuppressFinalize
|
||||
public void Dispose() => throw new NotImplementedException();
|
||||
#pragma warning restore CA1816 // Dispose methods should call SuppressFinalize
|
||||
|
||||
public IListItem[] TopLevelCommands()
|
||||
{
|
||||
return _actions;
|
||||
}
|
||||
}
|
||||
19
src/modules/cmdpal/extensions/TemplateExtension/app.manifest
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="HackerNewsExtension.app"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
|
||||
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
|
||||
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||