Skip to content

Commit 6328ff1

Browse files
authored
Use the actual devhome code for loading extensions (#8)
As in title. I'm adding a `ExtensionObject<T>` object too. It doesn't _enforce_ anything. We can use it to wrap up things we get from extensions. You get the object back out with `.Unsafe`, which is a mental clue "this object might not live in this process". It'll at least give us a better clue of all the places where accessing the object might not totally be safe. Also fixes a bug that makes cmdpal a bit more resilient to an extension dying and being reloaded. Just go to all apps & back, and presto, reload.
1 parent 1120e67 commit 6328ff1

13 files changed

+788
-259
lines changed

src/modules/cmdpal/extensions/SpongebotExtension/SpongebotCommandsProvider.cs

-30
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,12 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Diagnostics;
76
using System.IO;
8-
using System.Linq;
9-
using System.Net.Http;
10-
using System.Runtime.CompilerServices;
11-
using System.Runtime.InteropServices;
12-
using System.Runtime.InteropServices.WindowsRuntime;
137
using System.Text;
14-
using System.Text.Json;
158
using System.Text.Json.Nodes;
169
using System.Threading.Tasks;
17-
using System.Xml.Linq;
18-
using ABI.System;
19-
using Microsoft.UI;
2010
using Microsoft.Windows.CommandPalette.Extensions;
2111
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
22-
using Windows.Foundation;
23-
using Windows.Storage.Streams;
2412

2513
namespace SpongebotExtension;
2614

@@ -98,15 +86,10 @@ private static async Task<string> _GenerateMeme(string text) {
9886
var content = new System.Net.Http.FormUrlEncodedContent(bodyObj);
9987
var resp = await client.PostAsync("https://api.imgflip.com/caption_image", content);
10088
var respBody = await resp.Content.ReadAsStringAsync();
101-
// dynamic r = JsonSerializer.Deserialize(respBody);
10289
var response = JsonNode.Parse(respBody);
10390

104-
// var url = r?.data?.url;
10591
var url = response["data"]?["url"]?.ToString() ?? "";
10692

107-
// var encodedMessage = JsonEncodedText.Encode(Message).ToString();
108-
// var encodedUrl = JsonEncodedText.Encode(url).ToString();
109-
//
11093
var body = $$"""
11194
SpongeBot says:
11295
![{{text}}]({{url}})
@@ -144,19 +127,6 @@ public IListItem[] TopLevelCommands()
144127
};
145128
return [ listItem ];
146129
}
147-
148-
// public IAsyncOperation<IReadOnlyList<ICommand>> GetCommands()
149-
// {
150-
// var spongeCommand = new SpongeDynamicCommandHost() ;
151-
// var settingsCommand = new SettingsCommand() ;
152-
// ICommand command = (File.Exists(SettingsCommand.StateJsonPath())?
153-
// spongeCommand : settingsCommand);
154-
// var list = new List<ICommand>()
155-
// {
156-
// command
157-
// };
158-
// return Task.FromResult(list as IReadOnlyList<ICommand>).AsAsyncOperation();
159-
// }
160130
}
161131

162132

src/modules/cmdpal/src/Microsoft.CmdPal.Common/Microsoft.CmdPal.Common.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@
1818
<PackageReference Include="Microsoft.WindowsAppSDK" />
1919
</ItemGroup>
2020

21+
<ItemGroup>
22+
<ProjectReference Include="..\..\extensionsdk\Microsoft.Windows.CommandPalette.Extensions.Helpers\Microsoft.CmdPal.Extensions.Helpers.csproj" />
23+
</ItemGroup>
24+
2125
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Threading.Tasks;
7+
8+
namespace Microsoft.CmdPal.Common.Services;
9+
10+
public interface IExtensionService
11+
{
12+
Task<IEnumerable<IExtensionWrapper>> GetInstalledExtensionsAsync(bool includeDisabledExtensions = false);
13+
14+
// Task<IEnumerable<string>> GetInstalledHomeWidgetPackageFamilyNamesAsync(bool includeDisabledExtensions = false);
15+
16+
Task<IEnumerable<IExtensionWrapper>> GetInstalledExtensionsAsync(Microsoft.Windows.CommandPalette.Extensions.ProviderType providerType, bool includeDisabledExtensions = false);
17+
18+
IExtensionWrapper? GetInstalledExtension(string extensionUniqueId);
19+
20+
Task SignalStopExtensionsAsync();
21+
22+
public event EventHandler OnExtensionsChanged;
23+
24+
public void EnableExtension(string extensionUniqueId);
25+
26+
public void DisableExtension(string extensionUniqueId);
27+
28+
///// <summary>
29+
///// Gets a boolean indicating whether the extension was disabled due to the corresponding Windows optional feature
30+
///// being absent from the machine or in an unknown state.
31+
///// </summary>
32+
///// <param name="extension">The out of proc extension object</param>
33+
///// <returns>True only if the extension was disabled. False otherwise.</returns>
34+
//public Task<bool> DisableExtensionIfWindowsFeatureNotAvailable(IExtensionWrapper extension);
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Threading.Tasks;
7+
using Microsoft.Windows.CommandPalette.Extensions;
8+
using Windows.ApplicationModel;
9+
10+
namespace Microsoft.CmdPal.Common.Services;
11+
12+
public interface IExtensionWrapper
13+
{
14+
/// <summary>
15+
/// Gets the DisplayName of the package as mentioned in the manifest
16+
/// </summary>
17+
string PackageDisplayName { get; }
18+
19+
/// <summary>
20+
/// Gets DisplayName of the extension as mentioned in the manifest
21+
/// </summary>
22+
string ExtensionDisplayName { get; }
23+
24+
/// <summary>
25+
/// Gets PackageFullName of the extension
26+
/// </summary>
27+
string PackageFullName { get; }
28+
29+
/// <summary>
30+
/// Gets PackageFamilyName of the extension
31+
/// </summary>
32+
string PackageFamilyName { get; }
33+
34+
/// <summary>
35+
/// Gets Publisher of the extension
36+
/// </summary>
37+
string Publisher { get; }
38+
39+
/// <summary>
40+
/// Gets class id (GUID) of the extension class (which implements IExtension) as mentioned in the manifest
41+
/// </summary>
42+
string ExtensionClassId { get; }
43+
44+
/// <summary>
45+
/// Gets the date on which the application package was installed or last updated.
46+
/// </summary>
47+
DateTimeOffset InstalledDate { get; }
48+
49+
/// <summary>
50+
/// Gets the PackageVersion of the extension
51+
/// </summary>
52+
PackageVersion Version { get; }
53+
54+
/// <summary>
55+
/// Gets the Unique Id for the extension
56+
/// </summary>
57+
public string ExtensionUniqueId { get; }
58+
59+
/// <summary>
60+
/// Checks whether we have a reference to the extension process and we are able to call methods on the interface.
61+
/// </summary>
62+
/// <returns>Whether we have a reference to the extension process and we are able to call methods on the interface.</returns>
63+
bool IsRunning();
64+
65+
/// <summary>
66+
/// Starts the extension if not running
67+
/// </summary>
68+
/// <returns>An awaitable task</returns>
69+
Task StartExtensionAsync();
70+
71+
/// <summary>
72+
/// Signals the extension to dispose itself and removes the reference to the extension com object
73+
/// </summary>
74+
void SignalDispose();
75+
76+
/// <summary>
77+
/// Gets the underlying instance of IExtension
78+
/// </summary>
79+
/// <returns>Instance of IExtension</returns>
80+
IExtension? GetExtensionObject();
81+
82+
/// <summary>
83+
/// Tells the wrapper that the extension implements the given provider
84+
/// </summary>
85+
/// <param name="providerType">The type of provider to be added</param>
86+
void AddProviderType(ProviderType providerType);
87+
88+
/// <summary>
89+
/// Checks whether the given provider was added through `AddProviderType` method
90+
/// </summary>
91+
/// <param name="providerType">The type of the provider to be checked for</param>
92+
/// <returns>Whether the given provider was added through `AddProviderType` method</returns>
93+
bool HasProviderType(ProviderType providerType);
94+
95+
/// <summary>
96+
/// Starts the extension if not running and gets the provider from the underlying IExtension object
97+
/// Can be null if not found
98+
/// </summary>
99+
/// <typeparam name="T">The type of provider</typeparam>
100+
/// <returns>Nullable instance of the provider</returns>
101+
Task<T?> GetProviderAsync<T>()
102+
where T : class;
103+
104+
/// <summary>
105+
/// Starts the extension if not running and gets a list of providers of type T from the underlying IExtension object.
106+
/// If no providers are found, returns an empty list.
107+
/// </summary>
108+
/// <typeparam name="T">The type of provider</typeparam>
109+
/// <returns>Nullable instance of the provider</returns>
110+
Task<IEnumerable<T>> GetListOfProvidersAsync<T>()
111+
where T : class;
112+
}

src/modules/cmdpal/src/WindowsCommandPalette/App.xaml.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using Windows.ApplicationModel.Activation;
2626
using Windows.Foundation;
2727
using Windows.Foundation.Collections;
28+
using Microsoft.Windows.CommandPalette.Services;
2829

2930
// To learn more about WinUI, the WinUI project structure,
3031
// and more about our project templates, see: http://aka.ms/winui-project-info.
@@ -38,7 +39,7 @@ public partial class App : Application, IApp
3839
private Window? window;
3940
public Window? AppWindow
4041
{
41-
get { return window; }
42+
get => window;
4243
private set { }
4344
}
4445

@@ -79,6 +80,7 @@ public App()
7980

8081
// Core Services
8182
services.AddSingleton<IFileService, FileService>();
83+
services.AddSingleton<IExtensionService, ExtensionService>();
8284

8385
//// Main window: Allow access to the main window
8486
//// from anywhere in the application.

src/modules/cmdpal/src/WindowsCommandPalette/ExtensionLoader.cs

-120
This file was deleted.

0 commit comments

Comments
 (0)