使用 C++/WinRT 的 Windows 运行时组件Windows Runtime components with C++/WinRT

本主题演示如何使用 c + +/WinRT 创建和使用 Windows 运行时组件 — ,该组件可从使用任意 Windows 运行时语言构建的通用 Windows 应用程序调用。This topic shows how to use C++/WinRT to create and consume a Windows Runtime component—a component that's callable from a Universal Windows app built using any Windows Runtime language.

用 c + +/WinRT. 生成 Windows 运行时组件有多种原因。There are several reasons for building a Windows Runtime component in C++/WinRT.

  • 在复杂或计算密集型操作中享有 c + + 的性能优势。To enjoy the performance advantage of C++ in complex or computationally intensive operations.
  • 用于重用已编写和测试的标准 c + + 代码。To reuse standard C++ code that's already written and tested.
  • 若要向编写的通用 Windows 平台 (UWP) 应用公开 Win32 功能,例如 c #。To expose Win32 functionality to a Universal Windows Platform (UWP) app written in, for example, C#.

通常,在创作 c + +/WinRT 组件时,可以使用标准 c + + 库中的类型和内置类型,但在应用程序二进制接口 (ABI) 边界,在这种情况下,你要将数据传入和传入其他包中的代码 .winmdIn general, when you author your C++/WinRT component, you can use types from the standard C++ library, and built-in types, except at the application binary interface (ABI) boundary where you're passing data to and from code in another .winmd package. 在 ABI 上,使用 Windows 运行时类型。At the ABI, use Windows Runtime types. 此外,在 c + +/WinRT 代码中,使用委托和事件之类的类型来实现可从你的组件引发的事件,并使用另一种语言进行处理。In addition, in your C++/WinRT code, use types such as delegate and event to implement events that can be raised from your component and handled in another language. 有关 c + +/WinRT. 的详细信息,请参阅c + +/WinRTSee C++/WinRT for more info about C++/WinRT.

本主题的其余部分将介绍如何在 c + +/WinRT 中创作 Windows 运行时组件,然后从应用程序使用该组件。The remainder of this topic walks you through how to author a Windows Runtime component in C++/WinRT, and then how to consume it from an application.

本主题中将生成的 Windows 运行时组件包含表示温度计的运行时类。The Windows Runtime component that you'll build in this topic contains a runtime class representing a thermometer. 本主题还演示了一个使用温度计运行时类的核心应用程序,并调用了一个函数来调整温度。The topic also demonstrates a Core App that consumes the thermometer runtime class, and calls a function to adjust the temperature.

备注

有关安装和使用 C++/WinRT Visual Studio 扩展 (VSIX) 和 NuGet 包(两者共同提供项目模板,并生成支持)的信息,请参阅适用于 C++/WinRT 的 Visual Studio 支持For info about installing and using the C++/WinRT Visual Studio Extension (VSIX) and the NuGet package (which together provide project template and build support), see Visual Studio support for C++/WinRT.

重要

有关支持你了解如何利用 C++/WinRT 来使用和创作运行时类的基本概述和术语,请参阅通过 C++/WinRT 使用 API通过 C++/WinRT 创作 APIFor essential concepts and terms that support your understanding of how to consume and author runtime classes with C++/WinRT, see Consume APIs with C++/WinRT and Author APIs with C++/WinRT.

创建 Windows 运行时组件 (ThermometerWRC) Create a Windows Runtime component (ThermometerWRC)

