次の方法で共有


win32 アプリでフィード プロバイダーを実装する (C++/WinRT)

Note

一部の情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

この記事では、フィード コンテンツ URI を登録し、IFeedProvider インターフェイスを実装する単純なフィード プロバイダーを作成する手順について説明します。 このインターフェイスのメソッドは、カスタム クエリ文字列パラメーターを要求するために ウィジェット ボード によって呼び出されます。通常は認証シナリオをサポートするためのものです。 フィード プロバイダーは、1 つのフィードまたは複数のフィードをサポートできます。

C++/WinRT を使ってフィード プロバイダーを実装するには、「C# Windows アプリでフィード プロバイダーを実装する (C++/WinRT)」をご覧ください。

前提条件

  • デバイスで開発者モードが有効になっている必要があります。 詳しくは、「デバイスを開発用に有効にする」をご覧ください。
  • ユニバーサル Windows プラットフォーム開発ワークロードを含む Visual Studio 2022 以降。 オプションのドロップダウンから C++ (v143) 用のコンポーネントを追加してください。

新しい C++/WinRT win32 コンソール アプリを作成する

Visual Studio で、新しいプロジェクトを作成します。 [新しいプロジェクトの作成] ダイアログで、言語フィルターを "C++" に設定し、プラットフォーム フィルターを Windows に設定してから、Windows コンソール アプリケーション (C++/WinRT) プロジェクト テンプレートを選びます。 新しいプロジェクトに "ExampleFeedProvider" という名前を付けます。 このチュートリアルでは、[ソリューションとプロジェクトを同じディレクトリに配置する] がオフになっていることを確認します。 メッセージが表示されたら、アプリのターゲット Windows バージョンをバージョン 10.022631.2787 以降に設定します。

Windows App SDK と Windows 実装ライブラリの NuGet パッケージへの参照を追加する

このサンプルでは、最新の安定した Windows App SDK NuGet パッケージを使います。 ソリューション エクスプローラー[参照] を右クリックして、[NuGet パッケージの管理...] を選びます。NuGet パッケージ マネージャーで [参照] タブを選んで、"Microsoft.WindowsAppSDK" を検索します。 [バージョン] ドロップダウンで最新の安定バージョンを選んで、[インストール] をクリックします。

このサンプルでは、Windows 実装ライブラリ NuGet パッケージも使います。 ソリューション エクスプローラー[参照] を右クリックして、[NuGet パッケージの管理...] を選びます。NuGet パッケージ マネージャーで [参照] タブを選んで、"Microsoft.Windows.ImplementationLibrary" を検索します。 [バージョン] ドロップダウンで最新のバージョンを選んで、[インストール] をクリックします。

プリコンパイル済みヘッダー ファイル pch.h に、次の include ディレクティブを追加します。

//pch.h 
#pragma once
#include <wil/cppwinrt.h>
#include <wil/resource.h>
...
#include <winrt/Microsoft.Windows.Widgets.Providers.h>

注意

最初に wil/cppwinrt.h ヘッダー、その後で WinRT のヘッダーをインクルードする必要があります。

フィード プロバイダー アプリのシャットダウンを正しく処理するには、winrt::get_module_lock のカスタム実装が必要です。 SignalLocalServerShutdown メソッドを事前に宣言し、それを main.cpp ファイルで定義して、アプリに終了を通知するイベントを設定します。 pch.h ファイルの #pragma once ディレクティブのすぐ後、他の include の前に、次のコードを追加します。

//pch.h
#include <stdint.h>
#include <combaseapi.h>

// In .exe local servers the class object must not contribute to the module ref count, and use
// winrt::no_module_lock, the other objects must and this is the hook into the C++ WinRT ref counting system
// that enables this.
void SignalLocalServerShutdown();

namespace winrt
{
    inline auto get_module_lock() noexcept
    {
        struct service_lock
        {
            uint32_t operator++() noexcept
            {
                return ::CoAddRefServerProcess();
            }

            uint32_t operator--() noexcept
            {
                const auto ref = ::CoReleaseServerProcess();

                if (ref == 0)
                {
                    SignalLocalServerShutdown();
                }
                return ref;
            }
        };

        return service_lock{};
    }
}


