Merge pull request #29 from zadjii-msft/dev/migrie/template-project

Add a template project and a script to generate an extension
This commit is contained in:
Clint Rutkas
2024-09-04 07:15:55 -07:00
committed by GitHub
32 changed files with 759 additions and 0 deletions

View File

@@ -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}

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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>

View 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.");
}
}
}

View File

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

View 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>

View 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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -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>

View 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.");
}
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)')) &lt; 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>

View File

@@ -0,0 +1,10 @@
{
"profiles": {
"TemplateExtension (Package)": {
"commandName": "MsixPackage"
},
"TemplateExtension (Unpackaged)": {
"commandName": "Project"
}
}
}

View File

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

View File

@@ -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>

View File

@@ -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;
}
}

View 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>