《【windows8开发】深入浅出C++/CX》
希望大家带着如下问题去阅读这篇文章。Metro App中,要支持多语言调用,必须封装成windows runtime的组件dll,所谓windows runtime组件就是要基于windows runtime定义好的形式去封装组件API,而这些定义好的形式其实大部分都属于C++ /CX的特性,换句话说就是用C++ /CX的一些C++扩展特性来封装windows runtime组件。
namespace RuntimeC { public ref class Test sealed { public: Test() {} }; }
js中的调用:
var nativeObject = new RuntimeC.Test();
很简单吧,通过new和命名空间名,直接访问类来实例化对象。组件中要提供可被javascript实例化的类则必须把该类定义为public ref(不理解public ref的请参考C++ /CX一文)
void Func1() {}那么js中应该如下来调用:
nativeObject.func1();
3. 不同语言间的数据交互
大家都知道C++是强类型语言,那么C++传递数据给javascript时,对数据类型有什么要求呢?windows runtime中提供了一些内置类型来供多语言交互时使用,也就是说如果要封装给不同语言调用的接口,就要使用这些内置类型。double Func2(double pa) { return pa; }b. 返回结构体或类对象(C++ --> javascript)
public value struct DataStruct { int value; }; public ref class Test sealed { public: Test() { } DataStruct Func3() { DataStruct data; return data; } };注意,这里把DataStruct声明为public value,否则会出错,见C++ /CX。
var data = nativeObject.func3();c. 函数参数类型为结构体或类 (javascript --> C++)
public ref struct DataRef sealed { private: int value; public: DataRef() {} property int val { int get() {return value;} void set(int v) {value = v;} } }; public ref class Test sealed { public: Test() { } void Func4(DataRef^ data) { data->val = 0; } };由于需要从javascript侧传数据,所以需要把DataRef暴露出来,由js侧实例化DataRef对象并传递给C++。这里用到了property关键字,见C++ /CX一文。
var nativeObject = new RuntimeC.Test(); var obj = new RuntimeC.DataRef(); nativeObject.func4(obj); var value = obj.val;d. Windows::Foundation
Windows::Foundation::DateTime Func5() { auto cal = ref new Windows::Globalization::Calendar(); cal->SetToNow(); return cal->GetDateTime(); }js侧,调用Func5方法会返回一个Date类型的对象:
var date = nativeObject.func5(); var day = date.getDate();又比如各种Collections,假设要在C++中清空js传过来的array类型数据:
Windows::Foundation::Collections::IVector <int>^ ClearVector(Windows::Foundation::Collections::IVector<int>^ vec) { for (unsigned int i = 0; i < (vec->Size); i++) { vec->SetAt(i, 0); } return vec; }js调用:
var list = [1, 3, 2, 5]; nativeObject.clearVector(list);4. 方法重载的限制
int GetData(int i); int GetData(int i, MyType^ t);但是由于javascript是弱类型语言,它不能区分出如下C++支持的重载方式:
int GetData(int i, MyType1^ t); int GetData(int i, MyType2^ t);所以在要重载对外的接口方法时,需要注意这一点。
public delegate void ChangedHandler(); public ref class Test sealed { public: Test() {} void FireEvent() { changedEvent(); } event ChangedHandler^ changedEvent; };JS代码中绑定事件并调用FireEvent方法触发事件:
var eventHandler = function (evt) { ...... }; nativeObject.onchangedevent = eventHandler; nativeObject.fireEvent();通过onchangedevent把eventHandler方法绑定到changedEvent事件,当调用FireEvent触发事件后,js代码中eventHandler会被触发。(这里的onchangedevent是依据C++中的事件名changedEvent来决定的)
var eventHandler1 = function (evt) { ...... }; var eventHandler2 = function (evt) { ...... }; nativeObject.addEventListener("changedevent", eventHandler1); nativeObject.addEventListener("changedevent", eventHandler2); nativeObject.fireEvent();
这里eventHandler1和eventHandler2都会被触发。注意,事件名里的大写字母在用addEventListener绑定是都应该用小写,比如在C++里事件为changedEvent,js绑定时则应该是"changedevent"。