#define WINRT_CUSTOM_MODULE_LOCK

フィード操作を処理する FeedProvider クラスを追加する

Visual Studio のソリューション エクスプローラーExampleFeedProvider プロジェクトを右クリックして、[追加] > [クラス] を選びます。 [クラスの追加] ダイアログで、クラスに "FeedProvider" という名前を付けて、[追加] をクリックします。

IFeedProvider インターフェイスを実装するクラスを宣言する

IFeedProvider インターフェイスでは、ウィジェット ボードがフィード プロバイダーでの操作を開始するために呼び出すメソッドが定義されています。 FeedProvider.h ファイルの空のクラス定義を次のコードに置き換えます。 このコードでは、IFeedProvider インターフェイスを実装する構造と、インターフェイス メソッドのプロトタイプを宣言しています。

// FeedProvider.h
#pragma once
struct FeedProvider : winrt::implements<FeedProvider, winrt::Microsoft::Windows::Widgets::Feeds::Providers::IFeedProvider>
{
    FeedProvider() {}

    /* IFeedrovider required functions that need to be implemented */
    void OnFeedProviderEnabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedProviderEnabledArgs args);
    void OnFeedProviderDisabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedProviderDisabledArgs args);
    void OnFeedEnabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedEnabledArgs args);
    void OnFeedDisabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedDisabledArgs args);
    void OnCustomQueryParametersRequested(winrt::Microsoft::Windows::Widgets::Feeds::Providers::CustomQueryParametersRequestedArgs args);
    /* IFeedProvider required functions that need to be implemented */

};

IFeedProvider メソッドを実装する

次の数セクションでは、IFeedProvider インターフェイスのメソッドを実装します。 インターフェイスのメソッドに移る前に、FeedProvider.cpp の include ディレクティブの後に次の行を追加します。これらの行では、フィード プロバイダーの API を winrt 名前空間にプルし、前のステップで宣言したマップへのアクセスを許可しています。

Note

IFeedProvider インターフェイスのコールバック メソッドにパスされるオブジェクトは、コールバック内でのみ有効であることが保証されます。 コールバックのコンテキストの外部での動作は定義されていないため、これらのオブジェクトへの参照は保存しないでください。

// WidgetProvider.cpp
namespace winrt
{
    using namespace Microsoft::Windows::Widgets::Feeds::Providers;
}

OnFeedProviderEnabled

プロバイダーに関連付けられているフィードが ウィジェット ボード ホストによって作成されると、OnFeedProviderEnabled メソッドが呼び出されます。 このメソッドの実装では、必要な認証トークンを含むフィード コンテンツを提供する URL にパスされるパラメーターを含むクエリ文字列を生成します。 CustomQueryParametersUpdateOptions のインスタンスを作成し、有効になっているフィードとクエリ文字列を識別するイベント引数から FeedProviderDefinitionId をパスします。 既定の FeedManager を取得し、SetCustomQueryParameters を呼び出して、クエリ文字列パラメーターを ウィジェット ボード に登録します。

// FeedProvider.cs
void FeedProvider::OnFeedProviderEnabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedProviderEnabledArgs args)
{
    std::wstringstream wstringstream;
wstringstream << args.FeedProviderDefinitionId().c_str() << L" feed provider was enabled." << std::endl;
    _putws(wstringstream.str().c_str());

    auto updateOptions = winrt::CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId(), L"param1&param2");
    winrt::FeedManager::GetDefault().SetCustomQueryParameters(updateOptions);
}

OnFeedProviderDisabled

