Поделиться через


Начните работу с функциями приложений в Windows

В этой статье описаны шаги по созданию действий приложений и описаны компоненты приложения поставщика действий приложений. Действия приложений — это отдельные единицы поведения, которые приложение Windows может реализовать и зарегистрировать, чтобы они могли быть доступны из других приложений и возможностей, легко интегрируясь в рабочие процессы пользователей. Дополнительные сведения о действиях приложений в Windows см. в разделе "Действия приложений" в Обзоре Windows

Действия поддерживают две разные модели активации для поставщиков действий приложений: активацию COM и активацию запуска URI. В этой статье описываются шаги создания поставщика действий для приложения, который использует активацию COM.

  1. Выполните одну из приведенных ниже команд в терминале (будь то разработчик C# или C++). При этом запускается файл конфигурации WinGet , выполняющий следующие задачи (уже установленные зависимости будут пропущены):

    • Включает режим разработчика.
    • Установка Visual Studio Community Edition
    • Включите рабочие нагрузки для разработки приложений Windows и нагрузки C++ или .NET/C#
    • Включите средства упаковки MSIX

Для разработчиков C#:

winget configure https://raw.githubusercontent.com/microsoft/winget-dsc/refs/heads/main/samples/Configuration%20files/Learn%20tutorials/Windows%20AI/app_actions_cs.winget

Для разработчиков C++:

winget configure https://raw.githubusercontent.com/microsoft/winget-dsc/refs/heads/main/samples/Configuration%20files/Learn%20tutorials/Windows%20AI/app_actions_cpp.winget

Создание проекта приложения Windows в Visual Studio

Функция "Действия приложений в Windows" поддерживается для нескольких платформ приложений, но приложения должны иметь удостоверение пакета для регистрации в системе. В этом пошаговом руководстве будет реализован поставщик действий для приложений Windows в упакованном настольном приложении C# WinUI 3.

  1. В Visual Studio создайте проект.

  2. В диалоговом окне "Создание проекта " задайте для фильтра языка значение "C#", а фильтр платформы — "WinUI", а затем выберите шаблон проекта "Пустое приложение, упакованое (WinUI 3 в desktop)".

  3. Назовите новый проект ExampleAppActionProvider.

  4. Когда проект загрузится, в Обозревателе решений щелкните правой кнопкой мыши по имени проекта и выберите Свойства. На странице общего прокрутите страницу вниз до целевой ОС и выберите "Windows". Для целевой версии ОС и поддерживаемой версии ОС выберите версию 10.0.26100.0 или более поздней.

  5. Чтобы обновить проект для поддержки API поставщика действий, в обозревателе решений щелкните правой кнопкой мыши имя проекта и выберите "Изменить файл проекта". В PropertyGroup добавьте следующий элемент WindowsSdkPackageVersion .

    <WindowsSdkPackageVersion>10.0.26100.59-preview</WindowsSdkPackageVersion>
    

Добавление JSON-файла определения действия

Приложения поставщика действий должны предоставить файл определения действия, определяющий действия, которые реализует приложение. Этот файл содержит сведения о входных и выходных данных действий и метаданных, таких как уникальный идентификатор и описание действий. Дополнительные сведения о формате JSON-файла действия приложения см. в схеме JSON определения действия для поставщиков действий приложений Windows.

В этом примере определяется одно действие с именем SendMessage, которое принимает одну сущность Text в качестве входных данных и возвращает одно значение TextEntity в качестве выходных данных. Помимо определения действий, JSON-файл также указывает, следует ли запускать приложение поставщика действий с помощью активации COM или запуска URI. В этом примере будет использоваться активация COM.

  1. В обозревателе решений щелкните правой кнопкой мыши файл проекта ExampleAppActionProvider и выберите add-New> Item....
  2. В диалоговом окне "Добавление нового элемента" выберите текстовый файл. Назовите новый файл "registration.json" и нажмите кнопку "ОК".
  3. Добавьте следующее определение действия JSON в файл registration.json.
  4. В обозревателе решений щелкните правой кнопкой мыши файл registration.json и выберите "Свойства". В области "Свойства" установите Действие сборки в значение "Content" и установите для параметра Копировать в выходной каталог значение "Копировать, если новее".
  5. Замените значение invocation.clsid новым GUID, который будет определять поставщика. Вы можете создать новый GUID в Visual Studio, перейдя в раздел "Сервис-создание> GUID". Этот GUID будет использоваться еще раз в нескольких разных местах в этом пошаговом руководстве.
{
  "version": 2,
  "actions": [
    {
      "id": "ExampleAppActionProvider.SendMessage",
      "description": "Send a message",
      "icon": "ms-resource://Files/Assets/StoreLogo.png",
      "usesGenerativeAI": false,
      "inputs": [
        {
          "name": "message",
          "kind": "Text"
        }
      ],
      "inputCombinations": [
        {
          "inputs": [
            "message"
          ],
          "description": "Send message '${message.Text}'"
        }
      ],
      "outputs": [
        {
          "name": "response",
          "kind": "Text"
        }
      ],
      "invocation": {
        "type": "COM",
        "clsid": "00001111-aaaa-2222-bbbb-3333cccc4444"
      }
    }
  ]
}

Добавление класса ActionProvider для обработки операций действия

Поставщики действий должны реализовать интерфейс IActionProvider . Этот интерфейс требует реализации одного метода InvokeAsync, который система использует для вызова действия.

  1. В Visual Studio щелкните правой кнопкой мыши проект AppActionProvider в обозревателе решений и выберите Добавить ->Класс.
  2. В диалоговом окне "Добавить класс " назовите класс ActionProvider и нажмите кнопку "Добавить".
  3. В созданном файле ActionProvider.cs обновите определение класса, чтобы указать, что он реализует интерфейс IActionProvider .
  4. Пометка класса с помощью System.Runtime.InteropServices.GuidAttribute. Это используется кодом активации COM, показанным далее в этом пошаговом руководстве. Обязательно обновите значение до значения, указанного в поле invocation.clsid в файле registration.json.
// AppActionProvider.cs
[System.Runtime.InteropServices.GuidAttribute("00001111-aaaa-2222-bbbb-3333cccc4444")] 
public partial class AppActionProvider : IActionProvider

Реализуйте метод IActionProvider.InvokeAsync

Метод InvokeAsync имеет тип возвращаемого значения IAsyncAction. В этом примере используется вспомогательный класс, возвращающий задачу, который затем преобразуется в IAsyncAction с вызовом метода расширения AsAsyncAction . Добавьте следующее определение метода в класс AppActionProvider .

// AppActionProvider.cs
public IAsyncAction InvokeAsync(ActionInvocationContext context)
{
    return InvokeAsyncHelper(context).AsAsyncAction();
}

В вспомогательном методе InvokeAsyncHelper выполняются следующие действия:

  • ActionInvocationContext.GetInputEntities вызывается для получения набора сущностей, передаваемых в качестве входных данных в действие.
  • Поставщик действий может поддерживать несколько действий, поэтому перед обработкой входных значений свойство ActionInvocationContext.ActionId вычисляется, чтобы определить, какое действие вызывается. Идентификатор будет значением, объявленным для действия в поле id в файле reisgration.json.
  • В этом примере существует одна входная сущность типа TextActionEntity с именем message. Вспомогательный метод перебирает входные данные и проверяет ожидаемое имя.
  • При обнаружении ожидаемого имени входной сущности он возвращается к типу TextEntity , а текст сообщения извлекается с помощью свойства Text . На этом этапе реальная реализация действия будет принимать это входное сообщение, выполнять некоторую обработку и генерировать ответ.
  • В этом примере создается ответ TextEntity, как указано в поле выходных данных в файле registration.json. Сущность создается из жестко закодированных строк, а затем добавляется в качестве выходных данных путем вызова SetOutputEntity, передавая имя выходной сущности и объект TextEntity .

Добавьте следующее определение метода в класс AppActionProvider .

// AppActionProvider.cs
async Task InvokeAsyncHelper(ActionInvocationContext context)
{
    NamedActionEntity[] inputs = context.GetInputEntities();

    var actionId = context.ActionId;
    switch (actionId)
    {
      case "ExampleActionProvider.SendMessage":
          foreach (NamedActionEntity inputEntity in inputs)
          {
              if (inputEntity.Name.Equals("message", StringComparison.Ordinal))
              {
                
                TextActionEntity entity = (TextActionEntity)(inputEntity.Entity);
                string message = entity.Text;
                
                // TODO: Process the message and generate a response

                string response = "This is the message response"; 
                TextActionEntity result = context.EntityFactory.CreateTextEntity(response);
                context.SetOutputEntity("response", result);

              }

          }

          break;

      default:

          break;

  }

}

Обновление файла манифеста пакета приложения

Файл Package.appmanifest содержит сведения о пакете MSIX для приложения. Чтобы зарегистрировать систему в качестве поставщика действий приложений Windows, приложение должно включать элемент uap3:Extension с параметром "Категория ", равным "windows.appExtension". Этот элемент используется для указания расположения JSON-файла Действия приложения, который определяет действия приложения. Дополнительные сведения о формате манифеста пакета приложения поставщика действий см. в формате XML манифеста пакета для приложения Windows App Action.

В данном учебном примере используется активация COM для запуска провайдера действий приложения. Чтобы включить активацию COM, используйте элемент com2:Extension в манифесте пакета приложения. Значение invocation.clsid , указанное в JSON-файле определения действия, должно соответствовать идентификатору класса, указанному в элементе com:Class в манифесте пакета приложения.

  1. Щелкните правой кнопкой мыши файл Package.appxmanifest и выберите команду View Code
  2. Добавьте следующие пространства имен в элемент Package в корне файла.
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:com2="http://schemas.microsoft.com/appx/manifest/com/windows10/2"
xmlns:com3="http://schemas.microsoft.com/appx/manifest/com/windows10/3"
  1. Добавьте следующий элемент Extensions в элемент Application и после элемента VisualElements .
<Extensions>
  <com2:Extension Category="windows.comServer">
    <com2:ComServer>
        <com3:ExeServer Executable="ExampleAppActionProvider.exe" DisplayName="ExampleAppActionProvider">
            <com:Class Id="00001111-aaaa-2222-bbbb-3333cccc4444" DisplayName="ExampleAppActionProvider" />
        </com3:ExeServer>
      </com2:ComServer>
    </com2:Extension>
    <uap3:Extension Category="windows.appExtension">
        <uap3:AppExtension Name="com.microsoft.windows.ai.actions" DisplayName="Example App Action Provider" Id="appactionprovider" PublicFolder="Assets">
        <uap3:Properties>
            <Registration xmlns="">registration.json</Registration>
        </uap3:Properties>
    </uap3:AppExtension>
</uap3:Extension>
</Extensions>

Реализовать фабрику классов, которая будет создавать экземпляр IActionProvider по запросу

После запуска приложения поставщика действий приложение должно вызвать CoRegisterClassObject , чтобы система может создать экземпляр COM-сервера для реализации IActionProvider . Для этой функции требуется реализация IClassFactory. В этом примере фабрика классов реализуется в автономном вспомогательном классе.

В Visual Studio щелкните правой кнопкой мыши проект ExampleAppActionProvider в обозревателе решений и выберите Добавить ->Класс. В диалоговом окне Добавить класс наберите имя класса "FactoryHelper" и нажмите Добавить.

Замените содержимое файла FactoryHelper.cs следующим кодом. Этот код определяет интерфейс IClassFactory и реализует два метода CreateInstance и LockServer. Этот код является типичным шаблоном для реализации фабрики классов и не зависит от функциональности поставщика действий приложения, за исключением того, что созданный объект класса реализует интерфейс IActionProvider .

// FactoryHelper.cs

using Microsoft.Windows.Widgets.Providers;
using System.Runtime.InteropServices;
using WinRT;

namespace COM
{
    static class Guids
    {
        public const string IClassFactory = "00000001-0000-0000-C000-000000000046";
        public const string IUnknown = "00000000-0000-0000-C000-000000000046";
    }

    /// 
    /// IClassFactory declaration
    /// 
    [ComImport, ComVisible(false), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(COM.Guids.IClassFactory)]
    internal interface IClassFactory
    {
        [PreserveSig]
        int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
        [PreserveSig]
        int LockServer(bool fLock);
    }

    [ComVisible(true)]
    class WidgetProviderFactory<T> : IClassFactory
    where T : IActionProvider, new()
    {
        public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
        {
            ppvObject = IntPtr.Zero;

            if (pUnkOuter != IntPtr.Zero)
            {
                Marshal.ThrowExceptionForHR(CLASS_E_NOAGGREGATION);
            }

            if (riid == typeof(T).GUID || riid == Guid.Parse(COM.Guids.IUnknown))
            {
                // Create the instance of the .NET object
                ppvObject = MarshalInspectable<IActionProvider>.FromManaged(new T());
            }
            else
            {
                // The object that ppvObject points to does not support the
                // interface identified by riid.
                Marshal.ThrowExceptionForHR(E_NOINTERFACE);
            }

            return 0;
        }

        int IClassFactory.LockServer(bool fLock)
        {
            return 0;
        }

        private const int CLASS_E_NOAGGREGATION = -2147221232;
        private const int E_NOINTERFACE = -2147467262;

    }
}

Реализуйте пользовательский метод "Main"

В шаблоне проекта по умолчанию точка входа основного метода автоматически создается компилятором. Этот пример отключит автоматическое создание Main , чтобы при запуске можно было запустить необходимый код активации.

  1. В обозревателе решений щелкните правой кнопкой мыши значок проекта и выберите "Изменить файл проекта".
  2. В элементе PropertyGroup добавьте следующий дочерний элемент, чтобы отключить автоматически созданную главную функцию.
<DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>

Затем в обозревателе решений щелкните правой кнопкой мыши значок проекта и выберите "Добавить> класс". Измените имя файла на "Program.cs" и нажмите кнопку "Добавить".

В исполняемом файле Program.cs вызывается CoRegisterClassObject для регистрации COM-сервера поставщика действий. Замените содержимое Program.cs приведенным ниже кодом. Этот код импортирует функцию CoRegisterClassObject и вызывает ее, передавая класс ActionProviderFactory , определенный на предыдущем шаге. Обязательно обновите объявление переменной CLSID_Factory , чтобы использовать GUID, указанный в файле registration.json.

// Program.cs

using System.Runtime.InteropServices;
using ComTypes = System.Runtime.InteropServices.ComTypes;
using Microsoft.Windows.Widgets;
using ExampleWidgetProvider;
using COM;
using System;


[DllImport("ole32.dll")]

static extern int CoRegisterClassObject(
            [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
            [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
            uint dwClsContext,
            uint flags,
            out uint lpdwRegister);

[DllImport("ole32.dll")] static extern int CoRevokeClassObject(uint dwRegister);

uint cookie;

Guid CLSID_Factory = Guid.Parse("00001111-aaaa-2222-bbbb-3333cccc4444");
CoRegisterClassObject(CLSID_Factory, new ActionProviderFactory<AppActionProvider>(), 0x4, 0x1, out cookie);

Application.Start((p) =>
{
    var context = new DispatcherQueueSynchronizationContext(
        DispatcherQueue.GetForCurrentThread());
    SynchronizationContext.SetSynchronizationContext(context);
    _ = new App();
});

PInvoke.CoRevokeClassObject(cookie);

return 0;

Проверка действия приложения Windows

Приложение "Тестовый игровой полигон для действий приложений" позволяет проверить регистрацию и функциональные возможности вашего приложения-поставщика действий для Windows. Для получения дополнительной информации об использовании этого инструмента см. App Actions Testing Playground.