使用 C++/CX 创建 Windows 运行时组件Windows Runtime components with C++/CX

备注

本主题旨在帮助你维护 C++/CX 应用程序。This topic exists to help you maintain your C++/CX application. 不过,我们建议你使用 C++/WinRT 编写新应用程序。But we recommend that you use C++/WinRT for new applications. C++/WinRT 是 Windows 运行时 (WinRT) API 的完全标准新式 C++17 语言投影,以基于标头文件的库的形式实现,旨在为你提供对新式 Windows API 的一流访问。C++/WinRT is an entirely standard modern C++17 language projection for Windows Runtime (WinRT) APIs, implemented as a header-file-based library, and designed to provide you with first-class access to the modern Windows API. 若要了解如何使用 C++/WinRT 创建 Windows 运行时组件,请参阅使用 C++/WinRT 创建 Windows 运行时组件To learn how to create a Windows Runtime component using C++/WinRT, see Windows Runtime components with C++/WinRT.

本主题演示如何使用 c + +/CX 创建 Windows 运行时组件 — ,该组件可从使用任意 Windows 运行时 (语言(c #、Visual Basic、c + + 或 Javascript) )生成的通用 Windows 应用程序中调用。This topic shows how to use C++/CX to create a Windows Runtime component—a component that's callable from a Universal Windows app built using any Windows Runtime language (C#, Visual Basic, C++, or Javascript).

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

  • 在复杂或计算密集型操作中获取 C++ 的性能优势。To get the performance advantage of C++ in complex or computationally intensive operations.
  • 重复使用已编写和测试的代码。To reuse code that's already written and tested.

在生成包含 JavaScript 或 .NET 项目的解决方案时,Windows 运行时组件项目、JavaScript 项目文件和编译的 DLL 会合并到一个程序包中,可以在模拟器中本地调试或在受限设备上远程调试该程序包。When you build a solution that contains a JavaScript or .NET project, and a Windows Runtime component project, the JavaScript project files and the compiled DLL are merged into one package, which you can debug locally in the simulator or remotely on a tethered device. 你还可以仅将组件项目作为扩展 SDK 进行分配。You can also distribute just the component project as an Extension SDK. 有关详细信息,请参阅创建软件开发工具包For more information, see Creating a Software Development Kit.

通常,当你编写 c + +/CX 组件的代码时,请使用常规 c + + 库和内置类型,但在抽象二进制接口 (ABI) 边界,在该边界内,你要将数据传递到另一个 winmd 包中的代码。In general, when you code your C++/CX component, use the regular C++ library and built-in types, except at the abstract binary interface (ABI) boundary where you are passing data to and from code in another .winmd package. 在那里,使用 Windows 运行时类型和 c + +/CX 支持的用于创建和操作这些类型的特殊语法。There, use Windows Runtime types and the special syntax that C++/CX supports for creating and manipulating those types. 此外,在 c + +/CX 代码中,可以使用委托和事件等类型来实现可从你的组件引发并在 JavaScript、Visual Basic、c + + 或 c # 中进行处理的事件。In addition, in your C++/CX code, use types such as delegate and event to implement events that can be raised from your component and handled in JavaScript, Visual Basic, C++, or C#. 有关 c + +/CX 语法的详细信息,请参阅 c + +/cx (Visual C++ 语言参考) For more information about the C++/CX syntax, see Visual C++ Language Reference (C++/CX).

大小写和命名规则Casing and naming rules

JavascriptJavaScript

JavaScript 区分大小写。JavaScript is case-sensitive. 因此,必须遵循以下大小写约定:Therefore, you must follow these casing conventions:

  • 引用 C++ 命名空间和类时,采用在 C++ 端上使用的相同大小写。When you reference C++ namespaces and classes, use the same casing that's used on the C++ side.
  • 调用方法时,使用 Camel 大小写格式,即使方法名在 C++ 端上是大写。When you call methods, use camel casing even if the method name is capitalized on the C++ side. 例如,C++ 方法 GetDate() 必须作为 getDate() 从 JavaScript 调用。For example, a C++ method GetDate() must be called from JavaScript as getDate().
  • 可激活类名和命名空间名称不能包含 UNICODE 字符。An activatable class name and namespace name can't contain UNICODE characters.

.NET.NET

.NET 语言遵循其正常大小写规则。The .NET languages follow their normal casing rules.

实例化对象Instantiating the object

仅 Windows 运行时类型可以跨 ABI 边界传递。Only Windows Runtime types can be passed across the ABI boundary. 如果组件在公共方法中具有作为返回类型或参数的类型(例如 std::wstring),编译器将引发错误。The compiler will raise an error if the component has a type like std::wstring as a return type or parameter in a public method. Visual C++ 组件扩展 (C++/CX) 内置类型包括诸如整型和双精度型的常用标量及其 typedef 等效项 int32、float64 等。The Visual C++ component extensions (C++/CX) built-in types include the usual scalars such as int and double, and also their typedef equivalents int32, float64, and so on. 有关详细信息,请参阅类型系统 (C++/CX)For more information, see Type System (C++/CX).

// ref class definition in C++
public ref class SampleRefClass sealed
{
    // Class members...

    // #include <valarray>
public:
    double LogCalc(double input)
    {
        // Use C++ standard library as usual.
        return std::log(input);
    }

};
//Instantiation in JavaScript (requires "Add reference > Project reference")
var nativeObject = new CppComponent.SampleRefClass();
//Call a method and display result in a XAML TextBlock
var num = nativeObject.LogCalc(21.5);
ResultText.Text = num.ToString();

C + +/CX 内置类型、库类型和 Windows 运行时类型C++/CX built-in types, library types, and Windows Runtime types

可激活类(也称为 ref 类)是可通过其他诸如 JavaScript、C# 或 Visual Basic 语言实例化的类。An activatable class (also known as a ref class) is one that can be instantiated from another language such as JavaScript, C# or Visual Basic. 若要能够通过其他语言使用,组件必须包含至少一项可激活类。To be consumable from another language, a component must contain at least one activatable class.

Windows 运行时组件可以包含多个公共的可激活类以及其他仅为组件内部所知的类。A Windows Runtime component can contain multiple public activatable classes as well as additional classes that are known only internally to the component. WebHostHidden 特性应用于不应向 JavaScript 显示的 c + +/cx 类型。Apply the WebHostHidden attribute to C++/CX types that are not intended to be visible to JavaScript.

所有公共类必须驻留在与组件元数据文件具有相同名称的相同根命名空间中。All public classes must reside in the same root namespace which has the same name as the component metadata file. 例如,名为 A.B.C.MyClass 的类只有在名为 A.winmd 或 A.B.winmd 或 A.B.C.winmd 的元数据文件中定义后才能实例化。For example, a class that's named A.B.C.MyClass can be instantiated only if it's defined in a metadata file that's named A.winmd or A.B.winmd or A.B.C.winmd. DLL 的名称不必与 .winmd 文件名匹配。The name of the DLL is not required to match the .winmd file name.

就像对任意类一样,客户端代码使用 new(在 Visual Basic 中是 New)关键字创建组件实例。Client code creates an instance of the component by using the new (New in Visual Basic) keyword just as for any class.

可激活类必须声明为 public ref class sealedAn activatable class must be declared as public ref class sealed. ref class 关键字告知编译器将类创建为 Windows 运行时兼容类型,而 sealed 关键字指定该类无法继承。The ref class keyword tells the compiler to create the class as a Windows Runtime compatible type, and the sealed keyword specifies that the class cannot be inherited. Windows 运行时当前无法支持一般化的继承模型;有限的继承模型支持创建自定义 XAML 控件。The Windows Runtime does not currently support a generalized inheritance model; a limited inheritance model supports creation of custom XAML controls. 有关详细信息,请参阅 Ref 类和结构 (C++/CX)For more information, see Ref classes and structs (C++/CX).

对于 c + +/CX,所有数值基元都在默认命名空间中定义。For C++/CX, all the numeric primitives are defined in the default namespace. 平台命名空间包含特定于 Windows 运行时类型系统的 c + +/cx 类。The Platform namespace contains C++/CX classes that are specific to the Windows Runtime type system. 这些类包括 Platform::String 类和 Platform::Object 类。These include Platform::String class and Platform::Object class. 诸如 Platform::Collections::Map 类和 Platform::Collections::Vector 类的具体集合类型在 Platform::Collections 命名空间中定义。The concrete collection types such as Platform::Collections::Map class and Platform::Collections::Vector class are defined in the Platform::Collections namespace. 这些类型实现的公共接口在 Windows::Foundation::Collections 命名空间 (C++/CX) 中定义。The public interfaces that these types implement are defined in Windows::Foundation::Collections Namespace (C++/CX). JavaScript、C# 和 Visual Basic 使用的正是这些接口类型。It is these interface types that are consumed by JavaScript, C# and Visual Basic. 有关详细信息,请参阅类型系统 (C++/CX)For more information, see Type System (C++/CX).

返回内置类型值的方法Method that returns a value of built-in type

    // #include <valarray>
public:
    double LogCalc(double input)
    {
        // Use C++ standard library as usual.
        return std::log(input);
    }
//Call a method
var nativeObject = new CppComponent.SampleRefClass;
var num = nativeObject.logCalc(21.5);
document.getElementById('P2').innerHTML = num;

返回自定义值结构的方法Method that returns a custom value struct

namespace CppComponent
{
    // Custom struct
    public value struct PlayerData
    {
        Platform::String^ Name;
        int Number;
        double ScoringAverage;
    };

    public ref class Player sealed
    {
    private:
        PlayerData m_player;
    public:
        property PlayerData PlayerStats
        {
            PlayerData get(){ return m_player; }
            void set(PlayerData data) {m_player = data;}
        }
    };
}

若要跨 ABI 传递用户定义的值结构,请定义一个 JavaScript 对象,该对象具有与 c + +/CX 中定义的值结构相同的成员。To pass user-defined value structs across the ABI, define a JavaScript object that has the same members as the value struct that's defined in C++/CX. 然后,可以将该对象作为参数传递给 c + +/CX 方法,以便将对象隐式转换为 c + +/CX 类型。You can then pass that object as an argument to a C++/CX method so that the object is implicitly converted to the C++/CX type.

// Get and set the value struct
function GetAndSetPlayerData() {
    // Create an object to pass to C++
    var myData =
        { name: "Bob Homer", number: 12, scoringAverage: .357 };
    var nativeObject = new CppComponent.Player();
    nativeObject.playerStats = myData;

    // Retrieve C++ value struct into new JavaScript object
    var myData2 = nativeObject.playerStats;
    document.getElementById('P3').innerHTML = myData.name + " , " + myData.number + " , " + myData.scoringAverage.toPrecision(3);
}

另一种方法是定义实现 IPropertySet 的类(未显示)。Another approach is to define a class that implements IPropertySet (not shown).

在 .NET 语言中,只需创建一个在 c + +/CX 组件中定义的类型的变量。In the .NET languages, you just create a variable of the type that's defined in the C++/CX component.

private void GetAndSetPlayerData()
{
    // Create a ref class
    var player = new CppComponent.Player();

    // Create a variable of a value struct
    // type that is defined in C++
    CppComponent.PlayerData myPlayer;
    myPlayer.Name = "Babe Ruth";
    myPlayer.Number = 12;
    myPlayer.ScoringAverage = .398;

    // Set the property
    player.PlayerStats = myPlayer;

    // Get the property and store it in a new variable
    CppComponent.PlayerData myPlayer2 = player.PlayerStats;
    ResultText.Text += myPlayer.Name + " , " + myPlayer.Number.ToString() +
        " , " + myPlayer.ScoringAverage.ToString();
}

重载方法Overloaded Methods

C + +/CX 公共 ref 类可以包含重载方法,但 JavaScript 的功能有限,可以区分重载方法。A C++/CX public ref class can contain overloaded methods, but JavaScript has limited ability to differentiate overloaded methods. 例如,它可以区分以下签名之间的区别:For example, it can tell the difference between these signatures:

public ref class NumberClass sealed
{
public:
    int GetNumber(int i);
    int GetNumber(int i, Platform::String^ str);
    double GetNumber(int i, MyData^ d);
};

但它不能判断它们之间的区别:But it can't tell the difference between these:

int GetNumber(int i);
double GetNumber(double d);

在不明确的情况下,通过在标头文件中将 Windows::Foundation::Metadata::DefaultOverload 属性应用到方法签名,你可以确保 JavaScript 始终调用特定重载。In ambiguous cases, you can ensure that JavaScript always calls a specific overload by applying the Windows::Foundation::Metadata::DefaultOverload attribute to the method signature in the header file.

此 JavaScript 始终调用属性化重载:This JavaScript always calls the attributed overload:

var nativeObject = new CppComponent.NumberClass();
var num = nativeObject.getNumber(9);
document.getElementById('P4').innerHTML = num;

.NET.NET

.NET 语言识别 c + +/CX ref 类中的重载,就像在任何 .NET 类中一样。The .NET languages recognize overloads in a C++/CX ref class just as in any .NET class.

DateTimeDateTime

在 Windows 运行时中,Windows::Foundation::DateTime 对象仅是一个 64 位有符号的整数,代表 1601 年 1 月 1 日前或后 100 纳秒间隔的数字。In the Windows Runtime, a Windows::Foundation::DateTime object is just a 64-bit signed integer that represents the number of 100-nanosecond intervals either before or after January 1, 1601. Windows:Foundation::DateTime 对象上没有方法。There are no methods on a Windows:Foundation::DateTime object. 相反,每个语言以该语言的本机方式投影日期时间: JavaScript 中的 Date 对象和 .NET 中的 system.string 和 System.object 类型。Instead, each language projects the DateTime in the way that is native to that language: the Date object in JavaScript and the System.DateTime and System.DateTimeOffset types in .NET.

public  ref class MyDateClass sealed
{
public:
    property Windows::Foundation::DateTime TimeStamp;
    void SetTime(Windows::Foundation::DateTime dt)
    {
        auto cal = ref new Windows::Globalization::Calendar();
        cal->SetDateTime(dt);
        TimeStamp = cal->GetDateTime(); // or TimeStamp = dt;
    }
};

将日期时间值从 c + +/CX 传递到 JavaScript 时,JavaScript 会接受它作为 Date 对象并默认显示为长格式日期字符串。When you pass a DateTime value from C++/CX to JavaScript, JavaScript accepts it as a Date object and displays it by default as a long-form date string.

function SetAndGetDate() {
    var nativeObject = new CppComponent.MyDateClass();

    var myDate = new Date(1956, 4, 21);
    nativeObject.setTime(myDate);

    var myDate2 = nativeObject.timeStamp;

    //prints long form date string
    document.getElementById('P5').innerHTML = myDate2;

}

当 .NET 语言将 system.exception 传递到 c + +/CX 组件时,该方法会将其接受为 Windows:: Foundation::D ateTime。When a .NET language passes a System.DateTime to a C++/CX component, the method accepts it as a Windows::Foundation::DateTime. 当组件将 Windows:: Foundation::D ateTime 传递到 .NET 方法时,框架方法会将其作为 DateTimeOffset 接受。When the component passes a Windows::Foundation::DateTime to a .NET method, the Framework method accepts it as a DateTimeOffset.

private void DateTimeExample()
{
    // Pass a System.DateTime to a C++ method
    // that takes a Windows::Foundation::DateTime
    DateTime dt = DateTime.Now;
    var nativeObject = new CppComponent.MyDateClass();
    nativeObject.SetTime(dt);

    // Retrieve a Windows::Foundation::DateTime as a
    // System.DateTimeOffset
    DateTimeOffset myDate = nativeObject.TimeStamp;

    // Print the long-form date string
    ResultText.Text += myDate.ToString();
}

集合和数组Collections and arrays

集合始终作为 Windows 运行时类型(例如 Windows::Foundation::Collections::IVector^ 和 Windows::Foundation::Collections::IMap^)的句柄在 ABI 边界上传递。Collections are always passed across the ABI boundary as handles to Windows Runtime types such as Windows::Foundation::Collections::IVector^ and Windows::Foundation::Collections::IMap^. 例如,如果将句柄返回到 Platform::Collections::Map,它会隐式转换为 Windows::Foundation::Collections::IMap^。For example, if you return a handle to a Platform::Collections::Map, it implicitly converts to a Windows::Foundation::Collections::IMap^. 集合接口在与提供具体实现的 c + +/CX 类不同的命名空间中定义。The collection interfaces are defined in a namespace that's separate from the C++/CX classes that provide the concrete implementations. JavaScript 和 .NET 语言使用接口。JavaScript and .NET languages consume the interfaces. 有关详细信息,请参阅集合 (C++/CX)数组和 WriteOnlyArray (C++/CX)For more information, see Collections (C++/CX) and Array and WriteOnlyArray (C++/CX).

传递 IVectorPassing IVector

// Windows::Foundation::Collections::IVector across the ABI.
//#include <algorithm>
//#include <collection.h>
Windows::Foundation::Collections::IVector<int>^ SortVector(Windows::Foundation::Collections::IVector<int>^ vec)
{
    std::sort(begin(vec), end(vec));
    return vec;
}
var nativeObject = new CppComponent.CollectionExample();
// Call the method to sort an integer array
var inVector = [14, 12, 45, 89, 23];
var outVector = nativeObject.sortVector(inVector);
var result = "Sorted vector to array:";
for (var i = 0; i < outVector.length; i++)
{
    outVector[i];
    result += outVector[i].toString() + ",";
}
document.getElementById('P6').innerHTML = result;

.NET 语言将 IVector<T> 视为 IList<T>。The .NET languages see IVector<T> as IList<T>.

private void SortListItems()
{
    IList<int> myList = new List<int>();
    myList.Add(5);
    myList.Add(9);
    myList.Add(17);
    myList.Add(2);

    var nativeObject = new CppComponent.CollectionExample();
    IList<int> mySortedList = nativeObject.SortVector(myList);

    foreach (var item in mySortedList)
    {
        ResultText.Text += " " + item.ToString();
    }
}

传递 IMapPassing IMap

// #include <map>
//#include <collection.h>
Windows::Foundation::Collections::IMap<int, Platform::String^> ^GetMap(void)
{    
    Windows::Foundation::Collections::IMap<int, Platform::String^> ^ret =
        ref new Platform::Collections::Map<int, Platform::String^>;
    ret->Insert(1, "One ");
    ret->Insert(2, "Two ");
    ret->Insert(3, "Three ");
    ret->Insert(4, "Four ");
    ret->Insert(5, "Five ");
    return ret;
}
// Call the method to get the map
var outputMap = nativeObject.getMap();
var mStr = "Map result:" + outputMap.lookup(1) + outputMap.lookup(2)
    + outputMap.lookup(3) + outputMap.lookup(4) + outputMap.lookup(5);
document.getElementById('P7').innerHTML = mStr;

.NET 语言查看 IMap 和 IDictionary<K, V>。The .NET languages see IMap and IDictionary<K, V>.

private void GetDictionary()
{
    var nativeObject = new CppComponent.CollectionExample();
    IDictionary<int, string> d = nativeObject.GetMap();
    ResultText.Text += d[2].ToString();
}

属性Properties

C + +/CX 组件扩展中的公共 ref 类通过使用 property 关键字将公共数据成员作为属性公开。A public ref class in C++/CX component extensions exposes public data members as properties, by using the property keyword. 概念与 .NET 属性相同。The concept is identical to .NET properties. 普通属性类似于数据成员,因为其功能是隐式的。A trivial property resembles a data member because its functionality is implicit. 特殊属性具有显式获取和设置的访问器和作为值的“备份存储”的已命名私有变量。A non-trivial property has explicit get and set accessors and a named private variable that's the "backing store" for the value. 在此示例中,私有成员变量 _ propertyAValue 是 PropertyA 的后备存储。In this example, the private member variable _propertyAValue is the backing store for PropertyA. 属性可以在它的值更改时引发某个事件,并且客户端应用可注册为接收该事件。A property can fire an event when its value changes, and a client app can register to receive that event.

//Properties
public delegate void PropertyChangedHandler(Platform::Object^ sender, int arg);
public ref class PropertyExample  sealed
{
public:
    PropertyExample(){}

    // Event that is fired when PropertyA changes
    event PropertyChangedHandler^ PropertyChangedEvent;

    // Property that has custom setter/getter
    property int PropertyA
    {
        int get() { return m_propertyAValue; }
        void set(int propertyAValue)
        {
            if (propertyAValue != m_propertyAValue)
            {
                m_propertyAValue = propertyAValue;
                // Fire event. (See event example below.)
                PropertyChangedEvent(this, propertyAValue);
            }
        }
    }

    // Trivial get/set property that has a compiler-generated backing store.
    property Platform::String^ PropertyB;

private:
    // Backing store for propertyA.
    int m_propertyAValue;
};
var nativeObject = new CppComponent.PropertyExample();
var propValue = nativeObject.propertyA;
document.getElementById('P8').innerHTML = propValue;

//Set the string property
nativeObject.propertyB = "What is the meaning of the universe?";
document.getElementById('P9').innerHTML += nativeObject.propertyB;

.NET 语言访问本机 c + +/CX 对象上的属性,就像它们在 .NET 对象上一样。The .NET languages access properties on a native C++/CX object just as they would on a .NET object.

private void GetAProperty()
{
    // Get the value of the integer property
    // Instantiate the C++ object
    var obj = new CppComponent.PropertyExample();

    // Get an integer property
    var propValue = obj.PropertyA;
    ResultText.Text += propValue.ToString();

    // Set a string property
    obj.PropertyB = " What is the meaning of the universe?";
    ResultText.Text += obj.PropertyB;

}

委托和事件Delegates and events

委派是表示函数对象的 Windows 运行时类型。A delegate is a Windows Runtime type that represents a function object. 你可以将委派与事件、回调和异步方法调用结合起来,以指定稍后要执行的操作。You can use delegates in connection with events, callbacks, and asynchronous method calls to specify an action to be performed later. 像函数对象一样,委派通过支持编译器验证返回类型和函数的参数类型来提供类型安全。Like a function object, the delegate provides type-safety by enabling the compiler to verify the return type and parameter types of the function. 委派的声明类似于函数签名、实现类似于类定义,而调用类似于函数调用。The declaration of a delegate resembles a function signature, the implementation resembles a class definition, and the invocation resembles a function invocation.

添加事件侦听器Adding an event listener

你可以使用事件关键字声明指定的委派类型的公共成员。You can use the event keyword to declare a public member of a specified delegate type. 客户端代码通过使用在特定语言中提供的标准机制订阅事件。Client code subscribes to the event by using the standard mechanisms that are provided in the particular language.

public:
    event SomeHandler^ someEvent;

此示例使用与之前属性部分相同的 C++ 代码。This example uses the same C++ code as for the previous properties section.

function Button_Click() {
    var nativeObj = new CppComponent.PropertyExample();
    // Define an event handler method
    var singlecasthandler = function (ev) {
        document.getElementById('P10').innerHTML = "The button was clicked and the value is " + ev;
    };

    // Subscribe to the event
    nativeObj.onpropertychangedevent = singlecasthandler;

    // Set the value of the property and fire the event
    var propValue = 21;
    nativeObj.propertyA = 2 * propValue;

}

在 .NET 语言中,订阅 c + + 组件中的事件与订阅 .NET 类中的事件相同:In the .NET languages, subscribing to an event in a C++ component is the same as subscribing to an event in a .NET class:

//Subscribe to event and call method that causes it to be fired.
private void TestMethod()
{
    var objWithEvent = new CppComponent.PropertyExample();
    objWithEvent.PropertyChangedEvent += objWithEvent_PropertyChangedEvent;

    objWithEvent.PropertyA = 42;
}

//Event handler method
private void objWithEvent_PropertyChangedEvent(object __param0, int __param1)
{
    ResultText.Text = "the event was fired and the result is " +
         __param1.ToString();
}

为一个事件添加多个事件侦听器Adding multiple event listeners for one event

JavaScript 具有支持多个处理程序订阅单一事件的 addEventListener 方法。JavaScript has an addEventListener method that enables multiple handlers to subscribe to a single event.

public delegate void SomeHandler(Platform::String^ str);

public ref class LangSample sealed
{
public:
    event SomeHandler^ someEvent;
    property Platform::String^ PropertyA;

    // Method that fires an event
    void FireEvent(Platform::String^ str)
    {
        someEvent(Platform::String::Concat(str, PropertyA->ToString()));
    }
    //...
};
// Add two event handlers
var multicast1 = function (ev) {
    document.getElementById('P11').innerHTML = "Handler 1: " + ev.target;
};
var multicast2 = function (ev) {
    document.getElementById('P12').innerHTML = "Handler 2: " + ev.target;
};

var nativeObject = new CppComponent.LangSample();
//Subscribe to the same event
nativeObject.addEventListener("someevent", multicast1);
nativeObject.addEventListener("someevent", multicast2);

nativeObject.propertyA = "42";

// This method should fire an event
nativeObject.fireEvent("The answer is ");

在 C# 中,任意数量的事件处理程序可以使用 += 运算符订阅事件,如之前示例所示。In C#, any number of event handlers can subscribe to the event by using the += operator as shown in the previous example.

枚举Enums

C + +/CX 中的 Windows 运行时枚举是使用公共类枚举声明的;它类似于标准 c + + 中的范围枚举。A Windows Runtime enum in C++/CX is declared by using public class enum; it resembles a scoped enum in standard C++.

public enum class Direction {North, South, East, West};

public ref class EnumExampleClass sealed
{
public:
    property Direction CurrentDirection
    {
        Direction  get(){return m_direction; }
    }

private:
    Direction m_direction;
};

枚举值作为整数在 c + +/CX 和 JavaScript 之间传递。Enum values are passed between C++/CX and JavaScript as integers. 您可以选择声明一个 JavaScript 对象,该对象包含与 c + +/CX 枚举相同的命名值,并按如下所示使用。You can optionally declare a JavaScript object that contains the same named values as the C++/CX enum and use it as follows.

var Direction = { 0: "North", 1: "South", 2: "East", 3: "West" };
//. . .

var nativeObject = new CppComponent.EnumExampleClass();
var curDirection = nativeObject.currentDirection;
document.getElementById('P13').innerHTML =
Direction[curDirection];

C# 和 Visual Basic 均支持枚举语言。Both C# and Visual Basic have language support for enums. 这些语言会看到 c + + 公共枚举类,就像它们会看到 .NET 枚举一样。These languages see a C++ public enum class just as they would see a .NET enum.

异步方法Asynchronous methods

若要使用其他 Windows 运行时对象公开的异步方法,请使用任务类(并发运行时)To consume asynchronous methods that are exposed by other Windows Runtime objects, use the task Class (Concurrency Runtime). 有关详细信息,请参阅任务并行度(并发运行时)For more information, see and Task Parallelism (Concurrency Runtime).

若要在 c + +/CX 中实现异步方法,请使用 ppltasks.h 中定义的 create _ async 函数。To implement asynchronous methods in C++/CX, use the create_async function that's defined in ppltasks.h. 有关详细信息,请参阅 在适用于 UWP 应用的 c + +/cx 中创建异步操作For more information, see Creating Asynchronous Operations in C++/CX for UWP apps. 有关示例,请参阅 创建 c + +/cx Windows 运行时组件并从 JavaScript 或 c # 中调用该组件的演练For an example, see Walkthrough of creating a C++/CX Windows Runtime component, and calling it from JavaScript or C#. .NET 语言使用 c + +/CX 异步方法,就像它们是在 .NET 中定义的任何异步方法一样。The .NET languages consume C++/CX asynchronous methods just as they would any asynchronous method that's defined in .NET.

异常Exceptions

你可以引发任何由 Windows 运行时定义的异常类型。You can throw any exception type that's defined by the Windows Runtime. 你无法从任何 Windows 运行时异常类型中派生自定义类型。You cannot derive custom types from any Windows Runtime exception type. 但是,你可以引发 COMException 并提供可由捕获异常的代码访问的自定义 HRESULT。However, you can throw COMException and provide a custom HRESULT that can be accessed by the code that catches the exception. 无法在 COMException 中指定自定义消息。There's no way to specify a custom Message in a COMException.

调试提示Debugging tips

在调试具有组件 DLL 的 JavaScript 解决方案时,你可以将调试器设置为在组件中支持单步调试脚本或单步调试本机代码,但无法设置为同时进行。When you debug a JavaScript solution that has a component DLL, you can set the debugger to enable either stepping through script, or stepping through native code in the component, but not both at the same time. 若要更改设置,请在解决方案资源管理器中选择 JavaScript 项目节点,然后选择“属性”、“调试”、“调试器类型”。To change the setting, select the JavaScript project node in Solution Explorer and then choose Properties, Debugging, Debugger Type.

请确保在程序包设计器中选择相应的功能。Be sure to select appropriate capabilities in the package designer. 例如,如果你要尝试使用 Windows 运行时 API 打开用户的“图片”库中的图像文件,请确保在清单设计器中的“功能”窗格中选中“图片库”复选框。For example, if you are attempting to open an image file in the user's Pictures library by using the Windows Runtime APIs, be sure to select the Pictures Library check box in the Capabilities pane of the manifest designer.

如果 JavaScript 代码似乎无法识别组件中的公共属性或方法,请确保在 JavaScript 中使用的是 Camel 大小写格式。If your JavaScript code doesn't seem to be recognizing the public properties or methods in the component, make sure that in JavaScript you are using camel casing. 例如,在 JavaScript 中,LogCalc c + +/CX 方法必须被引用为 logCalc。For example, the LogCalc C++/CX method must be referenced as logCalc in JavaScript.

如果从解决方案中删除 c + +/CX Windows 运行时组件项目,还必须从 JavaScript 项目中手动删除项目引用。If you remove a C++/CX Windows Runtime component project from a solution, you must also manually remove the project reference from the JavaScript project. 如果此操作无法完成,将阻止后续调试或生成操作。Failure to do so prevents subsequent debug or build operations. 如有必要,你可以稍后向 DLL 添加程序集引用。If necessary, you can then add an assembly reference to the DLL.