OnFeedProviderDisabled は、このプロバイダーのすべてのフィードが無効になっている場合にウィジェット ボードが呼び出されます。 フィード プロバイダーは、これらのメソッド呼び出しに応答してアクションを実行する必要はありません。 メソッドの起動は、利用統計情報の目的で使用したり、必要に応じてクエリ文字列パラメーターを更新したり、認証トークンを取り消したりするために使用できます。 アプリが単一のフィード プロバイダーのみをサポートしている場合、またはアプリでサポートされているすべてのフィード プロバイダーが無効になっている場合は、このコールバックに応答してアプリを終了できます。

// FeedProvider.cs

void FeedProvider::OnFeedProviderDisabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedProviderDisabledArgs args)
{
    std::wstringstream wstringstream;
    wstringstream << args.FeedProviderDefinitionId().c_str() << L" feed provider was disabled." << std::endl;
    _putws(wstringstream.str().c_str());
}

OnFeedEnabled、OnFeedDisabled

フィードが有効または無効になると、OnFeedEnabledOnFeedDisabled がウィジェット ボードによって呼び出されます。 フィードプロバイダは、これらのメソッド呼び出しに応答して何らかのアクションを実行する必要はありません。 メソッドの起動は、利用統計情報の目的で使用したり、必要に応じてクエリ文字列パラメーターを更新したり、認証トークンを取り消したりするために使用できます。

// FeedProvider.cs

void FeedProvider::OnFeedEnabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedEnabledArgs args)
{
    std::wstringstream wstringstream;
    wstringstream << args.FeedDefinitionId().c_str() << L" feed was enabled." << std::endl;
    _putws(wstringstream.str().c_str());
}
// FeedProvider.cs

void FeedProvider::OnFeedDisabled(winrt::Microsoft::Windows::Widgets::Feeds::Providers::FeedDisabledArgs args)
{
    std::wstringstream wstringstream;
    wstringstream << args.FeedDefinitionId().c_str() << L" feed was disabled." << std::endl;
    _putws(wstringstream.str().c_str());
}

OnCustomQueryParametersRequested

OnCustomQueryParametersRequested は、フィード プロバイダーに 関連付けられているカスタム クエリ パラメーターを更新する必要があるとウィジェット ボードが判断したときに発生します。 たとえば、リモート Web サービスからフィード コンテンツをフェッチする操作が失敗した場合に、このメソッドが発生する可能性があります。 このメソッドに渡される CustomQueryParametersRequestedArgsFeedProviderDefinitionId プロパティは、クエリ文字列パラメーターが要求されるフィードを指定します。 プロバイダーは、クエリ文字列を再生成し、SetCustomQueryParameters を呼び出してウィジェット ボードにパスする必要があります。

// FeedProvider.cs

void FeedProvider::OnCustomQueryParametersRequested(winrt::Microsoft::Windows::Widgets::Feeds::Providers::CustomQueryParametersRequestedArgs args)
{
    std::wstringstream wstringstream;
    wstringstream << L"CustomQueryParameters were requested for " << args.FeedProviderDefinitionId().c_str() << std::endl;
    _putws(wstringstream.str().c_str());

    auto updateOptions = winrt::CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId(), L"param1&param2");
    winrt::FeedManager::GetDefault().SetCustomQueryParameters(updateOptions);
}

要求に応じて FeedProvider をインスタンス化するクラス ファクトリを登録する

アプリの main.cpp ファイルの先頭にある include に、FeedProvider クラスを定義するヘッダーを追加します。 ここで mutex もインクルードします。

// main.cpp
...
#include "FeedProvider.h"
#include <mutex>

アプリの終了をトリガーするイベントと、イベントを設定する SignalLocalServerShutdown 関数を宣言します。 main.cpp に次のコードを貼り付けます。

// main.cpp
wil::unique_event g_shudownEvent(wil::EventOptions::None);

void SignalLocalServerShutdown()
{
    g_shudownEvent.SetEvent();
}

次に、COM のアクティブ化でフィード プロバイダーを識別するために使われる CLSID を作成する必要があります。 Visual Studio で [ツール] > [GUID の作成] に移動して、GUID を生成します。 オプション "static const GUID =" を選んで [コピー] をクリックし、それを main.cpp に貼り付けます。 次の C++/WinRT 構文を使って GUID の定義を更新し、GUID の変数名を feed_provider_clsid に設定します。 コメントになっている GUID のバージョンは、後でアプリをパッケージ化するときにこの形式が必要になるため、そのままにします。

