zoukankan      html  css  js  c++  java
  • 【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;
         }
    };
    由于需要从javascript侧传数据,所以需要把DataRef暴露出来,由js侧实例化DataRef对象并传递给C++。这里用到了property关键字,见C++ /CX一文。
    javascript侧的调用如下:

    var nativeObject = new RuntimeC.Test();
    var obj = new RuntimeC.DataRef();
    nativeObject.func4(obj);
    var value = obj.val;
    d. Windows::Foundation
    Windows::Foundation中提供了很多供不同语言交互使用的内置类型,
    比如DateTime,假设在C++中要把当前时间返回给javascript:

    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. 方法重载的限制
    javascript中对C++中的函数重载形式有一定限制,比如它可以区分出如下的重载函数:

    int GetData(int i);
    int GetData(int i, MyType^ t);
    但是由于javascript是弱类型语言,它不能区分出如下C++支持的重载方式:
    int GetData(int i, MyType1^ t);
    int GetData(int i, MyType2^ t);
    所以在要重载对外的接口方法时,需要注意这一点。

    5. 委托与事件(调用与回调)
    关于delegate和event的详细说明请参照C++ /CX一文。这里主要关注C++和javascript之间的调用和回调,先看如下代码:

    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来决定的)

    除了使用onchangedevent来绑定外,还可以使用addEventListener来绑定多个处理,如下所示:

    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"。


    最后,总结一下,在Metro app中封装能给不同语言使用的组件,必须基于windows runtime组件的封装原则,使用C++ /CX的一些扩展特性来封装外部方法。所以如果要复用以前的windows desktop app的通用组件,就需要为这些组件再包一层windows runtime的wrap。
  • 相关阅读:
    进程详解
    java 实体对象与Map之间的转换工具类(自己还没看)
    fastjson中toString与toJSONString的差别
    JSONObject.toJSONString()包含或排除指定的属性
    FastJson中JSONObject用法及常用方法总结
    SpringBoot之ApplicationRunner接口和@Order注解
    shiro使用
    RedisTemplate 中 opsForHash()使用 (没有测试过,copy的)
    解决:javax.servlet.ServletException: Circular view path []: would dispatch back to the current....
    【Springboot】spring-boot-starter-redis包报错 :unknown
  • 原文地址:https://www.cnblogs.com/secbook/p/2655096.html
Copyright © 2011-2022 走看看