zoukankan      html  css  js  c++  java
  • 不可或缺 Windows Native (25)

    [源码下载]


    不可或缺 Windows Native (25) - C++: windows app native, android app native, ios app native



    作者:webabcd


    介绍
    不可或缺 Windows Native 之 C++

    • windows app native
    • android app native
    • ios app native



    示例
    一、演示 windows app native 开发
    1、native 层
    CppCx.h

    #pragma once 
    
    #include <string>
    
    using namespace std;
    
    namespace NativeDll
    {
        class CppCx
        {
        public:
            string Hello(string name);
        };
    }

    CppCx.cpp

    /*
     * 演示 C#, C++/CX, C/C++ 间的通信
     *
     * 本例是 C/C++ 部分
     */
    
    #include "pch.h" 
    #include "CppCx.h" 
    #include "DemoCx.h"
    
    using namespace NativeDll;
    
    string CppCx::Hello(string name)
    {
        // C/C++ 通过 C++/CX 调用 C#
        if (DemoCx::GlobalCallback != nullptr)
            DemoCx::GlobalCallback->Cx2Cs("c/c++ to c++/cx to cs");
    
        return "hello: " + name;
    }


    2、C++/CX 层
    DemoCx.h

    #pragma once 
    
    #include "ICallback.h"
    
    using namespace Platform;
    
    namespace NativeDll 
    {
        // ref class 可被输出到元数据(winmd - Windows Metadata),以便其他托管程序调用
        public ref class DemoCx sealed 
        {
        public:
            // 用“^”标记的,系统会负责他们的引用计数,当引用计数为 0 时,它们会被销毁
            String^ HelloCx(String^ name); 
    
            String^ HelloCpp(String^ name);
    
    
            // 由 C# 调用,用于设置 ICallback 对象
            void SetCallback(ICallback^ callback);
    
            // 由 C++/CX 调用,用于通过 ICallback 向 C# 发送数据
            property static ICallback^ GlobalCallback;
        };
    }

    DemoCx.cpp

    /*
     * 演示 C#, C++/CX, C/C++ 间的通信
     *
     * 本例是 C++/CX 部分
     *
     * 为了支持 Windows Runtime Component 这种方式,所以引入 Microsoft created the Visual C++ component extensions (C++/CX),可以将其看作是连接“调用者”和“C/C++”之间的桥梁,元数据是 windows metadata (.winmd) files
     * 为了让“调用者”调用 Windows Runtime Component,所以 C++/CX 会有自己的一些数据类型,比如字符串是 Platform::String^ 类型的,这样才能让“调用者”调用
     * 关于 C++/CX 的相关知识请参见:https://msdn.microsoft.com/en-us/library/hh755822.aspx
     */
    
    #include "pch.h" 
    #include "DemoCx.h" 
    #include "CppCx.h" 
    #include "cppHelper.h"
    
    using namespace NativeDll;
    
    String^ DemoCx::HelloCx(String^ name)
    {
        // 如果 C# 端设置了 ICallback 对象,则可以在 C++/Cx 端向 C# 端发送数据
        if (GlobalCallback != nullptr)
            GlobalCallback->Cx2Cs("c++/cx to cs");
    
        return "hello: " + name;
    }
    
    // 由 C# 调用,用于设置 ICallback 对象
    void DemoCx::SetCallback(ICallback^ callback)
    {
        GlobalCallback = callback;
    }
    
    
    String^ DemoCx::HelloCpp(String^ name)
    {
        // C++/CX 与 C/C++ 通信时,如果要传递字符串,则要对字符串做转换
        string cppName = ws2s_3(std::wstring(name->Data()));
    
        // C++/CX 调用 C/C++
        CppCx cppCx;
        string cppResult = cppCx.Hello(cppName);
        String^ cxResult = ref new Platform::String(s2ws_3(cppResult).c_str());
    
        return cxResult;
    }


    3、托管代码层
    Cx.xaml

    <Page
        x:Class="NativeDemo.Demo.Cx"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:NativeDemo.Demo"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="Transparent">
    
            <StackPanel Margin="120 0 0 0">
    
                <TextBlock Name="lblMsg" TextAlignment="Left" FontSize="24.667" TextWrapping="Wrap" />
    
            </StackPanel>
        </Grid>
    </Page>

    Cx.xaml.cs

    /*
     * 演示 C#, C++/CX, C/C++ 间的通信
     * 
     * 本例是 C# 部分
     * 
     * 
     * C# 与 C++/CX 间通信;C++/CX 与 C/C++ 间通信;C# 通过 C++/CX 与 C/C++ 间通信
     */
    
    using System;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace NativeDemo.Demo
    {
        public sealed partial class Cx : Page
        {
            public Cx()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                NativeDll.DemoCx demoCx = new NativeDll.DemoCx();
    
                MyCallback myCallback = new MyCallback();
                myCallback.MessageReceived += myCallback_MessageReceived;
                demoCx.SetCallback(myCallback);
    
                // C# 调用 C++/CX
                lblMsg.Text += demoCx.HelloCx("cs to c++/cx");
                lblMsg.Text += Environment.NewLine;
    
                // C# 通过 C++/CX 调用 C/C++
                lblMsg.Text += demoCx.HelloCpp("cs to c++/cx to c/c++");
                lblMsg.Text += Environment.NewLine;
            }
    
            async void myCallback_MessageReceived(object sender, MessageEventArgs e)
            {
                MyCallback myCallback = (MyCallback)sender;
    
                await lblMsg.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    lblMsg.Text += e.Message;
                    lblMsg.Text += Environment.NewLine;
                });
            }
        }
    
        // 实现 C++/CX 中的 ICallback 接口
        public class MyCallback : NativeDll.ICallback
        {
            // 收到 C++/CX 直接发送过来的数据,或者 C/C++ 通过 C++/CX 发送过来的数据
            public void Cx2Cs(string message)
            {
                OnMessageReceived(new MessageEventArgs { Message = message });
            }
    
            public event EventHandler<MessageEventArgs> MessageReceived;
            protected virtual void OnMessageReceived(MessageEventArgs e)
            {
                EventHandler<MessageEventArgs> handler = MessageReceived;
                if (handler != null)
                    handler(this, e);
            }
        }
    
    
        public class MessageEventArgs : EventArgs
        {
            public string Message { get; set; }
        }
    
    }



    二、演示 android app native 开发
    1、native 层(C 语言)
    cHello.h

    #ifndef _MYHEAD_CHELLO_
    #define _MYHEAD_CHELLO_
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    char *hello(const char *name);
    
    #ifdef __cplusplus
    }
    #endif
    #endif

    cHello.c

    #include "cHello.h"
    #include <stdlib.h>
    
    char *str_concat2(const char *, const char *);
    
    char *hello(const char *name)
    {
        return str_concat2("hello: ", name);
    }
    
    char *str_concat2(const char *str1, const char *str2)
    {
        char *result;
        result = (char *)malloc(strlen(str1) + strlen(str2) + 1);
        if (!result)
        {
            exit(EXIT_FAILURE);
        }
    
        strncpy(result, str1, strlen(str1) + 1);
        strncat(result, str2, strlen(str1) + strlen(str2) + 1);
        return result;
    }


    2、native 层(C++)
    CppHello.h

    #ifndef _MYHEAD_CPPHELLO_
    #define _MYHEAD_CPPHELLO_
    
    #include <string>
    
    using namespace std;
    
    namespace MyNs
    {
        class CppHello
        {
        public:
            string Hello(string name);
        };
    }
    
    #endif

    CppHello.cpp

    #include "CppHello.h"
    
    using namespace MyNs;
    
    string CppHello::Hello(string name)
    {
        return "hello: " + name;
    }


    3、jni 层
    jniDemo.h

    #include <jni.h>
    
    #ifndef _Included_com_cnblogs_webabcd_jniDemo
    #define _Included_com_cnblogs_webabcd_jniDemo
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    // 注意函数名的命名规则
    JNIEXPORT jstring JNICALL Java_com_example_androidnative_MainActivity_helloJniCpp(JNIEnv *env, jobject obj, jstring name);
    
    JNIEXPORT jstring JNICALL Java_com_example_androidnative_MainActivity_helloJniC(JNIEnv *env, jobject obj, jstring name);
    
    #ifdef __cplusplus
    }
    #endif
    #endif

    jniDemo.cpp

    /*
     * jni(Java Native Interface) - 详细文档参见 http://docs.oracle.com/javase/7/docs/technotes/guides/jni/
     * ndk(Native Development Kit) - 下载 ndk 后,其目录内有详细的文档
     * cygwin - 在 windows 平台上运行的类 UNIX 模拟环境,可以调用 ndk 编译 so
     *
     *
     * 为了使 jni 能支持 c++ 需要这么做:
     * 1、将本文件的后缀名从 .c 修改为 .cpp(c++ 文件的扩展名可以通过 Android.mk 的 LOCAL_CPP_EXTENSION 指定)
     * 2、按本例的方式配置 Application.mk 文件(如果只想支持 c 语言的话,则可以不要此文件)
     */
    
    #include "jniDemo.h"
    #include "CppHello.h"
    #include "cHello.h"
    
    void jni2java(JNIEnv *);
    
    // 对应 MainActivity 类中的 public native String helloJniCpp(String name); 注意函数的命名规则
    JNIEXPORT jstring JNICALL Java_com_example_androidnative_MainActivity_helloJniCpp(JNIEnv *env, jobject obj, jstring name)
    {
        jni2java(env);
    
        MyNs::CppHello cppHello;
        const char *charName = env->GetStringUTFChars(name, 0); // jstring to char
        std::string stringName(charName); // jstring to string
        std::string stringResult = cppHello.Hello(stringName);
        const char *charResult = stringResult.data(); // string to char
        jstring jstringResult = env->NewStringUTF(charResult); // char to jstring
        return jstringResult;
    
        /*
         * 调用 jni 函数时注意(对于 C 和 CPP 来说,JNIEnv 的含义不同,具体请查看文档):
         * 1、C 的用法示例:jstring jstringResult = (*env)->NewStringUTF(env, charResult); // char to jstring
         * 2、CPP 的用法示例:jstring jstringResult = env->NewStringUTF(charResult); // char to jstring
         */
    }
    
    // 对应 MainActivity 类中的 public native String helloJniC(String name); 注意函数的命名规则
    JNIEXPORT jstring JNICALL Java_com_example_androidnative_MainActivity_helloJniC(JNIEnv *env, jobject obj, jstring name)
    {
        jni2java(env);
    
        const char *charName = env->GetStringUTFChars(name, 0); // jstring to char
        char *charResult = hello(charName);
        jstring jstringResult = env->NewStringUTF(charResult); // char to jstring
        free(charResult);
        return jstringResult;
    }
    
    // 调用 MainActivity 类中的 public static void helloJava(String message); 函数
    void jni2java(JNIEnv *env)
    {
        const char *className = "com/example/androidnative/MainActivity"; // 注意类名规则
        jclass cla = env->FindClass(className);
        // 第三个参数中:(Ljava/lang/String;)代表 java 中的被调用的函数的参数是 String 类型;V 代表 java 中的被调用的函数的返回值是 void 类型
        jmethodID method = env->GetStaticMethodID(cla, "helloJava", "(Ljava/lang/String;)V");
        jstring result = env->NewStringUTF("jni to java");
        env->CallStaticVoidMethod(cla, method, result);
    }

    编译相关
    Application.mk

    APP_STL := stlport_static #以静态链接的方式使用stlport版本的STL
    APP_CPPFLAGS := -fexceptions -frtti #允许异常功能,及运行时类型识别  
    APP_CPPFLAGS +=-std=c++11 #允许使用c++11的函数等功能  
    APP_CPPFLAGS +=-fpermissive  #此项有效时表示宽松的编译形式,比如没有用到的代码中有错误也可以通过编  

    Android.mk

    LOCAL_PATH := $(call my-dir)
    
    #模块1
    include $(CLEAR_VARS) #清除 LOCAL_MODULE, LOCAL_SRC_FILES 之类的变量
    LOCAL_CPP_EXTENSION := .cpp # C++ 文件的扩展名
    LOCAL_MODULE := jniDemo # 模块名。如果模块名为“abc”,则此模块将会生成“libabc.so”文件。
    LOCAL_SRC_FILES := jniDemo.cpp CppHello.cpp cHello.c # 需要编译的源文件
    include $(BUILD_SHARED_LIBRARY) # 编译当前模块
    
    #模块2


    4、托管代码层
    MainActivity.java

    /*
     * 演示 java 如何通过 jni 与 C/C++ 互相通信
     */
    
    package com.example.androidnative;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
    
        private static TextView txtMsg;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            txtMsg = (TextView) this.findViewById(R.id.txtMsg);
            
            // 加载 so
            System.loadLibrary("jniDemo");
            
            // java 调用 jni, c
            String resultC = helloJniC("java to jni to c");
            txtMsg.append(resultC);
            txtMsg.append("
    ");
            
            // java 调用 jni, c++
            String resultCpp = helloJniCpp("java to jni to c++");
            txtMsg.append(resultCpp);
            txtMsg.append("
    ");
        }
    
        // native function(对应的 jni 函数参见 jniDemo.cpp)
        public native String helloJniC(String name);
        public native String helloJniCpp(String name);
        
        // jni 调用 java
        public static void helloJava(String message)
        {
            txtMsg.append(message);
            txtMsg.append("
    ");
        }
    }



    三、演示 ios app native 开发(无论是 oc 还是 swift 都是 native 开发,本例演示 oc, c, c++ 混编)
    ViewController.h

    //
    //  ViewController.h
    //  IosNative
    //
    //  Created by wanglei on 4/24/15.
    //  Copyright (c) 2015 webabcd. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface ViewController : UIViewController
    
    
    @end

    ViewController.mm

    /*
     * 演示 objective-c 如何与 C/C++ 互相通信
     * 
     * objective-c 是面向对象的 c 语言,本身就是 Native 的,完全兼容 c 语言,可以与 C/C++ 混编
     *
     * 注:为了支持 C++ 需要把本文件的后缀名由 .m 修改为 .mm
     */
    
    #import "ViewController.h"
    
    #include <string>
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    char *hello(const char *);
    class CppHello;
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        [self helloC:@"oc to c"];
        [self helloCpp:@"oc to c++"];
    }
    
    // oc 调用 c
    - (void)helloC:(NSString *)name
    {
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 50, 200, 20)];
        [self.view addSubview:label];
        
        const char *charName = [name UTF8String]; // nsstring to char
        char *charResult = hello(charName);
        NSString *nsstringResult = [[NSString alloc] initWithCString:charResult encoding:NSUTF8StringEncoding]; // char to nsstring
        free(charResult);
        
        label.text = nsstringResult;
    }
    
    // oc 调用 c++
    - (void)helloCpp:(NSString *)name
    {
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 200, 20)];
        [self.view addSubview:label];
        
        string stringName = [name UTF8String]; // nsstring to string
        MyNs::CppHello cppHello;
        string stringResult = cppHello.Hello(stringName);
        NSString *nsstringResult = [[NSString alloc] initWithCString:stringResult.c_str() encoding:NSUTF8StringEncoding]; // string to nsstring
        
        label.text = nsstringResult;
    }
    
    
    char *hello(const char *name)
    {
        // c 调用 oc(别忘了 #import <Foundation/Foundation.h>,本例中不用是因为 UIViewController 已经导入这个头文件了)
        NSLog(@"c to oc");
        
        char *s = "hello: ";
        
        char *result;
        result = (char *)malloc(strlen(s) + strlen(name) + 1);
        if (!result)
            exit(EXIT_FAILURE);
        
        strncpy(result, s, strlen(s) + 1);
        strncat(result, name, strlen(s) + strlen(name) + 1);
        
        return result;
    }
    
    using namespace std;
    namespace MyNs
    {
        class CppHello
        {
        public:
            string Hello(string name);
        };
    }
    string MyNs::CppHello::Hello(string name)
    {
        // c++ 调用 oc(别忘了 #import <Foundation/Foundation.h>,本例中不用是因为 UIViewController 已经导入这个头文件了)
        NSLog(@"c++ to oc");
        
        return "hello: " + name;
    }
    
    @end



    OK
    [源码下载]

  • 相关阅读:
    C++中智能指针的设计和使用
    [转]C++ 智能指针详解
    C++ const 常量和常指针
    深入理解C++中的mutable关键字
    C++ 静态常量
    BZOJ 1875: [SDOI2009]HH去散步
    BZOJ 1024: [SCOI2009]生日快乐
    BZOJ 1059: [ZJOI2007]矩阵游戏
    bzoj 1833: [ZJOI2010]count 数字计数
    LUOGU P2587 [ZJOI2008]泡泡堂
  • 原文地址:https://www.cnblogs.com/webabcd/p/4670572.html
Copyright © 2011-2022 走看看