// main.cpp
...
// {80F4CB41-5758-4493-9180-4FB8D480E3F5}
static constexpr GUID feed_provider_clsid
{
    0x80f4cb41, 0x5758, 0x4493, { 0x91, 0x80, 0x4f, 0xb8, 0xd4, 0x80, 0xe3, 0xf5 }
};

次のクラス ファクトリの定義を main.cpp に追加します。 これは主に、フィード プロバイダーの実装に固有ではない定型コードです。 アプリが終了する前、CoWaitForMultipleObjects はシャットダウン イベントがトリガーされるのを待機することに注意してください。

// main.cpp
template <typename T>
struct SingletonClassFactory : winrt::implements<SingletonClassFactory<T>, IClassFactory>
{
    STDMETHODIMP CreateInstance(
        ::IUnknown* outer,
        GUID const& iid,
        void** result) noexcept final
    {
        *result = nullptr;

        std::unique_lock lock(mutex);

        if (outer)
        {
            return CLASS_E_NOAGGREGATION;
        }

        if (!instance)
        {
            instance = winrt::make<FeedProvider>();
        }

        return instance.as(iid, result);
    }

    STDMETHODIMP LockServer(BOOL) noexcept final
    {
        return S_OK;
    }

private:
    T instance{ nullptr };
    std::mutex mutex;
};

int main()
{
    winrt::init_apartment();
    wil::unique_com_class_object_cookie feedProviderFactory;
    auto factory = winrt::make<SingletonClassFactory<winrt::Microsoft::Windows::Widgets::Feeds::Providers::IFeedProvider>>();

    winrt::check_hresult(CoRegisterClassObject(
        feed_provider_clsid,
        factory.get(),
        CLSCTX_LOCAL_SERVER,
        REGCLS_MULTIPLEUSE,
        feedProviderFactory.put()));

    DWORD index{};
    HANDLE events[] = { g_shudownEvent.get() };
    winrt::check_hresult(CoWaitForMultipleObjects(CWMO_DISPATCH_CALLS | CWMO_DISPATCH_WINDOW_MESSAGES,
        INFINITE,
        static_cast<ULONG>(std::size(events)), events, &index));

    return 0;
}

フィード プロバイダー アプリをパッケージ化する

現在のリリースでは、フィード プロバイダーとして登録できるのはパッケージ化されたアプリのみです。 次の手順では、アプリをフィード プロバイダーとして OS に登録するために、アプリをパッケージ化してアプリ マニフェストを更新するプロセスについて説明します。

MSIX パッケージ プロジェクトを作成する

ソリューション エクスプローラーでソリューションを右クリックして、[追加] > [新しいプロジェクト...] を選びます。[新しいプロジェクトの追加] ダイアログで "Windows アプリケーション パッケージ プロジェクト" テンプレートを選んで、[次へ] をクリックします。 プロジェクト名を "ExampleFeedProviderPackage" に設定して、[作成] をクリックします。 求められたらターゲット バージョンをバージョン 1809 以降に設定し、[OK] をクリックします。 次に、ExampleFeedProviderPackage プロジェクトを右クリックして、[追加] -> [プロジェクト参照] を選びます。 ExampleFeedProvider プロジェクトを選んで、[OK] をクリックします。

Windows App SDK のパッケージ参照をパッケージ プロジェクトに追加する

Windows App SDK Nuget パッケージへの参照を、MSIX パッケージ プロジェクトに追加する必要があります。 ソリューション エクスプローラーで ExampleFeedProviderPackage プロジェクトをダブルクリックして、ExampleFeedProviderPackage.wapproj ファイルを開きます。 Project 要素内に次の XML を追加します。

