注意
尚未正式發行的產品的相關資訊,可能會在產品正式發行前進行大幅修改。 Microsoft 對提供的資訊不做任何明示或暗示的保證。
本文將逐步引導您建立簡單的摘要提供者,其會註冊摘要內容 URI 並實作 IFeedProvider 介面。 Widgets Board 叫用這個介面的方法,用來要求自訂查詢字串參數,通常是為了支持驗證案例。 訂閱源提供者可以支援單一訂閱源或多個訂閱源。
若要使用 C++/WinRT 實行摘要提供者,請參閱在 C# Windows 應用程式 (C++/WinRT) 中實作摘要提供者。
必要條件
- 您的裝置必須啟用開發人員模式。 如需詳細資訊,請參閱 開發人員的設定。
- Visual Studio 2026 或更新版本,搭配 WinUI 應用程式開發 工作負載。 請務必從選擇性下拉式清單中新增 C++ 的元件 (v143)。
建立新的 C++/WinRT win32 主控台應用程式
在 Visual Studio 中,建立新專案。 在 [建立新專案] 對話方塊中,將語言篩選條件設定為「C++」,並將平台篩選條件設定為 Windows,然後選取 [Windows 主控台應用程式 (C++/WinRT)] 專案範本。 將新專案命名為「ExampleFeedProvider」。 針對此逐步解說,請確定「將方案和專案放置於同一個目錄」未被選擇。 出現提示時,將應用程式的目標 Windows 版本設定為 10.022631.2787 或更新版本。
新增 Windows 應用程式 SDK 和 Windows 實作程式庫 NuGet 套件的參考
此範例會使用最新的穩定 Windows 應用程式 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 指示詞正下方,再加入其他包含項目。
//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 類別以處理 Feed 作業
在 Visual Studio 的 [方案總管] 中,右鍵點選 ExampleFeedProvider 專案,然後選取 [新增類別]>。 在 [新增類別] 對話方塊中,命名類別為「FeedProvider」,並按一下 [新增]。
宣告實作 IFeedProvider 介面的類別
IFeedProvider 介面定義了 Widgets Board 將叫用的方法,以與摘要提供者進行作業的起始。 以下列程式碼取代 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 命名空間,並且允許存取我們在先前步驟中宣告的映射。
注意
傳遞到 IFeedProvider 介面的回呼方法中的物件,只能保證在回呼過程中有效。 您不應儲存這些物件的參考,因為它們在回呼函式之外的行為是未定的。
// WidgetProvider.cpp
namespace winrt
{
using namespace Microsoft::Windows::Widgets::Feeds::Providers;
}
OnFeedProviderEnabled
當 Widgets Board 主機建立與提供程式相關聯的摘要時,會叫用 OnFeedProviderEnabled 方法。 在此方法的實作中,生成包含參數的查詢字串,這些參數將傳遞至提供資料流內容的 URL,包括任何必要的認證令牌。 建立 CustomQueryParametersUpdateOptions 的執行個體,傳入事件引數中識別已啟用的供應項目和查詢字串所需的 FeedProviderDefinitionId。 取得預設的 FeedManager,並呼叫 SetCustomQueryParameters 向 Widgets Board 註冊查詢字串參數。
// 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¶m2");
winrt::FeedManager::GetDefault().SetCustomQueryParameters(updateOptions);
}
当Feed提供者被禁用
當 Widgets Board 上此提供程式的所有摘要都被停用時,會呼叫 `OnFeedProviderDisabled`。 Feed 提供者不需要執行動作,以回應此方法呼叫。 方法調用可用於遙測目的,或視需要更新查詢字串參數或撤銷驗證權杖。 如果應用程式只支援單一摘要提供者,或應用程式支援的所有摘要提供者已停用,則應用程式可以結束以回應此回撥。
// 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
Widgets Board 會在啟用或停用摘要時叫用 OnFeedEnabled 和 OnFeedDisabled。 摘要提供者不需要執行任何動作,以回應這些方法呼叫。 方法調用可用於遙測目的,或視需要更新查詢字串參數或撤銷驗證權杖。
// 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 是在 Widgets Board 判斷與資料供應者相關的自訂查詢參數需要重新整理時被引發的。 例如,如果從遠端網頁服務擷取摘要內容的作業失敗,可能會引發這個方法。 傳遞至此方法的 CustomQueryParametersRequestedArgs 之 FeedProviderDefinitionId 屬性會指定要請求查詢字串參數的摘要。 提供程式應該重新產生查詢字串,並藉由呼叫 SetCustomQueryParameters 將其傳遞回 Widgets Board。
// 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¶m2");
winrt::FeedManager::GetDefault().SetCustomQueryParameters(updateOptions);
}
註冊類別工廠,以便按需實例化 FeedProvider
將定義 FeedProvider類別的標頭新增至應用程式 main.cpp 檔案頂端的 include。 我們也將在這裡包括 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();
}
接下來,您必須建立 CLSID,用於識別您的信息提供者以進行 COM 啟動。 在 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 }
};
將以下 Class Factory 定義新增至 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;
}
封裝您的 Feed 提供者應用程式
在目前的版本中,只有已封裝的應用程式可以註冊為摘要提供者。 下列步驟會引導您完成封裝應用程式並更新應用程式資訊清單的流程,以向作業系統將應用程式註冊為摘要提供者。
建立 MSIX 封裝專案
在 [方案總管] 中,以滑鼠右鍵按一下方案並選取 [新增] > [新增專案...]。在 [新增專案] 對話方塊中,選取「Windows 應用程式封裝專案」範本,然後按一下 [下一步]。 將專案名稱設定為「ExampleFeedProviderPackage」,然後按一下 [建立]。 出現提示時,將目標版本設定為版本 1809 或更新版本,然後按一下 [確定]。 接下來,以滑鼠右鍵按一下 ExampleFeedProviderPackage 專案,然後選取 [新增] > [專案參考]。 選取 ExampleFeedProvider 專案,然後按一下 [確定]。
將 Windows 應用程式 SDK 套件參考新增到封裝專案
您必須將 Windows 應用程式 SDK nuget 套件的參考新增至 MSIX 封裝專案。 在 [方案總管] 中,按兩下 ExampleFeedProviderPackage 專案,以開啟 ExampleFeedProviderPackage.wapproj 檔案。 在專案元素中新增以下 xml。
<!--ExampleFeedProviderPackage.wapproj-->
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231116003-experimentalpr">
<IncludeAssets>build</IncludeAssets>
</PackageReference>
</ItemGroup>
注意
請確定 PackageReference 元素中指定的版本 符合您在上一個步驟中所參考的最新穩定版本。
如果電腦上已安裝正確的 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 延伸模組。 這會向作業系統註冊可執行檔的進入點。 此延伸模組是已封裝的應用程式,相當於藉由設定登錄機碼來註冊 COM 伺服器,而且不是摘要提供者特有的。將下列 com:Extension 元素新增為 Extensions 元素的子系。 將 Id 屬性中的 com:Class 元素的 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 所使用的。 這就是我們將儲存摘要圖示的位置。 當您新增所需的圖示之後,請確定影像名稱與 Path=ProviderAssets\ 之後在 Package.appxmanifest 中的名稱相符,否則信息源不會顯示在 Widget Board 中。
測試資料來源提供者
請確定您已從 [方案平台] 下拉式清單中選取符合您開發電腦的架構,例如「x64」。 在 [方案總管] 中,以右鍵按一下方案,然後選取 [建置解決方案]。 完成此動作後,以滑鼠右鍵按下您的 ExampleWidgetProviderPackage,然後選取 [部署]。 主控台應用程式應該會在部署時啟動,然後您將會在主控台輸出中看到資料流已啟用。 開啟Widgets Board後,您應該會在資訊區段上方的標籤中看到新的資訊來源。
對資料源提供者進行偵錯
釘選摘要之後,Widget 平台會啟動您的摘要提供者應用程式,以接收和傳送摘要的相關資訊。 若要偵錯執行中的摘要,您可以將偵錯工具附加至執行中的摘要提供者應用程式,或者您可以設定 Visual Studio 在啟動後自動開始偵錯摘要提供者流程。
若要附加至執行中的程序:
- 在 Visual Studio 按一下 偵錯 - > 附加至處理序。
- 過濾程序,並尋找您想要的信息源提供者應用程式。
- 連結偵錯工具。
若要在一開始啟動偵錯程式時自動將偵錯程式附加至流程:
- 在 Visual Studio 中,按一下 >[偵錯] > [其他偵錯目標] [偵錯已安裝的應用程式套件]。
- 篩選套件,並尋找所需的資料供應商套件。
- 選取它並勾選方塊,該方塊顯示 "不要啟動,但在啟動時偵錯我的程式碼。"
- 按一下 新增。
將主控台應用程式轉換為 Windows 應用程式
若要將本逐步解說中建立的主控台應用程式轉換為 Windows 應用程式:
- 在 [方案總管] 的 ExampleWidgetProvider 專案上按一下滑鼠右鍵,然後選取 [屬性]。 導覽至 連結器 - 系統>,並將 子系統 從「控制台」變更為「Windows」。 您也可以將 <SubSystem>Windows</SubSystem> 新增至 .vcxproj 的<Link>..</Link> 區段來完成此動作。
- 在 main.cpp 中,將
int main()變更為int WINAPI wWinMain(_In_ HINSTANCE /*hInstance*/, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ PWSTR pCmdLine, _In_ int /*nCmdShow*/)。
發布您的資訊流提供者應用程式
在開發並測試您的摘要提供者之後,您可以在 Microsoft Store 上發佈您的應用程式,使用者才能在其裝置上安裝您的摘要。 如需發佈應用程式的逐步指引,請參閱在 Microsoft Store 中發佈您的應用程式。
訂閱存放區集合
在 Microsoft 市集上發布您的應用程式之後,您可以要求您的應用程式包含在摘要市集集合中,以協助使用者探索具有 Windows 摘要的應用程式。 要提交您的供稿/看板以新增至 Store 集合,請參閱 提交您的供稿/看板以新增至 Store 集合。