日期:2014-05-16  浏览次数:20352 次

【windows8开发】Windows Runtime组件封装及与javascript的交互
/******************************************
开始本文之前,借块地方说明下,本文之前的所有win8系列的文章是在windows 8 consumer preview(消费者预览版)的上进行的一些尝试和分享,本文开始会切换到windows 8 release preview(发行者预览版),因为从老版本到现在的版本间,framework中一些API有所改变,所以有些示例代码并不兼容,特此说明下。
******************************************/
windows 8通过windows runtime framework支持不同语言间的交互,比如在《【windows8开发】C++开发WinRT组件和JS调用》一文里曾经介绍过javascript如何去调用C++组件,而在本文中会更关注于怎么去封装支持多语言交互的组件,组件方使用C++来描述,调用方则使用javascript,因为实例代码中会有很多关于C++ /CX的特性,所以还不了解C++ /CX的可以先阅读下这篇文章:

《【windows8开发】深入浅出C++/CX》

希望大家带着如下问题去阅读这篇文章。
1. javascript如何调用C++ API
2. C++如何返回数据给javascript
3. js和C++交互时的数据类型问题
4. 事件绑定,调用与回调

ok,进入正题。

Metro App中,要支持多语言调用,必须封装成windows runtime的组件dll,所谓windows runtime组件就是要基于windows runtime定义好的形式去封装组件API,而这些定义好的形式其实大部分都属于C++ /CX的特性,换句话说就是用C++ /CX的一些C++扩展特性来封装windows runtime组件。


0. 如何创建windows runtime组件工程
很简单,如果使用C++来封装组件的话,就在创建新工程时,选择 Visual C++ --> Windows Metro style --> Windows Runtime Component。

1. javascript调用C++类
windows runtime组件都会以类的形式给外部提供API,至少目前为止我还不知道是否可以封装成C风格函数的API。
看如下C++示例:
namespace RuntimeC
{
    public ref class Test sealed
    {
    public:
       Test() {}
    };
}

js中的调用:

var nativeObject = new RuntimeC.Test();

很简单吧,通过new和命名空间名,直接访问类来实例化对象。组件中要提供可被javascript实例化的类则必须把该类定义为public ref(不理解public ref的请参考C++ /CX一文)


2.类方法名大小写 
如果类中的暴露给外部的方法首字母是大写,那在javascript中调用时该方法首字母应该写为小写,比如:假设如上Test1类中有如下方法:

void Func1() {}
那么js中应该如下来调用:
nativeObject.func1();


3. 不同语言间的数据交互

大家都知道C++是强类型语言,那么C++传递数据给javascript时,对数据类型有什么要求呢?windows runtime中提供了一些内置类型来供多语言交互时使用,也就是说如果要封装给不同语言调用的接口,就要使用这些内置类型。

a. 基本数据类型(int,double等)
接口中可以直接使用基本类型来传递数据,它们会被自动转化成window runtime的内置类型int32,float64等。

double Func2(double pa) {
     return pa;
}
b. 返回结构体或类对象(C++ --> javascript)
如果Test类中有个方法,它的返回值是自定义的结构体,怎么做?

public value struct DataStruct {
     int value;
};
public ref class Test sealed
{
public:
     Test() {
     }
     DataStruct Func3() {
          DataStruct data;
          return data;
     }
};
注意,这里把DataStruct声明为public value,否则会出错,见C++ /CX。
javascript侧的调用:

var data = nativeObject.func3();
c. 函数参数类型为结构体或类 (javascript --> C++)
当组件中提供的函数参数类型为结构体和类时,也就意味着需要在javascript中把数据传递给C++,此时我们必须把参数定义为ref引用类型。

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;
     }
};