<!--ExampleFeedProviderPackage.wapproj-->
<ItemGroup>
    <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231116003-experimentalpr">
        <IncludeAssets>build</IncludeAssets>
    </PackageReference>  
</ItemGroup>

注意

PackageReference 要素で指定されている Version が、前のステップで参照した最新の安定バージョンと一致していることを確認します。

正しいバージョンの Windows アプリ SDK が既にコンピューターにインストールされていて、SDK のランタイムをパッケージにバンドルしたくない場合は、ExampleFeedProviderPackage プロジェクトの Package.appxmanifest ファイルでパッケージの依存関係を指定できます。

<!--Package.appxmanifest-->
...
<Dependencies>
...
    <PackageDependency Name="Microsoft.WindowsAppRuntime.1.5.233430000-experimental1" MinVersion="2000.638.7.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
...
</Dependencies>
...

パッケージ マニフェストを更新する

ソリューション エクスプローラーPackage.appxmanifest ファイルを右クリックし、[コードの表示] を選んでマニフェストの xml ファイルを開きます。 次に、使用するアプリ パッケージ拡張機能用の名前空間の宣言をいくつか追加する必要があります。 最上位の Package 要素に次の名前空間定義を追加します。

<!-- Package.appmanifest -->
<Package
  ...
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"

Application 要素内に、Extensions という名前の新しい空の要素を作成します。 これは、uap:VisualElements の終了タグの後に必ず追加します。

<!-- Package.appxmanifest -->
<Application>
...
    <Extensions>

    </Extensions>
</Application>

追加する必要がある最初の拡張機能は、ComServer 拡張機能です。 これにより、実行可能ファイルのエントリ ポイントが OS に登録されます。 この拡張機能は、レジストリ キーを設定することで COM サーバーを登録するのと同等のパッケージ アプリの機能であり、フィード プロバイダーに固有のものではありません。次の com:Extension 要素を、Extensions 要素の子として追加します。 com:Class 要素の Id 属性の GUID を、前のステップで生成した GUID に変更します。

<!-- Package.appxmanifest -->
<Extensions>
    <com:Extension Category="windows.comServer">
        <com:ComServer>
            <com:ExeServer Executable="ExampleFeedProvider\ExampleFeedProvider.exe" Arguments="-RegisterProcessAsComServer" DisplayName="C++ Feed Provider App">
                <com:Class Id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" DisplayName="FeedProvider" />
            </com:ExeServer>
        </com:ComServer>
    </com:Extension>
</Extensions>

次に、アプリをフィード プロバイダーとして登録する拡張機能を追加します。 次のコード スニペットの uap3:Extension 要素を、Extensions 要素の子として貼り付けます。 必ず、COM 要素の ClassId 属性を、前の手順で使った GUID に置き換えてください。

<!-- Package.appxmanifest -->
<Extensions>
    ...
    <uap3:Extension Category="windows.appExtension">
        <uap3:AppExtension Name="com.microsoft.windows.widgets.feeds" DisplayName="ContosoFeed" Id="com.examplewidgets.examplefeed" PublicFolder="Public">
            <uap3:Properties>
                <FeedProvider Icon="ms-appx:Assets\StoreLogo.png" Description="FeedDescription">
                    <Activation>
                        <!-- Apps exports COM interface which implements IFeedProvider -->
                        <CreateInstance ClassId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
                    </Activation>
                    <Definitions>
                        <Definition Id="Contoso_Feed"
                            DisplayName="Contoso_Feed Feed"
                            Description="Feed representing Contoso"
                            ContentUri="https://www.contoso.com/"
                            Icon="ms-appx:Images\StoreLogo.png">
                        </Definition>
                        <Definition Id="Fabrikam_Feed"
                            DisplayName="Fabrikam Feed"
                            Description="Feed representing Example"
                            ContentUri="https://www.fabrikam.com/"
                            Icon="ms-appx:Images\StoreLogo.png">
                        </Definition>
                    </Definitions>
                </FeedProvider>
            </uap3:Properties>
        </uap3:AppExtension>
    </uap3:Extension>