首先在 Microsoft Visual Studio 中创建新项目。Begin by creating a new project in Microsoft Visual Studio. ** (c + +/WinRT) *项目中创建 Windows 运行时组件,并将其命名为 "温度计 Windows 运行时组件" ) 的ThermometerWRC* (。Create a Windows Runtime Component (C++/WinRT) project, and name it ThermometerWRC (for "thermometer Windows Runtime component"). 请确保未选中“将解决方案和项目放在同一目录中”。Make sure that Place solution and project in the same directory is unchecked. 面向 Windows SDK 的最新正式发布(非预览)版本。Target the latest generally-available (that is, not preview) version of the Windows SDK. 将项目命名为 ThermometerWRC 将为你提供本主题中其他步骤的最简单体验。Naming the project ThermometerWRC will give you the easiest experience with the rest of the steps in this topic.

暂时不要生成该项目。Don't build the project yet.

该新建项目包含一个名为 Class.idl 的文件。The newly-created project contains a file named Class.idl. 在解决方案资源管理器中,将该文件重命名为 Thermometer.idl(重命名 .idl 文件还会自动重命名从属的 .h.cpp 文件)。In Solution Explorer, rename that file Thermometer.idl (renaming the .idl file automatically renames the dependent .h and .cpp files, too). Thermometer.idl 中的内容替换为下表。Replace the contents of Thermometer.idl with the listing below.

// Thermometer.idl
namespace ThermometerWRC
{
    runtimeclass Thermometer
    {
        Thermometer();
        void AdjustTemperature(Single deltaFahrenheit);
    };
}

保存该文件。Save the file. 此时,该项目不会生成到完成,但现在生成是一项有用的操作,因为它会生成要在其中实现 温度计 运行时类的源代码文件。The project won't build to completion at the moment, but building now is a useful thing to do because it generates the source code files in which you'll implement the Thermometer runtime class. 因此,继续生成(此阶段可能发生的生成错误与找不到 Class.hClass.g.h 有关)。So go ahead and build now (the build errors you can expect to see at this stage have to do with Class.h and Class.g.h not being found).

在生成过程中,midl.exe 工具会运行以创建组件的 Windows 运行时元数据文件(即 \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd)。During the build process, the midl.exe tool is run to create your component's Windows Runtime metadata file (which is \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd). 然后,cppwinrt.exe 工具运行(具有 -component 选项)以生成源代码文件,从而为你在创作组件时提供支持。Then, the cppwinrt.exe tool is run (with the -component option) to generate source code files to support you in authoring your component. 这些文件包括存根,可让你开始实现在 IDL 中声明的 温度计 运行时类。These files include stubs to get you started implementing the Thermometer runtime class that you declared in your IDL. 这些存根是 \ThermometerWRC\ThermometerWRC\Generated Files\sources\Thermometer.hThermometer.cppThose stubs are \ThermometerWRC\ThermometerWRC\Generated Files\sources\Thermometer.h and Thermometer.cpp.

右键单击项目节点,然后单击“打开文件资源管理器中的文件夹”。Right-click the project node and click Open Folder in File Explorer. 执行此操作,将在文件资源管理器中打开项目文件夹。This opens the project folder in File Explorer. 将存根文件 Thermometer.hThermometer.cpp 从文件夹 \ThermometerWRC\ThermometerWRC\Generated Files\sources\ 复制到包含项目文件的文件夹(即 \ThermometerWRC\ThermometerWRC\),并替换目标中的文件。There, copy the stub files Thermometer.h and Thermometer.cpp from the folder \ThermometerWRC\ThermometerWRC\Generated Files\sources\ and into the folder that contains your project files, which is \ThermometerWRC\ThermometerWRC\, and replace the files in the destination. 现在,让我们打开 Thermometer.hThermometer.cpp 并实现运行时类。Now, let's open Thermometer.h and Thermometer.cpp and implement our runtime class. 在中 Thermometer.h ,将新的私有成员添加到实现, (温度计的工厂实现) 。In Thermometer.h, add a new private member to the implementation (not the factory implementation) of Thermometer.

// Thermometer.h
...
namespace winrt::ThermometerWRC::implementation
{
    struct Thermometer : ThermometerT<Thermometer>
    {
        ...

    private:
        float m_temperatureFahrenheit { 0.f };
    };
}
...

在中 Thermometer.cpp ,实现 AdjustTemperature 方法,如下列表所示。In Thermometer.cpp, implement the AdjustTemperature method as shown in the listing below.

// Thermometer.cpp
...
namespace winrt::ThermometerWRC::implementation
{
    void Thermometer::AdjustTemperature(float deltaFahrenheit)
    {
        m_temperatureFahrenheit += deltaFahrenheit;
    }
}

还需要删除这两个文件中的 static_assertYou'll also need to delete the static_assert from both files.

如果任何警告阻止你进行生成,请处理这些警告或将项目属性“C/C++” > “常规” > “将警告视为错误”设置为“否(/WX-)”,然后重新生成该项目 。If any warnings prevent you from building, then either resolve them or set the project property C/C++ > General > Treat Warnings As Errors to No (/WX-), and build the project again.

创建核心应用 (ThermometerCoreApp) 测试 Windows 运行时组件Create a Core App (ThermometerCoreApp) to test the Windows Runtime component

现在 (在 ThermometerWRC 解决方案中创建新项目,或在新项目) 中创建。Now create a new project (either in your ThermometerWRC solution, or in a new one). ** (c + +/WinRT) *项目中创建一个核心应用,并将其命名为ThermometerCoreApp*。Create a Core App (C++/WinRT) project, and name it ThermometerCoreApp. 如果这两个项目处于同一个解决方案中,则将 ThermometerCoreApp 设置为启动项目。Set ThermometerCoreApp as the startup project if the two projects are in the same solution.

备注

如前文所述,在文件夹中创建了你 Windows 运行时组件的 Windows 运行时元数据文件, (其项目命名为 ThermometerWRC) \ThermometerWRC\Debug\ThermometerWRC\As mentioned earlier, the Windows Runtime metadata file for your Windows Runtime component (whose project you named ThermometerWRC) is created in the folder \ThermometerWRC\Debug\ThermometerWRC\. 该路径的第一段是包含解决方案文件的文件夹的名称;下一段是名为 Debug 的子目录;最后一段是为 Windows 运行时组件命名的子目录。The first segment of that path is the name of the folder that contains your solution file; the next segment is the subdirectory of that named Debug; and the last segment is the subdirectory of that named for your Windows Runtime component. 如果你未将项目命名为 ThermometerWRC,则元数据文件将位于文件夹中 \<YourProjectName>\Debug\<YourProjectName>\If you didn't name your project ThermometerWRC, then your metadata file will be in the folder \<YourProjectName>\Debug\<YourProjectName>\.

现在,在核心应用程序项目中 (ThermometerCoreApp) ,添加引用,并浏览到 \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd (或添加项目到项目的引用(如果两个项目位于同一解决方案) 中)。Now, in your Core App project (ThermometerCoreApp), add a reference, and browse to \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd (or add a project-to-project reference, if the two projects are in the same solution). 单击“添加”,然后单击“确定” 。Click Add, and then OK. 现在生成 ThermometerCoreAppNow build ThermometerCoreApp. 在极少数情况下,你看到了负载文件 readme.txt 不存在的错误,请从 Windows 运行时组件项目中排除该文件,重新生成该文件,然后重新生成 ThermometerCoreAppIn the unlikely event that you see an error that the payload file readme.txt doesn't exist, exclude that file from the Windows Runtime component project, rebuild it, then rebuild ThermometerCoreApp.

生成过程期间,cppwinrt.exe 工具会运行以将引用的 .winmd 文件处理到包含投影类型的源代码文件中,从而为你在使用组件时提供支持。During the build process, the cppwinrt.exe tool is run to process the referenced .winmd file into source code files containing projected types to support you in consuming your component. 组件的运行时类的投影类型的标头—名为 ThermometerWRC.h—将生成在文件夹 \ThermometerCoreApp\ThermometerCoreApp\Generated Files\winrt\ 中。The header for the projected types for your component's runtime classes—named ThermometerWRC.h—is generated into the folder \ThermometerCoreApp\ThermometerCoreApp\Generated Files\winrt\.

App.cpp 中包含该标头。Include that header in App.cpp.

// App.cpp
...
#include <winrt/ThermometerWRC.h>
...

此外,在中 App.cpp ,添加以下代码以实例化 温度计 对象 (使用投影类型的默认构造函数) ,并对温度计对象调用方法。Also in App.cpp, add the following code to instantiate a Thermometer object (using the projected type's default constructor), and call a method on the thermometer object.

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    ThermometerWRC::Thermometer m_thermometer;
    ...
    
    void OnPointerPressed(IInspectable const &, PointerEventArgs const & args)
    {
        m_thermometer.AdjustTemperature(1.f);
        ...
    }
    ...
};

每次单击窗口时,会增加温度计对象的温度。Each time you click the window, you increment the thermometer object's temperature. 如果要单步执行代码以确认应用程序确实正在调用 Windows 运行时组件,则可以设置断点。You can set breakpoints if you want to step through the code to confirm that the application really is calling into the Windows Runtime component.

后续步骤Next steps

若要将更多功能或新 Windows 运行时类型添加到 c + +/WinRT Windows 运行时组件,可以遵循上面所示的相同模式。To add even more functionality, or new Windows Runtime types, to your C++/WinRT Windows Runtime component, you can follow the same patterns shown above. 首先,使用 IDL 定义要公开的功能。First, use IDL to define the functionality you want to expose. 然后在 Visual Studio 中生成项目以生成存根实现。Then build the project in Visual Studio to generate a stub implementation. 然后,根据需要完成实现。And then complete the implementation as appropriate. IDL 中定义的任何方法、属性和事件都对使用 Windows 运行时组件的应用程序可见。Any methods, properties, and events that you define in IDL are visible to the application that consumes your Windows Runtime Component. 有关 IDL 的详细信息,请参阅 Microsoft 接口定义语言3.0 的简介For more info about IDL, see Introduction to Microsoft Interface Definition Language 3.0.

有关如何向 Windows 运行时组件添加事件的示例,请参阅 在 c + + 中创作事件/WinRTFor an example of how to add an event to your Windows Runtime Component, see Author events in C++/WinRT.

疑难解答Troubleshooting

症状Symptom 纠正方法Remedy
在 C++/WinRT 应用中,当使用利用 XAML 的 C# Windows 运行时组件时,编译器会生成一个错误,格式为:"'MyNamespace_XamlTypeInfo': 不是 'winrt::MyNamespace' 的成员"—其中 MyNamespace 是 Windows 运行时组件命名空间的名称。In a C++/WinRT app, when consuming a C# Windows Runtime component that uses XAML, the compiler produces an error of the form "'MyNamespace_XamlTypeInfo': is not a member of 'winrt::MyNamespace'"—where MyNamespace is the name of the Windows Runtime component's namespace. 在 C++/WinRT 应用中的 pch.h 中,根据需要添加 #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h>— 来替换 MyNamespace。In pch.h in the consuming C++/WinRT app, add #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h>—replacing MyNamespace as appropriate.