</Extensions>

これらの要素の詳細な説明と形式の情報については、「フィード プロバイダー パッケージ マニフェストの XML 形式」をご覧ください。

アイコンをパッケージ プロジェクトに追加する

ソリューション エクスプローラーExampleFeedProviderPackage を右クリックして、[追加] -> [新しいフォルダー] を選びます。 このフォルダーに ProviderAssets という名前を付けます。これは、前のステップの Package.appxmanifest で使ったものです。 ここでは、フィードのアイコンを格納します。 必要なアイコンを追加したら、画像の名前が Package.appxmanifestPath=ProviderAssets\ の後に続く部分と一致することを確認します。そうでないと、フィードはウィジェット ボードに表示されません。

フィード プロバイダーのテスト

[ソリューション プラットフォーム] ドロップダウンで選んだアーキテクチャが、開発用コンピューターと一致していることを確認します (例: "x64")。 ソリューション エクスプローラーでソリューションを右クリックして、[ソリューションのビルド] を選びます。 これが済んだら、ExampleWidgetProviderPackage を右クリックして [配置] を選びます。 デプロイ時にコンソール アプリが起動し、コンソール出力でフィードが有効になっていることがわかります。 ウィジェットボードを開くと、フィードセクションの上部にあるタブに新しいフィードが表示されます。

フィード プロバイダーのデバッグ

フィードをピン留めすると、フィードに関する関連情報を受信および送信するために、ウィジェット プラットフォームによってフィード プロバイダー アプリケーションが起動されます。 実行中のフィードをデバッグするには、実行中のフィード プロバイダー アプリケーションにデバッガーをアタッチするか、フィード プロバイダー プロセスの起動後にそのデバッグを自動的に開始するよう Visual Studio を設定することができます。

実行中のプロセスにアタッチするには:

  1. Visual Studio で、[デバッグ] > [プロセスにアタッチ] をクリックします。
  2. プロセスをフィルター処理し、目的のフィード プロバイダー アプリケーションを見つけます。
  3. デバッガーをアタッチします。

プロセスが最初に開始されるときにデバッガーを自動的にアタッチするには:

  1. Visual Studio で、[デバッグ] > [その他のデバッグ ターゲット] > [インストールされているアプリ パッケージのデバッグ] の順にクリックします。
  2. パッケージをフィルター処理し、目的のフィード プロバイダー パッケージを見つけます。
  3. それを選び、[起動はしないが、開始時にコードをデバッグする] チェック ボックスをオンにします。
  4. [アタッチ] をクリックします。

コンソール アプリを Windows アプリに変換する

このチュートリアルで作成したコンソール アプリを Windows アプリに変換するには:

  1. ソリューション エクスプローラーで ExampleWidgetProvider プロジェクトを右クリックして、[プロパティ] を選びます。 [リンカー] > [システム] に移動し、[サブシステム] を [コンソール] から [Windows] に変更します。 これは、<SubSystem>Windows</SubSystem> を .vcxproj の <Link>..</Link> セクションに追加することで行うこともできます。
  2. main.cpp で、int main()int WINAPI wWinMain(_In_ HINSTANCE /*hInstance*/, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ PWSTR pCmdLine, _In_ int /*nCmdShow*/) に変更します。

出力の種類が Windows アプリケーションに設定されている、C++ フィード プロバイダー プロジェクトのプロパティを示すスクリーンショット

フィード プロバイダー アプリの公開

フィード プロバイダーを開発してテストした後は、ユーザーがフィードをデバイスにインストールできるように、Microsoft Store でアプリを発行する必要があります。 アプリを発行するための詳細なガイダンスについては、「Microsoft Store でアプリを発行する」をご覧ください。

フィード ストア コレクション

Microsoft Store でアプリが公開されたら、アプリをフィード ストア コレクションに含め、ユーザーが Windows フィードを備えるアプリを検出できるように要求できます。 要求を送信するには、「 フィード/ボードを送信してストア コレクションに追加する」を参照してください